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