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