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