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