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