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