]> git.lyx.org Git - lyx.git/blob - src/text2.C
Three patches from Dekel. Read ChangeLog
[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         else if (pos < row->pos)
3179                 pos = row->pos;
3180
3181         if (last < row->pos)
3182                 cursor_vpos = row->pos;
3183         else if (pos > last && !boundary)
3184                 cursor_vpos = (row->par->isRightToLeftPar())
3185                         ? row->pos : last+1; 
3186         else if (pos > row->pos &&
3187                  (pos > last || boundary || 
3188                   (row->par->table && row->par->IsNewline(pos))))
3189                 /// Place cursor after char at (logical) position pos-1
3190                 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
3191                         ? log2vis(pos-1) + 1 : log2vis(pos-1);
3192         else
3193                 /// Place cursor before char at (logical) position pos
3194                 cursor_vpos = (bidi_level(pos) % 2 == 0)
3195                         ? log2vis(pos) : log2vis(pos) + 1;
3196
3197         /* table stuff -- begin*/
3198         if (row->par->table) {
3199                 int cell = NumberOfCell(row->par, row->pos);
3200                 float x_old = x;
3201                 x += row->par->table->GetBeginningOfTextInCell(cell);
3202                 for (LyXParagraph::size_type vpos = row->pos;
3203                      vpos < cursor_vpos; ++vpos) {
3204                         pos = vis2log(vpos);
3205                         if (row->par->IsNewline(pos)) {
3206                                 x = x_old + row->par->table->WidthOfColumn(cell);
3207                                 x_old = x;
3208                                 ++cell;
3209                                 x += row->par->table->GetBeginningOfTextInCell(cell);
3210                         } else {
3211                                 x += SingleWidth(row->par, pos);
3212                         }
3213                 }
3214         } else {
3215                 /* table stuff -- end*/
3216                 LyXParagraph::size_type main_body =
3217                         BeginningOfMainBody(row->par);
3218                 if ((main_body > 0) &&
3219                     ((main_body-1 > last) || 
3220                      !row->par->IsLineSeparator(main_body-1)))
3221                         main_body = 0;
3222
3223                 for (LyXParagraph::size_type vpos = row->pos;
3224                      vpos < cursor_vpos; ++vpos) {
3225                         pos = vis2log(vpos);
3226                         if (main_body > 0 && pos == main_body-1) {
3227                                 x += fill_label_hfill +
3228                                         lyxfont::width(textclasslist.Style(
3229                                                 buffer->params.textclass,
3230                                                 row->par->GetLayout())
3231                                                        .labelsep,
3232                                                        GetFont(row->par, -2));
3233                                 if (row->par->IsLineSeparator(main_body-1))
3234                                         x -= SingleWidth(row->par,main_body-1);
3235                         }
3236                         if (HfillExpansion(row, pos)) {
3237                                 x += SingleWidth(row->par, pos);
3238                                 if (pos >= main_body)
3239                                         x += fill_hfill;
3240                                 else 
3241                                         x += fill_label_hfill;
3242                         } else if (row->par->IsSeparator(pos)) {
3243                                 x += SingleWidth(row->par, pos);
3244                                 if (pos >= main_body)
3245                                         x += fill_separator;
3246                         } else
3247                                 x += SingleWidth(row->par, pos);
3248                 }
3249         }
3250    
3251         cur.x = int(x);
3252         cur.x_fix = cur.x;
3253         cur.row = row;
3254 }
3255
3256
3257 void LyXText::SetCursorIntern(LyXParagraph * par,
3258                               LyXParagraph::size_type pos,
3259                               bool setfont, bool boundary) const
3260 {
3261         SetCursor(cursor, par, pos, boundary);
3262 // #warning Remove this when verified working (Jug 20000413)
3263 #if 0
3264         // correct the cursor position if impossible
3265         if (pos > par->Last()){
3266                 LyXParagraph * tmppar = par->ParFromPos(pos);
3267                 pos = par->PositionInParFromPos(pos);
3268                 par = tmppar;
3269         }
3270         if (par->IsDummy() && par->previous &&
3271             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3272                 while (par->previous &&
3273                        ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
3274                         (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
3275                         par = par->previous ;
3276                         if (par->IsDummy() &&
3277                             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3278                                 pos += par->size() + 1;
3279                 }
3280                 if (par->previous) {
3281                         par = par->previous;
3282                 }
3283                 pos += par->size() + 1;
3284         }
3285
3286         cursor.par = par;
3287         cursor.pos = pos;
3288
3289         /* get the cursor y position in text  */
3290         long y = 0;
3291         Row * row = GetRow(par, pos, y);
3292         /* y is now the beginning of the cursor row */ 
3293         y += row->baseline;
3294         /* y is now the cursor baseline */ 
3295         cursor.y = y;
3296    
3297         /* now get the cursors x position */
3298         float x;
3299         float fill_separator, fill_hfill, fill_label_hfill;
3300         PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3301         LyXParagraph::size_type cursor_vpos;
3302         LyXParagraph::size_type last = RowLastPrintable(row);
3303
3304         if (pos > last + 1)   // This shouldn't happen.
3305                 pos = last+1;
3306
3307         if (last < row->pos)
3308                 cursor_vpos = 0;
3309         else if (pos > last ||
3310             (pos - 1 >= row->pos &&
3311              (row->par->IsSeparator(pos) ||
3312               (row->par->table && row->par->IsNewline(pos))
3313               )))
3314                 /// Place cursor after char at (logical) position pos-1
3315                 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
3316                         ? log2vis(pos-1) + 1 : log2vis(pos-1);
3317         else
3318                 /// Place cursor before char at (logical) position pos
3319                 cursor_vpos = (bidi_level(pos) % 2 == 0)
3320                         ? log2vis(pos) : log2vis(pos) + 1;
3321
3322         /* table stuff -- begin*/
3323         if (row->par->table) {
3324                 int cell = NumberOfCell(row->par, row->pos);
3325                 float x_old = x;
3326                 x += row->par->table->GetBeginningOfTextInCell(cell);
3327                 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos)  {
3328                         pos = vis2log(vpos);
3329                         if (row->par->IsNewline(pos)) {
3330                                 x = x_old + row->par->table->WidthOfColumn(cell);
3331                                 x_old = x;
3332                                 ++cell;
3333                                 x += row->par->table->GetBeginningOfTextInCell(cell);
3334                         } else {
3335                                 x += SingleWidth(row->par, pos);
3336                         }
3337                 }
3338         } else {
3339                 /* table stuff -- end*/
3340                 LyXParagraph::size_type main_body =
3341                         BeginningOfMainBody(row->par);
3342                 if (main_body > 0 &&
3343                     (main_body-1 > last || 
3344                      !row->par->IsLineSeparator(main_body-1)))
3345                         main_body = 0;
3346
3347                 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos)  {
3348                         pos = vis2log(vpos);
3349                         if (main_body > 0 && pos == main_body-1) {
3350                                 x += fill_label_hfill +
3351                                         lyxfont::width(textclasslist
3352                                                        .Style(buffer->params.textclass,
3353                                                               row->par->GetLayout())
3354                                                        .labelsep,
3355                                                        GetFont(row->par, -2));
3356                                 if (row->par->IsLineSeparator(main_body-1))
3357                                         x -= SingleWidth(row->par, main_body-1);
3358                         }
3359                         if (HfillExpansion(row, pos)) {
3360                                 x += SingleWidth(row->par, pos);
3361                                 if (pos >= main_body)
3362                                         x += fill_hfill;
3363                                 else 
3364                                         x += fill_label_hfill;
3365                         }
3366                         else if (row->par->IsSeparator(pos)) {
3367                                 x += SingleWidth(row->par, pos);
3368                                 if (pos >= main_body)
3369                                         x += fill_separator;
3370                         } else
3371                                 x += SingleWidth(row->par, pos);
3372                 }
3373         }
3374    
3375         cursor.x = int(x);
3376    
3377         cursor.x_fix = cursor.x;
3378         cursor.row = row;
3379 #endif
3380         if (setfont)
3381                 SetCurrentFont();
3382 }
3383
3384 void LyXText::SetCurrentFont() const
3385 {
3386         LyXParagraph::size_type pos = cursor.pos;
3387         if (cursor.boundary && pos > 0)
3388                 --pos;
3389
3390         if (pos > 0) {
3391                 if (pos == cursor.par->Last() ||
3392                     (cursor.par->table && cursor.par->IsNewline(pos)))
3393                         --pos;
3394                 else if (cursor.par->IsSeparator(pos)) {
3395                         if (pos > cursor.row->pos &&
3396                             bidi_level(pos) % 2 == 
3397                             bidi_level(pos - 1) % 2)
3398                                 --pos;
3399                         else if (pos + 1 < cursor.par->Last())
3400                                 ++pos;
3401                 }
3402         }
3403
3404         current_font = cursor.par->GetFontSettings(pos);
3405         real_current_font = GetFont(cursor.par, pos);
3406 }
3407
3408
3409 void LyXText::SetCursorFromCoordinates(int x, long y) const
3410 {
3411         LyXCursor old_cursor = cursor;
3412    
3413         /* get the row first */ 
3414    
3415         Row * row = GetRowNearY(y);
3416         cursor.par = row->par;
3417
3418         int column = GetColumnNearX(row, x, cursor.boundary);
3419         cursor.pos = row->pos + column;
3420         cursor.x = x;
3421         cursor.y = y + row->baseline;
3422         cursor.row = row;
3423         SetCurrentFont();
3424         DeleteEmptyParagraphMechanism(old_cursor);
3425 }
3426
3427 void LyXText::SetCursorFromCoordinates(LyXCursor & cur, int x, long y) const
3428 {
3429         /* get the row first */ 
3430    
3431         Row * row = GetRowNearY(y);
3432         int column = GetColumnNearX(row, x, cur.boundary);
3433    
3434         cur.par = row->par;
3435         cur.pos = row->pos + column;
3436         cur.x = x;
3437         cur.y = y + row->baseline;
3438         cur.row = row;
3439 }
3440
3441
3442 void LyXText::CursorLeft(bool internal) const
3443 {
3444         CursorLeftIntern(internal);
3445         if (cursor.par->table) {
3446                 int cell = NumberOfCell(cursor.par, cursor.pos);
3447                 if (cursor.par->table->IsContRow(cell) &&
3448                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell)) < 0) {
3449                         CursorUp();
3450                 }
3451         }
3452 }
3453
3454
3455 void LyXText::CursorLeftIntern(bool internal) const
3456 {
3457         if (cursor.pos > 0) {
3458                 bool boundary = cursor.boundary;
3459                 SetCursor(cursor.par, cursor.pos - 1, true, false);
3460                 if (!internal && !boundary &&
3461                     IsBoundary(cursor.par, cursor.pos + 1))
3462                         SetCursor(cursor.par, cursor.pos + 1, true, true);
3463         } else if (cursor.par->Previous()) { // steps into the above paragraph.
3464                 LyXParagraph * par = cursor.par->Previous();
3465                 LyXParagraph::size_type pos = par->Last();
3466                 SetCursor(par, pos);
3467                 if (IsBoundary(par, pos))
3468                         SetCursor(par, pos, false, true);
3469         }
3470 }
3471
3472
3473 void LyXText::CursorRight(bool internal) const
3474 {
3475         CursorRightIntern(internal);
3476         if (cursor.par->table) {
3477                 int cell = NumberOfCell(cursor.par, cursor.pos);
3478                 if (cursor.par->table->IsContRow(cell) &&
3479                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3480                         CursorUp();
3481                 }
3482         }
3483 }
3484
3485
3486 void LyXText::CursorRightIntern(bool internal) const
3487 {
3488         if (cursor.pos < cursor.par->Last()) {
3489                 if (!internal && cursor.boundary &&
3490                     (!cursor.par->table || !cursor.par->IsNewline(cursor.pos)))
3491                         SetCursor(cursor.par, cursor.pos, true, false);
3492                 else {
3493                         SetCursor(cursor.par, cursor.pos + 1, true, false);
3494                         if (!internal && IsBoundary(cursor.par, cursor.pos))
3495                                 SetCursor(cursor.par, cursor.pos, true, true);
3496                 }
3497         } else if (cursor.par->Next())
3498                 SetCursor(cursor.par->Next(), 0);
3499 }
3500
3501
3502 void LyXText::CursorUp() const
3503 {
3504         SetCursorFromCoordinates(cursor.x_fix, 
3505                                  cursor.y - cursor.row->baseline - 1);
3506         if (cursor.par->table) {
3507                 int cell = NumberOfCell(cursor.par, cursor.pos);
3508                 if (cursor.par->table->IsContRow(cell) &&
3509                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3510                         CursorUp();
3511                 }
3512         }
3513 }
3514
3515
3516 void LyXText::CursorDown() const
3517 {
3518         if (cursor.par->table &&
3519             cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3520             !cursor.par->next)
3521                 return;
3522         SetCursorFromCoordinates(cursor.x_fix, 
3523                                  cursor.y - cursor.row->baseline
3524                                  + cursor.row->height + 1);
3525         if (cursor.par->table) {
3526                 int cell = NumberOfCell(cursor.par, cursor.pos);
3527                 int cell_above = cursor.par->table->GetCellAbove(cell);
3528                 while(cursor.par->table &&
3529                       cursor.par->table->IsContRow(cell) &&
3530                       (cursor.par->table->CellHasContRow(cell_above)<0)) {
3531                     SetCursorFromCoordinates(cursor.x_fix, 
3532                                              cursor.y - cursor.row->baseline
3533                                              + cursor.row->height + 1);
3534                     if (cursor.par->table) {
3535                         cell = NumberOfCell(cursor.par, cursor.pos);
3536                         cell_above = cursor.par->table->GetCellAbove(cell);
3537                     }
3538                 }
3539         }
3540 }
3541
3542
3543 void LyXText::CursorUpParagraph() const
3544 {
3545         if (cursor.pos > 0) {
3546                 SetCursor(cursor.par, 0);
3547         }
3548         else if (cursor.par->Previous()) {
3549                 SetCursor(cursor.par->Previous(), 0);
3550         }
3551 }
3552
3553
3554 void LyXText::CursorDownParagraph() const
3555 {
3556         if (cursor.par->Next()) {
3557                 SetCursor(cursor.par->Next(), 0);
3558         } else {
3559                 SetCursor(cursor.par, cursor.par->Last());
3560         }
3561 }
3562
3563
3564 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3565 {
3566         // Would be wrong to delete anything if we have a selection.
3567         if (selection) return;
3568
3569         // We allow all kinds of "mumbo-jumbo" when freespacing.
3570         if (textclasslist.Style(buffer->params.textclass,
3571                                 old_cursor.par->GetLayout()).free_spacing)
3572                 return;
3573
3574         bool deleted = false;
3575         
3576         /* Ok I'll put some comments here about what is missing.
3577            I have fixed BackSpace (and thus Delete) to not delete
3578            double-spaces automagically. I have also changed Cut,
3579            Copy and Paste to hopefully do some sensible things.
3580            There are still some small problems that can lead to
3581            double spaces stored in the document file or space at
3582            the beginning of paragraphs. This happens if you have
3583            the cursor betwenn to spaces and then save. Or if you
3584            cut and paste and the selection have a space at the
3585            beginning and then save right after the paste. I am
3586            sure none of these are very hard to fix, but I will
3587            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3588            that I can get some feedback. (Lgb)
3589         */
3590
3591         // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3592         // delete the LineSeparator.
3593         // MISSING
3594
3595         // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3596         // delete the LineSeparator.
3597         // MISSING
3598
3599         // If the pos around the old_cursor were spaces, delete one of them.
3600         if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) { 
3601                 // Only if the cursor has really moved
3602                 
3603                 if (old_cursor.pos > 0
3604                     && old_cursor.pos < old_cursor.par->Last()
3605                     && old_cursor.par->IsLineSeparator(old_cursor.pos)
3606                     && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3607                         old_cursor.par->Erase(old_cursor.pos - 1);
3608                         RedoParagraphs(old_cursor, old_cursor.par->Next());
3609                         // correct cursor
3610                         if (old_cursor.par == cursor.par &&
3611                             cursor.pos > old_cursor.pos) {
3612                                 SetCursorIntern(cursor.par, cursor.pos - 1);
3613                         } else
3614                                 SetCursorIntern(cursor.par, cursor.pos);
3615                         return;
3616                 }
3617         }
3618
3619         // Do not delete empty paragraphs with keepempty set.
3620         if ((textclasslist.Style(buffer->params.textclass,
3621                                  old_cursor.par->GetLayout())).keepempty)
3622                 return;
3623
3624         LyXCursor tmpcursor;
3625
3626         if (old_cursor.par != cursor.par) {
3627                 if ( (old_cursor.par->Last() == 0
3628                       || (old_cursor.par->Last() == 1
3629                           && old_cursor.par->IsLineSeparator(0)))
3630                      && old_cursor.par->FirstPhysicalPar()
3631                      == old_cursor.par->LastPhysicalPar()) {
3632                         // ok, we will delete anything
3633                         
3634                         // make sure that you do not delete any environments
3635                         if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3636                              !(old_cursor.row->previous 
3637                                && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3638                              && !(old_cursor.row->next 
3639                                   && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3640                             || (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3641                                 && ((old_cursor.row->previous 
3642                                      && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3643                                     || (old_cursor.row->next
3644                                         && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3645                                     )) {
3646                                 status = LyXText::NEED_MORE_REFRESH;
3647                                 deleted = true;
3648                                 
3649                                 if (old_cursor.row->previous) {
3650                                         refresh_row = old_cursor.row->previous;
3651                                         refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3652                                         tmpcursor = cursor;
3653                                         cursor = old_cursor; // that undo can restore the right cursor position
3654                                         LyXParagraph * endpar = old_cursor.par->next;
3655                                         if (endpar && endpar->GetDepth()) {
3656                                                 while (endpar && endpar->GetDepth()) {
3657                                                         endpar = endpar->LastPhysicalPar()->Next();
3658                                                 }
3659                                         }
3660                                         SetUndo(Undo::DELETE,
3661                                                 old_cursor.par->previous,
3662                                                 endpar);
3663                                         cursor = tmpcursor;
3664
3665                                         // delete old row
3666                                         RemoveRow(old_cursor.row);
3667                                         if (buffer->paragraph == old_cursor.par) {
3668                                                 buffer->paragraph = buffer->paragraph->next;
3669                                         }
3670                                         // delete old par
3671                                         delete old_cursor.par;
3672                                         
3673                                         /* Breakagain the next par. Needed
3674                                          * because of the parindent that
3675                                          * can occur or dissappear. The
3676                                          * next row can change its height,
3677                                          * if there is another layout before */
3678                                         if (refresh_row->next) {
3679                                                 BreakAgain(refresh_row->next);
3680                                                 UpdateCounters(refresh_row);
3681                                         }
3682                                         SetHeightOfRow(refresh_row);
3683                                 } else {
3684                                         refresh_row = old_cursor.row->next;
3685                                         refresh_y = old_cursor.y - old_cursor.row->baseline;
3686                                         
3687                                         tmpcursor = cursor;
3688                                         cursor = old_cursor; // that undo can restore the right cursor position
3689                                         LyXParagraph *endpar = old_cursor.par->next;
3690                                         if (endpar && endpar->GetDepth()) {
3691                                                 while (endpar && endpar->GetDepth()) {
3692                                                         endpar = endpar->LastPhysicalPar()->Next();
3693                                                 }
3694                                         }
3695                                         SetUndo(Undo::DELETE,
3696                                                 old_cursor.par->previous,
3697                                                 endpar);
3698                                         cursor = tmpcursor;
3699
3700                                         // delete old row
3701                                         RemoveRow(old_cursor.row);
3702                                         // delete old par
3703                                         if (buffer->paragraph == old_cursor.par) {
3704                                                 buffer->paragraph = buffer->paragraph->next;
3705                                         }
3706                                         delete old_cursor.par;
3707                                         
3708                                         /* Breakagain the next par. Needed
3709                                            because of the parindent that can
3710                                            occur or dissappear.
3711                                            The next row can change its height,
3712                                            if there is another layout before
3713                                         */ 
3714                                         if (refresh_row) {
3715                                                 BreakAgain(refresh_row);
3716                                                 UpdateCounters(refresh_row->previous);
3717                                         }
3718                                 }
3719                                 
3720                                 // correct cursor y
3721
3722                                 SetCursorIntern(cursor.par, cursor.pos);
3723
3724                                 if (sel_cursor.par  == old_cursor.par
3725                                     && sel_cursor.pos == sel_cursor.pos) {
3726                                         // correct selection
3727                                         sel_cursor = cursor;
3728                                 }
3729                         }
3730                 }
3731                 if (!deleted) {
3732                         if (old_cursor.par->StripLeadingSpaces(buffer->params.textclass)) {
3733                                 RedoParagraphs(old_cursor, old_cursor.par->Next());
3734                                 // correct cursor y
3735                                 SetCursorIntern(cursor.par, cursor.pos);
3736                                 sel_cursor = cursor;
3737                         }
3738                 }
3739         }
3740 }
3741
3742
3743 LyXParagraph * LyXText::GetParFromID(int id)
3744 {
3745         LyXParagraph * result = FirstParagraph();
3746         while (result && result->id() != id)
3747                 result = result->next;
3748         return result;
3749 }
3750
3751
3752 // undo functions
3753 bool LyXText::TextUndo()
3754 {
3755         // returns false if no undo possible
3756         Undo * undo = buffer->undostack.pop();
3757         if (undo) {
3758                 FinishUndo();
3759                 if (!undo_frozen)
3760                         buffer->redostack
3761                                 .push(CreateUndo(undo->kind, 
3762                                                  GetParFromID(undo->number_of_before_par),
3763                                                  GetParFromID(undo->number_of_behind_par)));
3764         }
3765         return TextHandleUndo(undo);
3766 }
3767
3768
3769 bool LyXText::TextRedo()
3770 {
3771         // returns false if no redo possible
3772         Undo * undo = buffer->redostack.pop();
3773         if (undo) {
3774                 FinishUndo();
3775                 if (!undo_frozen)
3776                         buffer->undostack
3777                                 .push(CreateUndo(undo->kind, 
3778                                                  GetParFromID(undo->number_of_before_par),
3779                                                  GetParFromID(undo->number_of_behind_par)));
3780         }
3781         return TextHandleUndo(undo);
3782 }
3783
3784
3785 bool LyXText::TextHandleUndo(Undo * undo)
3786 {
3787         // returns false if no undo possible
3788         bool result = false;
3789         if (undo) {
3790                 LyXParagraph * before =
3791                         GetParFromID(undo->number_of_before_par); 
3792                 LyXParagraph * behind =
3793                         GetParFromID(undo->number_of_behind_par); 
3794                 LyXParagraph * tmppar;
3795                 LyXParagraph * tmppar2;
3796                 LyXParagraph * endpar;
3797                 LyXParagraph * tmppar5;
3798     
3799                 // if there's no before take the beginning
3800                 // of the document for redoing
3801                 if (!before)
3802                         SetCursorIntern(FirstParagraph(), 0);
3803
3804                 // replace the paragraphs with the undo informations
3805
3806                 LyXParagraph * tmppar3 = undo->par;
3807                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3808                 LyXParagraph * tmppar4 = tmppar3;
3809                 if (tmppar4){
3810                         while (tmppar4->next)
3811                                 tmppar4 = tmppar4->next;
3812                 } // get last undo par
3813     
3814                 // now remove the old text if there is any
3815                 if (before != behind || (!behind && !before)){
3816                         if (before)
3817                                 tmppar5 = before->next;
3818                         else
3819                                 tmppar5 = buffer->paragraph;
3820                         tmppar2 = tmppar3;
3821                         while (tmppar5 && tmppar5 != behind){
3822                                 tmppar = tmppar5;
3823                                 tmppar5 = tmppar5->next;
3824                                 // a memory optimization for edit: Only layout information
3825                                 // is stored in the undo. So restore the text informations.
3826                                 if (undo->kind == Undo::EDIT) {
3827                                         tmppar2->setContentsFromPar(tmppar);
3828                                         tmppar->clearContents();
3829                                         tmppar2 = tmppar2->next;
3830                                 }
3831                         }
3832                 }
3833     
3834                 // put the new stuff in the list if there is one
3835                 if (tmppar3){
3836                         if (before)
3837                                 before->next = tmppar3;
3838                         else
3839                                 buffer->paragraph = tmppar3;
3840                         tmppar3->previous = before;
3841                 }
3842                 else {
3843                         if (!before)
3844                                 buffer->paragraph = behind;
3845                 }
3846                 if (tmppar4) {
3847                         tmppar4->next = behind;
3848                         if (behind)
3849                                 behind->previous = tmppar4;
3850                 }
3851     
3852     
3853                 // Set the cursor for redoing
3854                 if (before) {
3855                         SetCursorIntern(before->FirstSelfrowPar(), 0);
3856                         // check wether before points to a closed float and open it if necessary
3857                         if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3858                             && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3859                                 tmppar4 = before;
3860                                 while (tmppar4->previous && 
3861                                        tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3862                                         tmppar4 = tmppar4->previous;
3863                                 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3864                                         tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3865                                         tmppar4 = tmppar4->next;
3866                                 }
3867                         }
3868                 }
3869     
3870                 // open a cosed footnote at the end if necessary
3871                 if (behind && behind->previous && 
3872                     behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3873                     behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3874                         while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3875                                 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3876                                 behind = behind->next;
3877                         }
3878                 }
3879     
3880                 // calculate the endpar for redoing the paragraphs.
3881                 if (behind){
3882                         if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3883                                 endpar = behind->LastPhysicalPar()->Next();
3884                         else
3885                                 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3886                 }
3887                 else
3888                         endpar = behind;
3889     
3890                 tmppar = GetParFromID(undo->number_of_cursor_par);
3891                 RedoParagraphs(cursor, endpar); 
3892                 if (tmppar){
3893                         SetCursorIntern(tmppar, undo->cursor_pos);
3894                         UpdateCounters(cursor.row);
3895                 }
3896                 result = true;
3897                 delete undo;
3898         }
3899         FinishUndo();
3900         return result;
3901 }
3902
3903
3904 void LyXText::FinishUndo()
3905 {
3906         // makes sure the next operation will be stored
3907         undo_finished = true;
3908 }
3909
3910
3911 void LyXText::FreezeUndo()
3912 {
3913         // this is dangerous and for internal use only
3914         undo_frozen = true;
3915 }
3916
3917
3918 void LyXText::UnFreezeUndo()
3919 {
3920         // this is dangerous and for internal use only
3921         undo_frozen = false;
3922 }
3923
3924
3925 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3926                       LyXParagraph const * behind) const
3927 {
3928         if (!undo_frozen)
3929                 buffer->undostack.push(CreateUndo(kind, before, behind));
3930         buffer->redostack.clear();
3931 }
3932
3933
3934 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3935                       LyXParagraph const * behind)
3936 {
3937         buffer->redostack.push(CreateUndo(kind, before, behind));
3938 }
3939
3940
3941 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3942                           LyXParagraph const * behind) const
3943 {
3944         int before_number = -1;
3945         int behind_number = -1;
3946         if (before)
3947                 before_number = before->id();
3948         if (behind)
3949                 behind_number = behind->id();
3950         // Undo::EDIT  and Undo::FINISH are
3951         // always finished. (no overlapping there)
3952         // overlapping only with insert and delete inside one paragraph: 
3953         // Nobody wants all removed  character
3954         // appear one by one when undoing. 
3955         // EDIT is special since only layout information, not the
3956         // contents of a paragaph are stored.
3957         if (!undo_finished && kind != Undo::EDIT && 
3958             kind != Undo::FINISH){
3959                 // check wether storing is needed
3960                 if (!buffer->undostack.empty() && 
3961                     buffer->undostack.top()->kind == kind &&
3962                     buffer->undostack.top()->number_of_before_par ==  before_number &&
3963                     buffer->undostack.top()->number_of_behind_par ==  behind_number ){
3964                         // no undo needed
3965                         return 0;
3966                 }
3967         }
3968         // create a new Undo
3969         LyXParagraph * undopar;
3970         LyXParagraph * tmppar;
3971         LyXParagraph * tmppar2;
3972
3973         LyXParagraph * start = 0;
3974         LyXParagraph * end = 0;
3975   
3976         if (before)
3977                 start = before->next;
3978         else
3979                 start = FirstParagraph();
3980         if (behind)
3981                 end = behind->previous;
3982         else {
3983                 end = FirstParagraph();
3984                 while (end->next)
3985                         end = end->next;
3986         }
3987
3988         if (start && end
3989             && start != end->next
3990             && (before != behind || (!before && !behind))) {
3991                 tmppar = start;
3992                 tmppar2 = tmppar->Clone();
3993                 tmppar2->id(tmppar->id());
3994
3995                 // a memory optimization: Just store the layout information
3996                 // when only edit
3997                 if (kind == Undo::EDIT){
3998                         //tmppar2->text.clear();
3999                         tmppar2->clearContents();
4000                 }
4001
4002                 undopar = tmppar2;
4003   
4004                 while (tmppar != end && tmppar->next) {
4005                         tmppar = tmppar->next;
4006                         tmppar2->next = tmppar->Clone();
4007                         tmppar2->next->id(tmppar->id());
4008                         // a memory optimization: Just store the layout
4009                         // information when only edit
4010                         if (kind == Undo::EDIT){
4011                                 //tmppar2->next->text.clear();
4012                                 tmppar2->clearContents();
4013                         }
4014                         tmppar2->next->previous = tmppar2;
4015                         tmppar2 = tmppar2->next;
4016                 }
4017                 tmppar2->next = 0;
4018         } else
4019                 undopar = 0; // nothing to replace (undo of delete maybe)
4020   
4021         int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
4022         int cursor_pos =  cursor.par->PositionInParFromPos(cursor.pos);
4023
4024         Undo * undo = new Undo(kind, 
4025                                before_number, behind_number,  
4026                                cursor_par, cursor_pos, 
4027                                undopar);
4028   
4029         undo_finished = false;
4030         return undo;
4031 }
4032
4033
4034 void LyXText::SetCursorParUndo()
4035 {
4036         SetUndo(Undo::FINISH, 
4037                 cursor.par->ParFromPos(cursor.pos)->previous, 
4038                 cursor.par->ParFromPos(cursor.pos)->next); 
4039 }
4040
4041
4042 void LyXText::RemoveTableRow(LyXCursor * cur) const
4043 {
4044         int cell = -1;
4045         int cell_org = 0;
4046         int ocell = 0;
4047     
4048         // move to the previous row
4049         int cell_act = NumberOfCell(cur->par, cur->pos);
4050         if (cell < 0)
4051                 cell = cell_act;
4052         while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
4053                 cur->pos--;
4054         while (cur->pos && 
4055                !cur->par->table->IsFirstCell(cell_act)) {
4056                 cur->pos--;
4057                 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
4058                         cur->pos--;
4059                 --cell;
4060                 --cell_act;
4061         }
4062         // now we have to pay attention if the actual table is the
4063         //   main row of TableContRows and if yes to delete all of them
4064         if (!cell_org)
4065                 cell_org = cell;
4066         do {
4067                 ocell = cell;
4068                 // delete up to the next row
4069                 while (cur->pos < cur->par->Last() && 
4070                        (cell_act == ocell
4071                         || !cur->par->table->IsFirstCell(cell_act))) {
4072                         while (cur->pos < cur->par->Last() &&
4073                                !cur->par->IsNewline(cur->pos))
4074                                 cur->par->Erase(cur->pos);
4075                         ++cell;
4076                         ++cell_act;
4077                         if (cur->pos < cur->par->Last())
4078                                 cur->par->Erase(cur->pos);
4079                 }
4080                 if (cur->pos && cur->pos == cur->par->Last()) {
4081                         cur->pos--;
4082                         cur->par->Erase(cur->pos); // no newline at very end!
4083                 }
4084         } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
4085                  !cur->par->table->IsContRow(cell_org) &&
4086                  cur->par->table->IsContRow(cell));
4087         cur->par->table->DeleteRow(cell_org);
4088         return;
4089 }
4090
4091
4092 bool LyXText::IsEmptyTableCell() const
4093 {
4094         LyXParagraph::size_type pos = cursor.pos - 1;
4095         while (pos >= 0 && pos < cursor.par->Last()
4096                && !cursor.par->IsNewline(pos))
4097                 --pos;
4098         return cursor.par->IsNewline(pos + 1);
4099 }
4100
4101
4102 void LyXText::toggleAppendix(){
4103         LyXParagraph * par = cursor.par->FirstPhysicalPar();
4104         bool start = !par->start_of_appendix;
4105
4106         // ensure that we have only one start_of_appendix in this document
4107         LyXParagraph * tmp = FirstParagraph();
4108         for (; tmp; tmp = tmp->next)
4109                 tmp->start_of_appendix = 0;
4110         par->start_of_appendix = start;
4111
4112         // we can set the refreshing parameters now
4113         status = LyXText::NEED_MORE_REFRESH;
4114         refresh_y = 0;
4115         refresh_row = 0; // not needed for full update
4116         UpdateCounters(0);
4117         SetCursor(cursor.par, cursor.pos);
4118 }
4119