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