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