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