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