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