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