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