]> git.lyx.org Git - lyx.git/blob - src/text2.C
Move using directives around, as pointed out by Angus
[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 //#ifdef HAVE_SSTREAM
1836                         std::ostringstream s;
1837 //#else
1838 //                      ostrstream s;
1839 //#endif
1840                         if (!par->appendix) {
1841                                 switch (2 * LABEL_COUNTER_CHAPTER -
1842                                         textclass.maxcounter() + i) {
1843                                 case LABEL_COUNTER_CHAPTER:
1844                                         s << par->getCounter(i);
1845                                         break;
1846                                 case LABEL_COUNTER_SECTION:
1847                                         s << par->getCounter(i - 1) << '.'
1848                                            << par->getCounter(i);
1849                                         break;
1850                                 case LABEL_COUNTER_SUBSECTION:
1851                                         s << par->getCounter(i - 2) << '.'
1852                                           << par->getCounter(i - 1) << '.'
1853                                           << par->getCounter(i);
1854                                         break;
1855                                 case LABEL_COUNTER_SUBSUBSECTION:
1856                                         s << par->getCounter(i - 3) << '.'
1857                                           << par->getCounter(i - 2) << '.'
1858                                           << par->getCounter(i - 1) << '.'
1859                                           << par->getCounter(i);
1860                                         
1861                                         break;
1862                                 case LABEL_COUNTER_PARAGRAPH:
1863                                         s << par->getCounter(i - 4) << '.'
1864                                           << par->getCounter(i - 3) << '.'
1865                                           << par->getCounter(i - 2) << '.'
1866                                           << par->getCounter(i - 1) << '.'
1867                                           << par->getCounter(i);
1868                                         break;
1869                                 case LABEL_COUNTER_SUBPARAGRAPH:
1870                                         s << par->getCounter(i - 5) << '.'
1871                                           << par->getCounter(i - 4) << '.'
1872                                           << par->getCounter(i - 3) << '.'
1873                                           << par->getCounter(i - 2) << '.'
1874                                           << par->getCounter(i - 1) << '.'
1875                                           << par->getCounter(i);
1876
1877                                         break;
1878                                 default:
1879                                         // Can this ever be reached? And in the
1880                                         // case it is, how can this be correct?
1881                                         // (Lgb)
1882                                         s << par->getCounter(i) << '.';
1883                                         break;
1884                                 }
1885                         } else { // appendix
1886                                 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1887                                 case LABEL_COUNTER_CHAPTER:
1888                                         if (par->isRightToLeftPar(buf->params))
1889                                                 s << hebrewCounter(par->getCounter(i));
1890                                         else
1891                                                 s << alphaCounter(par->getCounter(i));
1892                                         break;
1893                                 case LABEL_COUNTER_SECTION:
1894                                         if (par->isRightToLeftPar(buf->params))
1895                                                 s << hebrewCounter(par->getCounter(i - 1));
1896                                         else
1897                                                 s << alphaCounter(par->getCounter(i - 1));
1898
1899                                         s << '.'
1900                                           << par->getCounter(i);
1901
1902                                         break;
1903                                 case LABEL_COUNTER_SUBSECTION:
1904                                         if (par->isRightToLeftPar(buf->params))
1905                                                 s << hebrewCounter(par->getCounter(i - 2));
1906                                         else
1907                                                 s << alphaCounter(par->getCounter(i - 2));
1908
1909                                         s << '.'
1910                                           << par->getCounter(i-1) << '.'
1911                                           << par->getCounter(i);
1912
1913                                         break;
1914                                 case LABEL_COUNTER_SUBSUBSECTION:
1915                                         if (par->isRightToLeftPar(buf->params))
1916                                                 s << hebrewCounter(par->getCounter(i-3));
1917                                         else
1918                                                 s << alphaCounter(par->getCounter(i-3));
1919
1920                                         s << '.'
1921                                           << par->getCounter(i-2) << '.'
1922                                           << par->getCounter(i-1) << '.'
1923                                           << par->getCounter(i);
1924
1925                                         break;
1926                                 case LABEL_COUNTER_PARAGRAPH:
1927                                         if (par->isRightToLeftPar(buf->params))
1928                                                 s << hebrewCounter(par->getCounter(i-4));
1929                                         else
1930                                                 s << alphaCounter(par->getCounter(i-4));
1931
1932                                         s << '.'
1933                                           << par->getCounter(i-3) << '.'
1934                                           << par->getCounter(i-2) << '.'
1935                                           << par->getCounter(i-1) << '.'
1936                                           << par->getCounter(i);
1937
1938                                         break;
1939                                 case LABEL_COUNTER_SUBPARAGRAPH:
1940                                         if (par->isRightToLeftPar(buf->params))
1941                                                 s << hebrewCounter(par->getCounter(i-5));
1942                                         else
1943                                                 s << alphaCounter(par->getCounter(i-5));
1944
1945                                         s << '.'
1946                                           << par->getCounter(i-4) << '.'
1947                                           << par->getCounter(i-3) << '.'
1948                                           << par->getCounter(i-2) << '.'
1949                                           << par->getCounter(i-1) << '.'
1950                                           << par->getCounter(i);
1951
1952                                         break;
1953                                 default:
1954                                         // Can this ever be reached? And in the
1955                                         // case it is, how can this be correct?
1956                                         // (Lgb)
1957                                         s << par->getCounter(i) << '.';
1958                                         
1959                                         break;
1960                                 }
1961                         }
1962 //#ifdef HAVE_SSTREAM
1963                         par->labelstring += s.str().c_str();
1964                         // We really want to remove the c_str as soon as
1965                         // possible...
1966 //#else
1967 //                      s << '\0';
1968 //                      char * tmps = s.str();
1969 //                      par->labelstring += tmps;
1970 //                      delete [] tmps;
1971 //#endif
1972                         
1973                         for (i++; i < 10; ++i) {
1974                                 // reset the following counters
1975                                 par->setCounter(i, 0);
1976                         }
1977                 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1978                         for (i++; i < 10; ++i) {
1979                                 // reset the following counters
1980                                 par->setCounter(i, 0);
1981                         }
1982                 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1983                         par->incCounter(i + par->enumdepth);
1984                         int number = par->getCounter(i + par->enumdepth);
1985
1986 //#ifdef HAVE_SSTREAM
1987                         std::ostringstream s;
1988 //#else
1989 //                      ostrstream s;
1990 //#endif
1991                         switch (par->enumdepth) {
1992                         case 1:
1993                                 if (par->isRightToLeftPar(buf->params))
1994                                         s << '('
1995                                           << hebrewCounter(number)
1996                                           << ')';
1997                                 else
1998                                         s << '('
1999                                           << loweralphaCounter(number)
2000                                           << ')';
2001                                 break;
2002                         case 2:
2003                                 if (par->isRightToLeftPar(buf->params))
2004                                         s << '.' << romanCounter(number);
2005                                 else
2006                                         s << romanCounter(number) << '.';
2007                                 break;
2008                         case 3:
2009                                 if (par->isRightToLeftPar(buf->params))
2010                                         s << '.'
2011                                           << alphaCounter(number);
2012                                 else
2013                                         s << alphaCounter(number)
2014                                           << '.';
2015                                 break;
2016                         default:
2017                                 if (par->isRightToLeftPar(buf->params))
2018                                         s << '.' << number;
2019                                 else
2020                                         s << number << '.';
2021                                 break;
2022                         }
2023 //#ifdef HAVE_SSTREAM
2024                         par->labelstring = s.str().c_str();
2025                         // we really want to get rid of that c_str()
2026 //#else
2027 //                      s << '\0';
2028 //                      char * tmps = s.str();
2029 //                      par->labelstring = tmps;
2030 //                      delete [] tmps;
2031 //#endif
2032
2033                         for (i += par->enumdepth + 1; i < 10; ++i)
2034                                 par->setCounter(i, 0);  /* reset the following counters  */
2035          
2036                 } 
2037         } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2038                 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2039                 par->incCounter(i);
2040                 int number = par->getCounter(i);
2041                 if (!par->bibkey) {
2042                         InsetCommandParams p( "bibitem" );
2043                         par->bibkey = new InsetBibKey(p);
2044                 }
2045                 par->bibkey->setCounter(number);
2046                 par->labelstring = layout.labelstring();
2047                 
2048                 // In biblio should't be following counters but...
2049         } else {
2050                 string s = layout.labelstring();
2051                 
2052                 // the caption hack:
2053                 if (layout.labeltype == LABEL_SENSITIVE) {
2054                         bool isOK (par->InInset() && par->InInset()->owner() &&
2055                                    (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2056 #ifndef NEW_INSETS
2057                         if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2058                             && (par->footnotekind == LyXParagraph::FIG
2059                                 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2060                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2061                                         ? ":øåéà" : "Figure:";
2062                         } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2063                                  && (par->footnotekind == LyXParagraph::TAB
2064                                      || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2065                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2066                                         ? ":äìáè" : "Table:";
2067                         } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2068                                    && par->footnotekind == LyXParagraph::ALGORITHM) {
2069                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2070                                         ? ":íúéøåâìà" : "Algorithm:";
2071                         } else
2072 #endif
2073                         if (isOK) {
2074                                 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2075                                 Floating const & fl
2076                                         = floatList.getType(tmp->type());
2077                                 // We should get the correct number here too.
2078                                 s = fl.name + " #:";
2079                         } else {
2080                                 /* par->SetLayout(0); 
2081                                    s = layout->labelstring;  */
2082                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2083                                         ? " :úåòîùî Ã¸Ã±Ã§" : "Senseless: ";
2084                         }
2085                 }
2086                 par->labelstring = s;
2087                 
2088                 /* reset the enumeration counter. They are always resetted
2089                  * when there is any other layout between */ 
2090                 for (int i = 6 + par->enumdepth; i < 10; ++i)
2091                         par->setCounter(i, 0);
2092         }
2093 }
2094
2095
2096 /* Updates all counters BEHIND the row. Changed paragraphs
2097 * with a dynamic left margin will be rebroken. */ 
2098 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2099 {
2100         LyXParagraph * par;
2101         if (!row) {
2102                 row = firstrow;
2103                 par = row->par();
2104         } else {
2105                 if (row->par()->next
2106 #ifndef NEW_INSETS
2107                     && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2108 #endif
2109                         ) {
2110 #ifndef NEW_INSETS
2111                         par = row->par()->LastPhysicalPar()->Next();
2112 #else
2113                         par = row->par()->Next();
2114 #endif
2115                 } else {
2116                         par = row->par()->next;
2117                 }
2118         }
2119
2120         while (par) {
2121                 while (row->par() != par)
2122                         row = row->next();
2123                 
2124                 SetCounter(bview->buffer(), par);
2125                 
2126                 /* now  check for the headline layouts. remember that they
2127                  * have a dynamic left margin */ 
2128                 if (
2129 #ifndef NEW_INSETS
2130                         !par->IsDummy() &&
2131 #endif
2132                     ( textclasslist.Style(bview->buffer()->params.textclass,
2133                                              par->layout).margintype == MARGIN_DYNAMIC
2134                          || textclasslist.Style(bview->buffer()->params.textclass,
2135                                                 par->layout).labeltype == LABEL_SENSITIVE)
2136                         ) {
2137          
2138                         /* Rebreak the paragraph */ 
2139                         RemoveParagraph(row);
2140                         AppendParagraph(bview, row);
2141
2142 #ifndef NEW_INSETS
2143                         /* think about the damned open footnotes! */ 
2144                         while (par->Next() &&
2145                                (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2146                                 || par->Next()->IsDummy())){
2147                                 par = par->Next();
2148                                 if (par->IsDummy()) {
2149                                         while (row->par() != par)
2150                                                 row = row->next();
2151                                         RemoveParagraph(row);
2152                                         AppendParagraph(bview, row);
2153                                 }
2154                         }
2155 #endif
2156                 }
2157 #ifndef NEW_INSETS
2158                 par = par->LastPhysicalPar()->Next();
2159 #else
2160                 par = par->Next();
2161 #endif
2162      
2163         }
2164 }
2165
2166
2167 /* insets an inset. */ 
2168 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2169 {
2170         if (!cursor.par()->InsertInsetAllowed(inset))
2171                 return;
2172         SetUndo(bview->buffer(), Undo::INSERT,
2173 #ifndef NEW_INSETS
2174                 cursor.par()->ParFromPos(cursor.pos())->previous, 
2175                 cursor.par()->ParFromPos(cursor.pos())->next
2176 #else
2177                 cursor.par()->previous, 
2178                 cursor.par()->next
2179 #endif
2180                 );
2181         cursor.par()->InsertInset(cursor.pos(), inset);
2182         InsertChar(bview, LyXParagraph::META_INSET);  /* just to rebreak and refresh correctly.
2183                                       * The character will not be inserted a
2184                                       * second time */
2185 }
2186
2187
2188 void LyXText::copyEnvironmentType()
2189 {
2190         copylayouttype = cursor.par()->GetLayout();
2191 }
2192
2193
2194 void LyXText::pasteEnvironmentType(BufferView * bview)
2195 {
2196         SetLayout(bview, copylayouttype);
2197 }
2198
2199
2200 void LyXText::CutSelection(BufferView * bview, bool doclear)
2201 {
2202         // Stuff what we got on the clipboard. Even if there is no selection.
2203
2204         // There is a problem with having the stuffing here in that the
2205         // larger the selection the slower LyX will get. This can be
2206         // solved by running the line below only when the selection has
2207         // finished. The solution used currently just works, to make it
2208         // faster we need to be more clever and probably also have more
2209         // calls to stuffClipboard. (Lgb)
2210         bview->stuffClipboard(selectionAsString(bview->buffer()));
2211
2212         // This doesn't make sense, if there is no selection
2213         if (!selection)
2214                 return;
2215    
2216         // OK, we have a selection. This is always between sel_start_cursor
2217         // and sel_end cursor
2218 #ifndef NEW_INSETS
2219         // Check whether there are half footnotes in the selection
2220         if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2221             || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2222         LyXParagraph * tmppar = sel_start_cursor.par();
2223                 while (tmppar != sel_end_cursor.par()){
2224                         if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2225                                 WriteAlert(_("Impossible operation"),
2226                                            _("Don't know what to do with half floats."),
2227                                            _("sorry."));
2228                                 return;
2229                         }
2230                         tmppar = tmppar->Next();
2231                 }
2232         }
2233 #endif
2234 #ifndef NEW_TABULAR
2235         /* table stuff -- begin */
2236         if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2237                 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2238                         WriteAlert(_("Impossible operation"),
2239                                    _("Don't know what to do with half tables."),
2240                                    _("sorry."));
2241                         return;
2242                 }
2243                 sel_start_cursor.par()->table->Reinit();
2244         }
2245         /* table stuff -- end */
2246 #endif
2247         // make sure that the depth behind the selection are restored, too
2248 #ifndef NEW_INSETS
2249         LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2250 #else
2251         LyXParagraph * endpar = sel_end_cursor.par()->Next();
2252 #endif
2253         LyXParagraph * undoendpar = endpar;
2254     
2255         if (endpar && endpar->GetDepth()) {
2256                 while (endpar && endpar->GetDepth()) {
2257 #ifndef NEW_INSETS
2258                         endpar = endpar->LastPhysicalPar()->Next();
2259 #else
2260                         endpar = endpar->Next();
2261 #endif
2262                         undoendpar = endpar;
2263                 }
2264         } else if (endpar) {
2265                 endpar = endpar->Next(); // because of parindents etc.
2266         }
2267     
2268         SetUndo(bview->buffer(), Undo::DELETE,
2269 #ifndef NEW_INSETS
2270                 sel_start_cursor
2271                 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2272 #else
2273                 sel_start_cursor.par()->previous,
2274 #endif
2275                 undoendpar);
2276     
2277         CutAndPaste cap;
2278
2279         // there are two cases: cut only within one paragraph or
2280         // more than one paragraph
2281 #ifndef NEW_INSETS
2282         if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos()) 
2283             == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2284 #else
2285         if (sel_start_cursor.par() == sel_end_cursor.par())
2286 #endif
2287                 {
2288                 // only within one paragraph
2289                 endpar = sel_start_cursor.par();
2290                 int pos = sel_end_cursor.pos();
2291                 cap.cutSelection(sel_start_cursor.par(), &endpar,
2292                                  sel_start_cursor.pos(), pos,
2293                                  bview->buffer()->params.textclass, doclear);
2294                 sel_end_cursor.pos(pos);
2295         } else {
2296                 endpar = sel_end_cursor.par();
2297
2298                 int pos = sel_end_cursor.pos();
2299                 cap.cutSelection(sel_start_cursor.par(), &endpar,
2300                                  sel_start_cursor.pos(), pos,
2301                                  bview->buffer()->params.textclass, doclear);
2302                 cursor.par(endpar);
2303                 sel_end_cursor.par(endpar);
2304                 sel_end_cursor.pos(pos);
2305                 cursor.pos(sel_end_cursor.pos());
2306         }
2307         endpar = endpar->Next();
2308
2309         // sometimes necessary
2310         if (doclear)
2311                 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2312
2313         RedoParagraphs(bview, sel_start_cursor, endpar);
2314    
2315         ClearSelection();
2316         cursor = sel_start_cursor;
2317         SetCursor(bview, cursor.par(), cursor.pos());
2318         sel_cursor = cursor;
2319         UpdateCounters(bview, cursor.row());
2320 }
2321
2322
2323 void LyXText::CopySelection(BufferView * bview)
2324 {
2325         // Stuff what we got on the clipboard. Even if there is no selection.
2326
2327         // There is a problem with having the stuffing here in that the
2328         // larger the selection the slower LyX will get. This can be
2329         // solved by running the line below only when the selection has
2330         // finished. The solution used currently just works, to make it
2331         // faster we need to be more clever and probably also have more
2332         // calls to stuffClipboard. (Lgb)
2333         bview->stuffClipboard(selectionAsString(bview->buffer()));
2334
2335         // this doesnt make sense, if there is no selection
2336         if (!selection)
2337                 return;
2338
2339         // ok we have a selection. This is always between sel_start_cursor
2340         // and sel_end cursor
2341
2342 #ifndef NEW_INSETS
2343         /* check wether there are half footnotes in the selection */
2344         if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2345             || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2346                 LyXParagraph * tmppar = sel_start_cursor.par();
2347                 while (tmppar != sel_end_cursor.par()) {
2348                         if (tmppar->footnoteflag !=
2349                             sel_end_cursor.par()->footnoteflag) {
2350                                 WriteAlert(_("Impossible operation"),
2351                                            _("Don't know what to do"
2352                                              " with half floats."),
2353                                            _("sorry."));
2354                                 return;
2355                         }
2356                         tmppar = tmppar->Next();
2357                 }
2358         }
2359 #endif
2360 #ifndef NEW_TABULAR
2361         /* table stuff -- begin */
2362         if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2363                 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2364                         WriteAlert(_("Impossible operation"),
2365                                    _("Don't know what to do with half tables."),
2366                                    _("sorry."));
2367                         return;
2368                 }
2369         }
2370         /* table stuff -- end */
2371 #endif
2372    
2373         // copy behind a space if there is one
2374         while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2375                && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2376                && (sel_start_cursor.par() != sel_end_cursor.par()
2377                    || sel_start_cursor.pos() < sel_end_cursor.pos()))
2378                 sel_start_cursor.pos(sel_start_cursor.pos() + 1); 
2379
2380         CutAndPaste cap;
2381
2382         cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2383                           sel_start_cursor.pos(), sel_end_cursor.pos(),
2384                           bview->buffer()->params.textclass);
2385 }
2386
2387
2388 void LyXText::PasteSelection(BufferView * bview)
2389 {
2390         CutAndPaste cap;
2391
2392         // this does not make sense, if there is nothing to paste
2393         if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2394                 return;
2395
2396         SetUndo(bview->buffer(), Undo::INSERT,
2397 #ifndef NEW_INSETS
2398                 cursor.par()->ParFromPos(cursor.pos())->previous, 
2399                 cursor.par()->ParFromPos(cursor.pos())->next
2400 #else
2401                 cursor.par()->previous, 
2402                 cursor.par()->next
2403 #endif
2404                 ); 
2405
2406         LyXParagraph * endpar;
2407         LyXParagraph * actpar = cursor.par();
2408
2409         int pos = cursor.pos();
2410         cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2411     
2412         RedoParagraphs(bview, cursor, endpar);
2413         
2414         SetCursor(bview, cursor.par(), cursor.pos());
2415         ClearSelection();
2416    
2417         sel_cursor = cursor;
2418         SetCursor(bview, actpar, pos);
2419         SetSelection();
2420         UpdateCounters(bview, cursor.row());
2421 }
2422
2423
2424 // returns a pointer to the very first LyXParagraph
2425 LyXParagraph * LyXText::FirstParagraph() const
2426 {
2427         return OwnerParagraph();
2428 }
2429
2430
2431 // returns true if the specified string is at the specified position
2432 bool LyXText::IsStringInText(LyXParagraph * par,
2433                              LyXParagraph::size_type pos,
2434                              string const & str) const
2435 {
2436         if (par) {
2437                 unsigned int i = 0;
2438                 while (pos + i < par->Last() && i < str.length()&& 
2439                        str[i] == par->GetChar(pos + i)) {
2440                         ++i;
2441                 }
2442                 if (str.length() == i)
2443                         return true;
2444         }
2445         return false;
2446 }
2447
2448
2449 // sets the selection over the number of characters of string, no check!!
2450 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2451 {
2452         sel_cursor = cursor;
2453         for (int i = 0; str[i]; ++i)
2454                 CursorRight(bview);
2455         SetSelection();
2456 }
2457
2458
2459 // simple replacing. The font of the first selected character is used
2460 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2461                                          string const & str)
2462 {
2463         SetCursorParUndo(bview->buffer());
2464         FreezeUndo();
2465
2466         if (!selection) { // create a dummy selection
2467                 sel_end_cursor = cursor;
2468                 sel_start_cursor = cursor;
2469         }
2470
2471         // Get font setting before we cut
2472         LyXParagraph::size_type pos = sel_end_cursor.pos();
2473         LyXFont const font = sel_start_cursor.par()
2474                 ->GetFontSettings(bview->buffer()->params,
2475                                   sel_start_cursor.pos());
2476
2477         // Insert the new string
2478         for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2479                 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2480                 ++pos;
2481         }
2482         
2483         // Cut the selection
2484         CutSelection(bview);
2485
2486         UnFreezeUndo();
2487 }
2488
2489
2490 // if the string can be found: return true and set the cursor to
2491 // the new position
2492 bool LyXText::SearchForward(BufferView * bview, string const & str) const
2493 {
2494         LyXParagraph * par = cursor.par();
2495         LyXParagraph::size_type pos = cursor.pos();
2496         while (par && !IsStringInText(par, pos, str)) {
2497                 if (pos < par->Last() - 1)
2498                         ++pos;
2499                 else {
2500                         pos = 0;
2501                         par = par->Next();
2502                 }
2503         }
2504         if (par) {
2505                 SetCursor(bview, par, pos);
2506                 return true;
2507         }
2508         else
2509                 return false;
2510 }
2511
2512
2513 bool LyXText::SearchBackward(BufferView * bview, string const & str) const
2514 {
2515         LyXParagraph * par = cursor.par();
2516         int pos = cursor.pos();
2517
2518         do {
2519                 if (pos > 0)
2520                         --pos;
2521                 else {
2522                         // We skip empty paragraphs (Asger)
2523                         do {
2524                                 par = par->Previous();
2525                                 if (par)
2526                                         pos = par->Last() - 1;
2527                         } while (par && pos < 0);
2528                 }
2529         } while (par && !IsStringInText(par, pos, str));
2530   
2531         if (par) {
2532                 SetCursor(bview, par, pos);
2533                 return true;
2534         } else
2535                 return false;
2536 }
2537
2538
2539 // needed to insert the selection
2540 void LyXText::InsertStringA(BufferView * bview, string const & str)
2541 {
2542         LyXParagraph * par = cursor.par();
2543         LyXParagraph::size_type pos = cursor.pos();
2544         LyXParagraph::size_type a = 0;
2545         LyXParagraph * endpar = cursor.par()->Next();
2546         
2547         SetCursorParUndo(bview->buffer());
2548         
2549         bool flag =
2550                 textclasslist.Style(bview->buffer()->params.textclass, 
2551                                     cursor.par()->GetLayout()).isEnvironment();
2552         // only to be sure, should not be neccessary
2553         ClearSelection();
2554         
2555         // insert the string, don't insert doublespace
2556         string::size_type i = 0;
2557         while (i < str.length()) {
2558                 if (str[i] != '\n') {
2559                         if (str[i] == ' ' 
2560                             && i + 1 < str.length() && str[i + 1] != ' '
2561                             && pos && par->GetChar(pos - 1)!= ' ') {
2562                                 par->InsertChar(pos, ' ', current_font);
2563                                 ++pos;
2564 #ifndef NEW_TABULAR
2565                         } else if (par->table) {
2566                                 if (str[i] == '\t') {
2567                                         while((pos < par->size()) &&
2568                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2569                                                 ++pos;
2570                                         if (pos < par->size())
2571                                                 ++pos;
2572                                         else // no more fields to fill skip the rest
2573                                                 break;
2574                                 } else if ((str[i] != 13) &&
2575                                            ((str[i] & 127) >= ' ')) {
2576                                         par->InsertChar(pos, str[i],
2577                                                         current_font);
2578                                         ++pos;
2579                                 }
2580 #endif
2581                         } else if (str[i] == ' ') {
2582                                 InsetSpecialChar * new_inset =
2583                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2584                                 if (par->InsertInsetAllowed(new_inset)) {
2585                                         par->InsertInset(pos, new_inset,
2586                                                          current_font);
2587                                 } else {
2588                                         delete new_inset;
2589                                 }
2590                                 ++pos;
2591                         } else if (str[i] == '\t') {
2592                                 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2593                                 InsetSpecialChar * new_inset =
2594                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2595                                 if (par->InsertInsetAllowed(new_inset)) {
2596                                         par->InsertInset(pos, new_inset,
2597                                                          current_font);
2598                                 } else {
2599                                         delete new_inset;
2600                                 }
2601                                 }
2602                                 pos = a;
2603                         } else if (str[i] != 13 && 
2604                                    // Ignore unprintables
2605                                    (str[i] & 127) >= ' ') {
2606                                 par->InsertChar(pos, str[i], current_font);
2607                                 ++pos;
2608                         }
2609                 } else {
2610 #ifndef NEW_TABULAR
2611                         if (par->table) {
2612                                 if ((i + 1) >= str.length()) {
2613                                         if (pos < par->size())
2614                                                 ++pos;
2615                                         break;
2616                                 }
2617                                 while((pos < par->size()) &&
2618                                       (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2619                                         ++pos;
2620                                 ++pos;
2621                                 int cell = NumberOfCell(par, pos);
2622                                 while((pos < par->size()) &&
2623                                       !(par->table->IsFirstCell(cell))) {
2624
2625                                         while((pos < par->size()) &&
2626                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2627                                                 ++pos;
2628                                         ++pos;
2629                                         cell = NumberOfCell(par, pos);
2630                                 }
2631                                 if (pos >= par->size())
2632                                         // no more fields to fill skip the rest
2633                                         break;
2634                         } else {
2635 #endif
2636                                 if (!par->size()) { // par is empty
2637                                         InsetSpecialChar * new_inset =
2638                                                 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2639                                         if (par->InsertInsetAllowed(new_inset)) {
2640                                                 par->InsertInset(pos,
2641                                                                  new_inset,
2642                                                                  current_font);
2643                                         } else {
2644                                                 delete new_inset;
2645                                         }
2646                                         ++pos;
2647                                 }
2648                                 par->BreakParagraph(bview->buffer()->params, pos, flag);
2649                                 par = par->Next();
2650                                 pos = 0;
2651 #ifndef NEW_TABULAR
2652                         }
2653 #endif
2654                 }
2655                 ++i;
2656         }
2657         
2658         RedoParagraphs(bview, cursor, endpar);
2659         SetCursor(bview, cursor.par(), cursor.pos());
2660         sel_cursor = cursor;
2661         SetCursor(bview, par, pos);
2662         SetSelection();
2663 }
2664
2665
2666 /* turns double-CR to single CR, others where converted into one blank and 13s 
2667  * that are ignored .Double spaces are also converted into one. Spaces at
2668  * the beginning of a paragraph are forbidden. tabs are converted into one
2669  * space. then InsertStringA is called */ 
2670 void LyXText::InsertStringB(BufferView * bview, string const & s)
2671 {
2672         string str(s);
2673 #ifndef NEW_TABULAR
2674         LyXParagraph * par = cursor.par();
2675 #endif
2676         string::size_type i = 1;
2677         while (i < str.length()) {
2678                 if (str[i] == '\t'
2679 #ifndef NEW_TABULAR
2680                     && !par->table
2681 #endif
2682                         )
2683                         str[i] = ' ';
2684                 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2685                         str[i] = 13;
2686                 if (str[i] == '\n' && i + 1 < str.length()
2687 #ifndef NEW_TABULAR
2688                     && !par->table
2689 #endif
2690                         ){
2691                         if (str[i + 1] != '\n') {
2692                                 if (str[i - 1] != ' ')
2693                                         str[i] = ' ';
2694                                 else
2695                                         str[i] = 13;
2696                         }
2697                         while (i + 1 < str.length() 
2698                                && (str[i + 1] == ' ' 
2699                                    || str[i + 1] == '\t'
2700                                    || str[i + 1] == '\n' 
2701                                    || str[i + 1] == 13)) {
2702                                 str[i + 1] = 13;
2703                                 ++i;
2704                         }
2705                 }
2706                 ++i;
2707         }
2708         InsertStringA(bview, str);
2709 }
2710
2711
2712 bool LyXText::GotoNextError(BufferView * bview) const
2713 {
2714         LyXCursor res = cursor;
2715         do {
2716                 if (res.pos() < res.par()->Last() - 1) {
2717                         res.pos(res.pos() + 1);
2718                 } else  {
2719                         res.par(res.par()->Next());
2720                         res.pos(0);
2721                 }
2722       
2723         } while (res.par() && 
2724                  !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2725                    && res.par()->GetInset(res.pos())->AutoDelete()));
2726    
2727         if (res.par()) {
2728                 SetCursor(bview, res.par(), res.pos());
2729                 return true;
2730         }
2731         return false;
2732 }
2733
2734
2735 bool LyXText::GotoNextNote(BufferView * bview) const
2736 {
2737         LyXCursor res = cursor;
2738         do {
2739                 if (res.pos() < res.par()->Last() - 1) {
2740                         res.pos(res.pos() + 1);
2741                 } else  {
2742                         res.par(res.par()->Next());
2743                         res.pos(0);
2744                 }
2745       
2746         } while (res.par() && 
2747                  !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2748                    && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2749    
2750         if (res.par()) {
2751                 SetCursor(bview, res.par(), res.pos());
2752                 return true;
2753         }
2754         return false;
2755 }
2756
2757
2758 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2759                              LyXParagraph::size_type pos)
2760 {
2761         LyXCursor tmpcursor;                    
2762
2763 #ifndef NEW_TABULAR
2764         /* table stuff -- begin*/
2765    
2766         if (par->table) {
2767                 CheckParagraphInTable(bview, par, pos);
2768         }
2769         else {
2770 #endif
2771                 /* table stuff -- end*/
2772      
2773                 long y = 0;
2774                 LyXParagraph::size_type z;
2775                 Row * row = GetRow(par, pos, y);
2776      
2777                 // is there a break one row above
2778                 if (row->previous() && row->previous()->par() == row->par()) {
2779                         z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2780                         if ( z >= row->pos()) {
2781                                 // set the dimensions of the row above
2782                                 y -= row->previous()->height();
2783                                 refresh_y = y;
2784                                 refresh_row = row->previous();
2785                                 status = LyXText::NEED_MORE_REFRESH;
2786        
2787                                 BreakAgain(bview, row->previous());
2788
2789                                 // set the cursor again. Otherwise
2790                                 // dangling pointers are possible
2791                                 SetCursor(bview, cursor.par(), cursor.pos());
2792                                 sel_cursor = cursor;
2793                                 return;
2794                         }
2795                 }
2796
2797                 int tmpheight = row->height();
2798                 LyXParagraph::size_type tmplast = RowLast(row);
2799                 refresh_y = y;
2800                 refresh_row = row;
2801
2802                 BreakAgain(bview, row);
2803                 if (row->height() == tmpheight && RowLast(row) == tmplast)
2804                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
2805                 else
2806                         status = LyXText::NEED_MORE_REFRESH; 
2807    
2808                 // check the special right address boxes
2809                 if (textclasslist.Style(bview->buffer()->params.textclass,
2810                                         par->GetLayout()).margintype
2811                     == MARGIN_RIGHT_ADDRESS_BOX) {
2812                         tmpcursor.par(par);
2813                         tmpcursor.row(row);
2814                         tmpcursor.y(y);
2815                         tmpcursor.x(0);
2816                         tmpcursor.x_fix(0);
2817                         tmpcursor.pos(pos);
2818                         RedoDrawingOfParagraph(bview, tmpcursor); 
2819                 }
2820 #ifndef NEW_TABULAR
2821         }
2822 #endif
2823
2824         // set the cursor again. Otherwise dangling pointers are possible
2825         // also set the selection
2826    
2827         if (selection) {
2828                 tmpcursor = cursor;
2829                 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2830                 sel_cursor = cursor; 
2831                 SetCursorIntern(bview, sel_start_cursor.par(),
2832                                 sel_start_cursor.pos());
2833                 sel_start_cursor = cursor; 
2834                 SetCursorIntern(bview, sel_end_cursor.par(),
2835                                 sel_end_cursor.pos());
2836                 sel_end_cursor = cursor; 
2837                 SetCursorIntern(bview, last_sel_cursor.par(),
2838                                 last_sel_cursor.pos());
2839                 last_sel_cursor = cursor; 
2840                 cursor = tmpcursor;
2841         }
2842         SetCursorIntern(bview, cursor.par(), cursor.pos());
2843 }
2844
2845
2846 // returns false if inset wasn't found
2847 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2848 {
2849         // first check the current paragraph
2850         int pos = cursor.par()->GetPositionOfInset(inset);
2851         if (pos != -1){
2852                 CheckParagraph(bview, cursor.par(), pos);
2853                 return true;
2854         }
2855   
2856         // check every paragraph
2857   
2858         LyXParagraph * par = FirstParagraph();
2859         do {
2860 #ifndef NEW_INSETS
2861                 // make sure the paragraph is open
2862                 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2863 #endif
2864                         pos = par->GetPositionOfInset(inset);
2865                         if (pos != -1){
2866                                 CheckParagraph(bview, par, pos);
2867                                 return true;
2868                         }
2869 #ifndef NEW_INSETS
2870                 }
2871 #endif
2872                 par = par->Next();
2873         } while (par);
2874   
2875         return false;
2876 }
2877
2878
2879 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2880                         LyXParagraph::size_type pos, 
2881                         bool setfont, bool boundary) const
2882 {
2883         LyXCursor old_cursor = cursor;
2884         SetCursorIntern(bview, par, pos, setfont, boundary);
2885         DeleteEmptyParagraphMechanism(bview, old_cursor);
2886 }
2887
2888
2889 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2890                         LyXParagraph::size_type pos, bool boundary) const
2891 {
2892 #ifndef NEW_INSETS
2893         // correct the cursor position if impossible
2894         if (pos > par->Last()){
2895                 LyXParagraph * tmppar = par->ParFromPos(pos);
2896                 pos = par->PositionInParFromPos(pos);
2897                 par = tmppar;
2898         }
2899         if (par->IsDummy() && par->previous &&
2900             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2901                 while (par->previous &&
2902                        ((par->previous->IsDummy() &&
2903                          (par->previous->previous->footnoteflag ==
2904                           LyXParagraph::CLOSED_FOOTNOTE)) ||
2905                         (par->previous->footnoteflag ==
2906                          LyXParagraph::CLOSED_FOOTNOTE))) {
2907                         par = par->previous ;
2908                         if (par->IsDummy() &&
2909                             (par->previous->footnoteflag ==
2910                              LyXParagraph::CLOSED_FOOTNOTE))
2911                                 pos += par->size() + 1;
2912                 }
2913                 if (par->previous) {
2914                         par = par->previous;
2915                 }
2916                 pos += par->size() + 1;
2917         }
2918 #endif
2919         cur.par(par);
2920         cur.pos(pos);
2921         cur.boundary(boundary);
2922
2923         /* get the cursor y position in text  */
2924         long y = 0;
2925         Row * row = GetRow(par, pos, y);
2926         /* y is now the beginning of the cursor row */ 
2927         y += row->baseline();
2928         /* y is now the cursor baseline */ 
2929         cur.y(y);
2930    
2931         /* now get the cursors x position */
2932         float x;
2933         float fill_separator, fill_hfill, fill_label_hfill;
2934         PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2935                        fill_label_hfill);
2936         LyXParagraph::size_type cursor_vpos = 0;
2937         LyXParagraph::size_type last = RowLastPrintable(row);
2938
2939         if (pos > last + 1)   // This shouldn't happen.
2940                 pos = last + 1;
2941         else if (pos < row->pos())
2942                 pos = row->pos();
2943
2944         if (last < row->pos())
2945                 cursor_vpos = row->pos();
2946         else if (pos > last && !boundary)
2947                 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2948                         ? row->pos() : last + 1; 
2949         else if (pos > row->pos() &&
2950                  (pos > last || boundary
2951 #ifndef NEW_TABULAR
2952                   || (row->par()->table && row->par()->IsNewline(pos))
2953 #endif
2954                          ))
2955                 /// Place cursor after char at (logical) position pos - 1
2956                 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2957                         ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2958         else
2959                 /// Place cursor before char at (logical) position pos
2960                 cursor_vpos = (bidi_level(pos) % 2 == 0)
2961                         ? log2vis(pos) : log2vis(pos) + 1;
2962
2963 #ifndef NEW_TABULAR
2964         /* table stuff -- begin*/
2965         if (row->par()->table) {
2966                 int cell = NumberOfCell(row->par(), row->pos());
2967                 float x_old = x;
2968                 x += row->par()->table->GetBeginningOfTextInCell(cell);
2969                 for (LyXParagraph::size_type vpos = row->pos();
2970                      vpos < cursor_vpos; ++vpos) {
2971                         pos = vis2log(vpos);
2972                         if (row->par()->IsNewline(pos)) {
2973                                 x = x_old + row->par()->table->WidthOfColumn(cell);
2974                                 x_old = x;
2975                                 ++cell;
2976                                 x += row->par()->table->GetBeginningOfTextInCell(cell);
2977                         } else {
2978                                 x += SingleWidth(bview, row->par(), pos);
2979                         }
2980                 }
2981         } else {
2982                 /* table stuff -- end*/
2983 #endif
2984                 LyXParagraph::size_type main_body =
2985                         BeginningOfMainBody(bview->buffer(), row->par());
2986                 if ((main_body > 0) &&
2987                     ((main_body-1 > last) || 
2988                      !row->par()->IsLineSeparator(main_body-1)))
2989                         main_body = 0;
2990
2991                 for (LyXParagraph::size_type vpos = row->pos();
2992                      vpos < cursor_vpos; ++vpos) {
2993                         pos = vis2log(vpos);
2994                         if (main_body > 0 && pos == main_body-1) {
2995                                 x += fill_label_hfill +
2996                                         lyxfont::width(textclasslist.Style(
2997                                                 bview->buffer()->params.textclass,
2998                                                 row->par()->GetLayout())
2999                                                        .labelsep,
3000                                                        GetFont(bview->buffer(), row->par(), -2));
3001                                 if (row->par()->IsLineSeparator(main_body-1))
3002                                         x -= SingleWidth(bview, row->par(),main_body-1);
3003                         }
3004                         if (HfillExpansion(bview->buffer(), row, pos)) {
3005                                 x += SingleWidth(bview, row->par(), pos);
3006                                 if (pos >= main_body)
3007                                         x += fill_hfill;
3008                                 else 
3009                                         x += fill_label_hfill;
3010                         } else if (row->par()->IsSeparator(pos)) {
3011                                 x += SingleWidth(bview, row->par(), pos);
3012                                 if (pos >= main_body)
3013                                         x += fill_separator;
3014                         } else
3015                                 x += SingleWidth(bview, row->par(), pos);
3016                 }
3017 #ifndef NEW_TABULAR
3018         }
3019 #endif
3020    
3021         cur.x(int(x));
3022         cur.x_fix(cur.x());
3023         cur.row(row);
3024 }
3025
3026
3027 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
3028                               LyXParagraph::size_type pos,
3029                               bool setfont, bool boundary) const
3030 {
3031         SetCursor(bview, cursor, par, pos, boundary);
3032         if (setfont)
3033                 SetCurrentFont(bview);
3034 }
3035
3036 void LyXText::SetCurrentFont(BufferView * bview) const
3037 {
3038         LyXParagraph::size_type pos = cursor.pos();
3039         if (cursor.boundary() && pos > 0)
3040                 --pos;
3041
3042         if (pos > 0) {
3043                 if (pos == cursor.par()->Last()
3044 #ifndef NEW_TABULAR
3045                     || (cursor.par()->table && cursor.par()->IsNewline(pos))
3046 #endif
3047                         )
3048                         --pos;
3049                 else if (cursor.par()->IsSeparator(pos)) {
3050                         if (pos > cursor.row()->pos() &&
3051                             bidi_level(pos) % 2 == 
3052                             bidi_level(pos - 1) % 2)
3053                                 --pos;
3054                         else if (pos + 1 < cursor.par()->Last())
3055                                 ++pos;
3056                 }
3057         }
3058
3059         current_font =
3060                 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
3061         real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
3062
3063         if (cursor.pos() == cursor.par()->Last() &&
3064             IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
3065             !cursor.boundary()) {
3066                 Language const * lang =
3067                         cursor.par()->getParLanguage(bview->buffer()->params);
3068                 current_font.setLanguage(lang);
3069                 real_current_font.setLanguage(lang);
3070         }
3071 }
3072
3073
3074 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
3075 {
3076         LyXCursor old_cursor = cursor;
3077    
3078         /* get the row first */ 
3079    
3080         Row * row = GetRowNearY(y);
3081         cursor.par(row->par());
3082
3083         bool bound = false;
3084         int column = GetColumnNearX(bview, row, x, bound);
3085         cursor.pos(row->pos() + column);
3086         cursor.x(x);
3087         cursor.y(y + row->baseline());
3088         cursor.row(row);
3089         cursor.boundary(bound);
3090         SetCurrentFont(bview);
3091         DeleteEmptyParagraphMechanism(bview, old_cursor);
3092 }
3093
3094
3095 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3096                                        int x, long y) const
3097 {
3098         /* get the row first */ 
3099    
3100         Row * row = GetRowNearY(y);
3101         bool bound = false;
3102         int column = GetColumnNearX(bview, row, x, bound);
3103    
3104         cur.par(row->par());
3105         cur.pos(row->pos() + column);
3106         cur.x(x);
3107         cur.y(y + row->baseline());
3108         cur.row(row);
3109         cur.boundary(bound);
3110 }
3111
3112
3113 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3114 {
3115         CursorLeftIntern(bview, internal);
3116 #ifndef NEW_TABULAR
3117         if (cursor.par()->table) {
3118                 int cell = NumberOfCell(cursor.par(), cursor.pos());
3119                 if (cursor.par()->table->IsContRow(cell)
3120                     && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3121                         CursorUp(bview);
3122                 }
3123         }
3124 #endif
3125 }
3126
3127
3128 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3129 {
3130         if (cursor.pos() > 0) {
3131                 bool boundary = cursor.boundary();
3132                 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3133                 if (!internal && !boundary &&
3134                     IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3135                         SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3136         } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3137                 LyXParagraph * par = cursor.par()->Previous();
3138                 SetCursor(bview, par, par->Last());
3139         }
3140 }
3141
3142
3143 void LyXText::CursorRight(BufferView * bview, bool internal) const
3144 {
3145         CursorRightIntern(bview, internal);
3146 #ifndef NEW_TABULAR
3147         if (cursor.par()->table) {
3148                 int cell = NumberOfCell(cursor.par(), cursor.pos());
3149                 if (cursor.par()->table->IsContRow(cell) &&
3150                     cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3151                         CursorUp(bview);
3152                 }
3153         }
3154 #endif
3155 }
3156
3157
3158 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3159 {
3160         if (!internal && cursor.boundary() &&
3161             (
3162 #ifndef NEW_TABULAR
3163                     !cursor.par()->table ||
3164 #endif
3165                     !cursor.par()->IsNewline(cursor.pos())))
3166                 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3167         else if (cursor.pos() < cursor.par()->Last()) {
3168                 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3169                 if (!internal &&
3170                     IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3171                         SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3172         } else if (cursor.par()->Next())
3173                 SetCursor(bview, cursor.par()->Next(), 0);
3174 }
3175
3176
3177 void LyXText::CursorUp(BufferView * bview) const
3178 {
3179         SetCursorFromCoordinates(bview, cursor.x_fix(), 
3180                                  cursor.y() - cursor.row()->baseline() - 1);
3181 #ifndef NEW_TABULAR
3182         if (cursor.par()->table) {
3183                 int cell = NumberOfCell(cursor.par(), cursor.pos());
3184                 if (cursor.par()->table->IsContRow(cell) &&
3185                     cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3186                         CursorUp(bview);
3187                 }
3188         }
3189 #endif
3190 }
3191
3192
3193 void LyXText::CursorDown(BufferView * bview) const
3194 {
3195 #ifndef NEW_TABULAR
3196         if (cursor.par()->table &&
3197             cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3198             !cursor.par()->next)
3199                 return;
3200 #endif
3201         
3202         SetCursorFromCoordinates(bview, cursor.x_fix(), 
3203                                  cursor.y() - cursor.row()->baseline()
3204                                  + cursor.row()->height() + 1);
3205 #ifndef NEW_TABULAR
3206         if (cursor.par()->table) {
3207                 int cell = NumberOfCell(cursor.par(), cursor.pos());
3208                 int cell_above = cursor.par()->table->GetCellAbove(cell);
3209                 while(cursor.par()->table &&
3210                       cursor.par()->table->IsContRow(cell) &&
3211                       (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3212                     SetCursorFromCoordinates(bview, cursor.x_fix(), 
3213                                              cursor.y() - cursor.row()->baseline()
3214                                              + cursor.row()->height() + 1);
3215                     if (cursor.par()->table) {
3216                         cell = NumberOfCell(cursor.par(), cursor.pos());
3217                         cell_above = cursor.par()->table->GetCellAbove(cell);
3218                     }
3219                 }
3220         }
3221 #endif
3222 }
3223
3224
3225 void LyXText::CursorUpParagraph(BufferView * bview) const
3226 {
3227         if (cursor.pos() > 0) {
3228                 SetCursor(bview, cursor.par(), 0);
3229         }
3230         else if (cursor.par()->Previous()) {
3231                 SetCursor(bview, cursor.par()->Previous(), 0);
3232         }
3233 }
3234
3235
3236 void LyXText::CursorDownParagraph(BufferView * bview) const
3237 {
3238         if (cursor.par()->Next()) {
3239                 SetCursor(bview, cursor.par()->Next(), 0);
3240         } else {
3241                 SetCursor(bview, cursor.par(), cursor.par()->Last());
3242         }
3243 }
3244
3245
3246 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3247                                             LyXCursor const & old_cursor) const
3248 {
3249         // Would be wrong to delete anything if we have a selection.
3250         if (selection) return;
3251
3252         // We allow all kinds of "mumbo-jumbo" when freespacing.
3253         if (textclasslist.Style(bview->buffer()->params.textclass,
3254                                 old_cursor.par()->GetLayout()).free_spacing)
3255                 return;
3256
3257         bool deleted = false;
3258         
3259         /* Ok I'll put some comments here about what is missing.
3260            I have fixed BackSpace (and thus Delete) to not delete
3261            double-spaces automagically. I have also changed Cut,
3262            Copy and Paste to hopefully do some sensible things.
3263            There are still some small problems that can lead to
3264            double spaces stored in the document file or space at
3265            the beginning of paragraphs. This happens if you have
3266            the cursor betwenn to spaces and then save. Or if you
3267            cut and paste and the selection have a space at the
3268            beginning and then save right after the paste. I am
3269            sure none of these are very hard to fix, but I will
3270            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3271            that I can get some feedback. (Lgb)
3272         */
3273
3274         // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3275         // delete the LineSeparator.
3276         // MISSING
3277
3278         // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3279         // delete the LineSeparator.
3280         // MISSING
3281
3282         // If the pos around the old_cursor were spaces, delete one of them.
3283         if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) { 
3284                 // Only if the cursor has really moved
3285                 
3286                 if (old_cursor.pos() > 0
3287                     && old_cursor.pos() < old_cursor.par()->Last()
3288                     && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3289                     && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3290                         old_cursor.par()->Erase(old_cursor.pos() - 1);
3291                         RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3292                         // correct cursor
3293                         if (old_cursor.par() == cursor.par() &&
3294                             cursor.pos() > old_cursor.pos()) {
3295                                 SetCursorIntern(bview, cursor.par(),
3296                                                 cursor.pos() - 1);
3297                         } else
3298                                 SetCursorIntern(bview, cursor.par(),
3299                                                 cursor.pos());
3300                         return;
3301                 }
3302         }
3303
3304         // Do not delete empty paragraphs with keepempty set.
3305         if ((textclasslist.Style(bview->buffer()->params.textclass,
3306                                  old_cursor.par()->GetLayout())).keepempty)
3307                 return;
3308
3309         LyXCursor tmpcursor;
3310
3311         if (old_cursor.par() != cursor.par()) {
3312                 if ( (old_cursor.par()->Last() == 0
3313                       || (old_cursor.par()->Last() == 1
3314                           && old_cursor.par()->IsLineSeparator(0)))
3315 #ifndef NEW_INSETS
3316                      && old_cursor.par()->FirstPhysicalPar()
3317                      == old_cursor.par()->LastPhysicalPar()
3318 #endif
3319                         ) {
3320                         // ok, we will delete anything
3321                         
3322                         // make sure that you do not delete any environments
3323 #ifndef NEW_INSETS
3324                         if ((
3325                                 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3326                              !(old_cursor.row()->previous() 
3327                                && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3328                              && !(old_cursor.row()->next() 
3329                                   && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3330                             || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3331                                 && ((old_cursor.row()->previous() 
3332                                      && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3333                                     || (old_cursor.row()->next()
3334                                         && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3335                                     )) {
3336 #endif
3337                                 status = LyXText::NEED_MORE_REFRESH;
3338                                 deleted = true;
3339                                 
3340                                 if (old_cursor.row()->previous()) {
3341                                         refresh_row = old_cursor.row()->previous();
3342                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3343                                         tmpcursor = cursor;
3344                                         cursor = old_cursor; // that undo can restore the right cursor position
3345                                         LyXParagraph * endpar = old_cursor.par()->next;
3346                                         if (endpar && endpar->GetDepth()) {
3347                                                 while (endpar && endpar->GetDepth()) {
3348 #ifndef NEW_INSETS
3349                                                         endpar = endpar->LastPhysicalPar()->Next();
3350 #else
3351                                                         endpar = endpar->Next();
3352 #endif
3353                                                 }
3354                                         }
3355                                         SetUndo(bview->buffer(), Undo::DELETE,
3356                                                 old_cursor.par()->previous,
3357                                                 endpar);
3358                                         cursor = tmpcursor;
3359
3360                                         // delete old row
3361                                         RemoveRow(old_cursor.row());
3362                                         if (OwnerParagraph() == old_cursor.par()) {
3363                                                 OwnerParagraph(OwnerParagraph()->next);
3364                                         }
3365                                         // delete old par
3366                                         delete old_cursor.par();
3367                                         
3368                                         /* Breakagain the next par. Needed
3369                                          * because of the parindent that
3370                                          * can occur or dissappear. The
3371                                          * next row can change its height,
3372                                          * if there is another layout before */
3373                                         if (refresh_row->next()) {
3374                                                 BreakAgain(bview, refresh_row->next());
3375                                                 UpdateCounters(bview, refresh_row);
3376                                         }
3377                                         SetHeightOfRow(bview, refresh_row);
3378                                 } else {
3379                                         refresh_row = old_cursor.row()->next();
3380                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3381                                         
3382                                         tmpcursor = cursor;
3383                                         cursor = old_cursor; // that undo can restore the right cursor position
3384                                         LyXParagraph * endpar = old_cursor.par()->next;
3385                                         if (endpar && endpar->GetDepth()) {
3386                                                 while (endpar && endpar->GetDepth()) {
3387 #ifndef NEW_INSETS
3388                                                         endpar = endpar->LastPhysicalPar()->Next();
3389 #else
3390                                                         endpar = endpar->Next();
3391 #endif
3392                                                 }
3393                                         }
3394                                         SetUndo(bview->buffer(), Undo::DELETE,
3395                                                 old_cursor.par()->previous,
3396                                                 endpar);
3397                                         cursor = tmpcursor;
3398
3399                                         // delete old row
3400                                         RemoveRow(old_cursor.row());
3401                                         // delete old par
3402                                         if (OwnerParagraph() == old_cursor.par()) {
3403                                                 OwnerParagraph(OwnerParagraph()->next);
3404                                         }
3405                                         delete old_cursor.par();
3406                                         
3407                                         /* Breakagain the next par. Needed
3408                                            because of the parindent that can
3409                                            occur or dissappear.
3410                                            The next row can change its height,
3411                                            if there is another layout before
3412                                         */ 
3413                                         if (refresh_row) {
3414                                                 BreakAgain(bview, refresh_row);
3415                                                 UpdateCounters(bview, refresh_row->previous());
3416                                         }
3417                                 }
3418                                 
3419                                 // correct cursor y
3420
3421                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
3422
3423                                 if (sel_cursor.par()  == old_cursor.par()
3424                                     && sel_cursor.pos() == sel_cursor.pos()) {
3425                                         // correct selection
3426                                         sel_cursor = cursor;
3427                                 }
3428 #ifndef NEW_INSETS
3429                         }
3430 #endif
3431                 }
3432                 if (!deleted) {
3433                         if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3434                                 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3435                                 // correct cursor y
3436                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
3437                                 sel_cursor = cursor;
3438                         }
3439                 }
3440         }
3441 }
3442
3443
3444 LyXParagraph * LyXText::GetParFromID(int id)
3445 {
3446         LyXParagraph * result = FirstParagraph();
3447         while (result && result->id() != id)
3448                 result = result->next;
3449         return result;
3450 }
3451
3452
3453 // undo functions
3454 bool LyXText::TextUndo(BufferView * bview)
3455 {
3456         if (inset_owner)
3457                 return false;
3458         // returns false if no undo possible
3459         Undo * undo = bview->buffer()->undostack.pop();
3460         if (undo) {
3461                 FinishUndo();
3462                 if (!undo_frozen)
3463                         bview->buffer()->redostack
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::TextRedo(BufferView * bview)
3473 {
3474         if (inset_owner)
3475                 return false;
3476         // returns false if no redo possible
3477         Undo * undo = bview->buffer()->redostack.pop();
3478         if (undo) {
3479                 FinishUndo();
3480                 if (!undo_frozen)
3481                         bview->buffer()->undostack
3482                                 .push(CreateUndo(bview->buffer(), undo->kind, 
3483                                                  GetParFromID(undo->number_of_before_par),
3484                                                  GetParFromID(undo->number_of_behind_par)));
3485         }
3486         return TextHandleUndo(bview, undo);
3487 }
3488
3489
3490 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3491 {
3492         if (inset_owner)
3493                 return false;
3494         // returns false if no undo possible
3495         bool result = false;
3496         if (undo) {
3497                 LyXParagraph * before =
3498                         GetParFromID(undo->number_of_before_par); 
3499                 LyXParagraph * behind =
3500                         GetParFromID(undo->number_of_behind_par); 
3501                 LyXParagraph * tmppar;
3502                 LyXParagraph * tmppar2;
3503                 LyXParagraph * endpar;
3504                 LyXParagraph * tmppar5;
3505     
3506                 // if there's no before take the beginning
3507                 // of the document for redoing
3508                 if (!before)
3509                         SetCursorIntern(bview, FirstParagraph(), 0);
3510
3511                 // replace the paragraphs with the undo informations
3512
3513                 LyXParagraph * tmppar3 = undo->par;
3514                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3515                 LyXParagraph * tmppar4 = tmppar3;
3516                 if (tmppar4){
3517                         while (tmppar4->next)
3518                                 tmppar4 = tmppar4->next;
3519                 } // get last undo par
3520     
3521                 // now remove the old text if there is any
3522                 if (before != behind || (!behind && !before)){
3523                         if (before)
3524                                 tmppar5 = before->next;
3525                         else
3526                                 tmppar5 = OwnerParagraph();
3527                         tmppar2 = tmppar3;
3528                         while (tmppar5 && tmppar5 != behind){
3529                                 tmppar = tmppar5;
3530                                 tmppar5 = tmppar5->next;
3531                                 // a memory optimization for edit: Only layout information
3532                                 // is stored in the undo. So restore the text informations.
3533                                 if (undo->kind == Undo::EDIT) {
3534                                         tmppar2->setContentsFromPar(tmppar);
3535                                         tmppar->clearContents();
3536                                         tmppar2 = tmppar2->next;
3537                                 }
3538                         }
3539                 }
3540     
3541                 // put the new stuff in the list if there is one
3542                 if (tmppar3){
3543                         if (before)
3544                                 before->next = tmppar3;
3545                         else
3546                                 OwnerParagraph(tmppar3);
3547                         tmppar3->previous = before;
3548                 } else {
3549                         if (!before)
3550                                 OwnerParagraph(behind);
3551                 }
3552                 if (tmppar4) {
3553                         tmppar4->next = behind;
3554                         if (behind)
3555                                 behind->previous = tmppar4;
3556                 }
3557     
3558     
3559                 // Set the cursor for redoing
3560                 if (before) {
3561 #ifndef NEW_INSETS
3562                         SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3563 #else
3564                         SetCursorIntern(bview, before, 0);
3565 #endif
3566 #ifndef NEW_INSETS
3567                         // check wether before points to a closed float and open it if necessary
3568                         if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3569                             && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3570                                 tmppar4 = before;
3571                                 while (tmppar4->previous && 
3572                                        tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3573                                         tmppar4 = tmppar4->previous;
3574                                 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3575                                         tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3576                                         tmppar4 = tmppar4->next;
3577                                 }
3578                         }
3579 #endif
3580                 }
3581
3582 #ifndef NEW_INSETS
3583                 // open a cosed footnote at the end if necessary
3584                 if (behind && behind->previous && 
3585                     behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3586                     behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3587                         while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3588                                 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3589                                 behind = behind->next;
3590                         }
3591                 }
3592 #endif
3593     
3594                 // calculate the endpar for redoing the paragraphs.
3595                 if (behind) {
3596 #ifndef NEW_INSETS
3597                         if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3598                                 endpar = behind->LastPhysicalPar()->Next();
3599                         else
3600                                 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3601 #else
3602                                 endpar = behind->Next();
3603 #endif
3604                 } else
3605                         endpar = behind;
3606     
3607                 tmppar = GetParFromID(undo->number_of_cursor_par);
3608                 RedoParagraphs(bview, cursor, endpar); 
3609                 if (tmppar){
3610                         SetCursorIntern(bview, tmppar, undo->cursor_pos);
3611                         UpdateCounters(bview, cursor.row());
3612                 }
3613                 result = true;
3614                 delete undo;
3615         }
3616         FinishUndo();
3617         return result;
3618 }
3619
3620
3621 void LyXText::FinishUndo()
3622 {
3623         if (inset_owner)
3624                 return;
3625         // makes sure the next operation will be stored
3626         undo_finished = true;
3627 }
3628
3629
3630 void LyXText::FreezeUndo()
3631 {
3632         if (inset_owner)
3633                 return;
3634         // this is dangerous and for internal use only
3635         undo_frozen = true;
3636 }
3637
3638
3639 void LyXText::UnFreezeUndo()
3640 {
3641         if (inset_owner)
3642                 return;
3643         // this is dangerous and for internal use only
3644         undo_frozen = false;
3645 }
3646
3647
3648 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3649                       LyXParagraph const * before,
3650                       LyXParagraph const * behind) const
3651 {
3652         if (inset_owner)
3653                 return;
3654         if (!undo_frozen)
3655                 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3656         buf->redostack.clear();
3657 }
3658
3659
3660 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3661                       LyXParagraph const * before, LyXParagraph const * behind)
3662 {
3663         if (inset_owner)
3664                 return;
3665         buf->redostack.push(CreateUndo(buf, kind, before, behind));
3666 }
3667
3668
3669 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3670                            LyXParagraph const * before,
3671                            LyXParagraph const * behind) const
3672 {
3673         if (inset_owner)
3674                 return 0;
3675
3676         int before_number = -1;
3677         int behind_number = -1;
3678         if (before)
3679                 before_number = before->id();
3680         if (behind)
3681                 behind_number = behind->id();
3682         // Undo::EDIT  and Undo::FINISH are
3683         // always finished. (no overlapping there)
3684         // overlapping only with insert and delete inside one paragraph: 
3685         // Nobody wants all removed  character
3686         // appear one by one when undoing. 
3687         // EDIT is special since only layout information, not the
3688         // contents of a paragaph are stored.
3689         if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3690                 // check wether storing is needed
3691                 if (!buf->undostack.empty() && 
3692                     buf->undostack.top()->kind == kind &&
3693                     buf->undostack.top()->number_of_before_par ==  before_number &&
3694                     buf->undostack.top()->number_of_behind_par ==  behind_number ){
3695                         // no undo needed
3696                         return 0;
3697                 }
3698         }
3699         // create a new Undo
3700         LyXParagraph * undopar;
3701         LyXParagraph * tmppar;
3702         LyXParagraph * tmppar2;
3703
3704         LyXParagraph * start = 0;
3705         LyXParagraph * end = 0;
3706   
3707         if (before)
3708                 start = before->next;
3709         else
3710                 start = FirstParagraph();
3711         if (behind)
3712                 end = behind->previous;
3713         else {
3714                 end = FirstParagraph();
3715                 while (end->next)
3716                         end = end->next;
3717         }
3718
3719         if (start && end
3720             && start != end->next
3721             && (before != behind || (!before && !behind))) {
3722                 tmppar = start;
3723                 tmppar2 = tmppar->Clone();
3724                 tmppar2->id(tmppar->id());
3725
3726                 // a memory optimization: Just store the layout information
3727                 // when only edit
3728                 if (kind == Undo::EDIT){
3729                         //tmppar2->text.clear();
3730                         tmppar2->clearContents();
3731                 }
3732
3733                 undopar = tmppar2;
3734   
3735                 while (tmppar != end && tmppar->next) {
3736                         tmppar = tmppar->next;
3737                         tmppar2->next = tmppar->Clone();
3738                         tmppar2->next->id(tmppar->id());
3739                         // a memory optimization: Just store the layout
3740                         // information when only edit
3741                         if (kind == Undo::EDIT){
3742                                 //tmppar2->next->text.clear();
3743                                 tmppar2->clearContents();
3744                         }
3745                         tmppar2->next->previous = tmppar2;
3746                         tmppar2 = tmppar2->next;
3747                 }
3748                 tmppar2->next = 0;
3749         } else
3750                 undopar = 0; // nothing to replace (undo of delete maybe)
3751
3752 #ifndef NEW_INSETS
3753         int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3754         int cursor_pos =  cursor.par()->PositionInParFromPos(cursor.pos());
3755 #else
3756         int cursor_par = cursor.par()->id();
3757         int cursor_pos =  cursor.pos();
3758 #endif
3759
3760         Undo * undo = new Undo(kind, 
3761                                before_number, behind_number,  
3762                                cursor_par, cursor_pos, 
3763                                undopar);
3764   
3765         undo_finished = false;
3766         return undo;
3767 }
3768
3769
3770 void LyXText::SetCursorParUndo(Buffer * buf)
3771 {
3772         if (inset_owner)
3773                 return;
3774         SetUndo(buf, Undo::FINISH,
3775 #ifndef NEW_INSETS
3776                 cursor.par()->ParFromPos(cursor.pos())->previous, 
3777                 cursor.par()->ParFromPos(cursor.pos())->next
3778 #else
3779                 cursor.par()->previous, 
3780                 cursor.par()->next
3781 #endif
3782                 ); 
3783 }
3784
3785
3786 #ifndef NEW_TABULAR
3787 void LyXText::RemoveTableRow(LyXCursor & cur) const
3788 {
3789         int cell = -1;
3790         int cell_org = 0;
3791         int ocell = 0;
3792     
3793         // move to the previous row
3794         int cell_act = NumberOfCell(cur.par(), cur.pos());
3795         if (cell < 0)
3796                 cell = cell_act;
3797         while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3798                 cur.pos(cur.pos() - 1);
3799         while (cur.pos() && 
3800                !cur.par()->table->IsFirstCell(cell_act)) {
3801                 cur.pos(cur.pos() - 1);
3802                 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3803                         cur.pos(cur.pos() - 1);
3804                 --cell;
3805                 --cell_act;
3806         }
3807         // now we have to pay attention if the actual table is the
3808         //   main row of TableContRows and if yes to delete all of them
3809         if (!cell_org)
3810                 cell_org = cell;
3811         do {
3812                 ocell = cell;
3813                 // delete up to the next row
3814                 while (cur.pos() < cur.par()->Last() && 
3815                        (cell_act == ocell
3816                         || !cur.par()->table->IsFirstCell(cell_act))) {
3817                         while (cur.pos() < cur.par()->Last() &&
3818                                !cur.par()->IsNewline(cur.pos()))
3819                                 cur.par()->Erase(cur.pos());
3820                         ++cell;
3821                         ++cell_act;
3822                         if (cur.pos() < cur.par()->Last())
3823                                 cur.par()->Erase(cur.pos());
3824                 }
3825                 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3826                         cur.pos(cur.pos() - 1);
3827                         cur.par()->Erase(cur.pos()); // no newline at very end!
3828                 }
3829         } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3830                  !cur.par()->table->IsContRow(cell_org) &&
3831                  cur.par()->table->IsContRow(cell));
3832         cur.par()->table->DeleteRow(cell_org);
3833         return;
3834 }
3835 #endif
3836
3837
3838 #ifndef NEW_TABULAR
3839 bool LyXText::IsEmptyTableCell() const
3840 {
3841         LyXParagraph::size_type pos = cursor.pos() - 1;
3842         while (pos >= 0 && pos < cursor.par()->Last()
3843                && !cursor.par()->IsNewline(pos))
3844                 --pos;
3845         return cursor.par()->IsNewline(pos + 1);
3846 }
3847 #endif
3848
3849
3850 void LyXText::toggleAppendix(BufferView * bview)
3851 {
3852 #ifndef NEW_INSETS
3853         LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3854 #else
3855         LyXParagraph * par = cursor.par();
3856 #endif
3857         bool start = !par->start_of_appendix;
3858
3859         // ensure that we have only one start_of_appendix in this document
3860         LyXParagraph * tmp = FirstParagraph();
3861         for (; tmp; tmp = tmp->next)
3862                 tmp->start_of_appendix = 0;
3863         par->start_of_appendix = start;
3864
3865         // we can set the refreshing parameters now
3866         status = LyXText::NEED_MORE_REFRESH;
3867         refresh_y = 0;
3868         refresh_row = 0; // not needed for full update
3869         UpdateCounters(bview, 0);
3870         SetCursor(bview, cursor.par(), cursor.pos());
3871 }
3872
3873
3874 LyXParagraph * LyXText::OwnerParagraph() const
3875 {
3876         if (inset_owner)
3877                 return inset_owner->par;
3878
3879         return bv_owner->buffer()->paragraph;
3880 }
3881
3882
3883 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3884 {
3885         if (inset_owner)
3886                 inset_owner->par = p;
3887         else
3888                 bv_owner->buffer()->paragraph = p;
3889         return 0;
3890 }