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