]> git.lyx.org Git - lyx.git/blob - src/text2.C
Various warnings fixed, added preliminary read of old table format and
[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);
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);
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 delet 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 && cursor.x < last_sel_cursor.x)) {
1026                 toggle_end_cursor = last_sel_cursor;
1027                 toggle_cursor = cursor;
1028         }
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.x == sel_end_cursor.x && 
1058             sel_start_cursor.y == sel_end_cursor.y)
1059                 selection = false;
1060 }
1061
1062
1063 void LyXText::ClearSelection() const
1064 {
1065         selection = false;
1066         mark_set = false;
1067 }
1068
1069
1070 void LyXText::CursorHome() const
1071 {
1072         SetCursor(cursor.par, cursor.row->pos);
1073 }
1074
1075
1076 void  LyXText::CursorEnd() const
1077 {
1078         if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1079                 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1080         else {
1081                 if (cursor.par->Last() && 
1082                     (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1083                      || cursor.par->IsNewline(RowLast(cursor.row))))
1084                         SetCursor(cursor.par, RowLast(cursor.row));
1085                 else
1086                         SetCursor(cursor.par, RowLast(cursor.row) + 1);
1087         }
1088         if (cursor.par->table) {
1089                 int cell = NumberOfCell(cursor.par, cursor.pos);
1090                 if (cursor.par->table->RowHasContRow(cell) &&
1091                     cursor.par->table->CellHasContRow(cell)<0) {
1092                         if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1093                                 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1094                         else {
1095                                 if (cursor.par->Last() && 
1096                                     (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1097                                      || cursor.par->IsNewline(RowLast(cursor.row))))
1098                                         SetCursor(cursor.par, RowLast(cursor.row));
1099                                 else
1100                                         SetCursor(cursor.par, RowLast(cursor.row) + 1);
1101                         }
1102                 }
1103         }
1104 }
1105
1106
1107 void  LyXText::CursorTop() const
1108 {
1109         while (cursor.par->Previous())
1110                 cursor.par = cursor.par->Previous();
1111         SetCursor(cursor.par, 0);
1112 }
1113
1114
1115 void  LyXText::CursorBottom() const
1116 {
1117         while (cursor.par->Next())
1118                 cursor.par = cursor.par->Next();
1119         SetCursor(cursor.par, cursor.par->Last());
1120 }
1121    
1122    
1123 /* returns a pointer to the row near the specified y-coordinate
1124 * (relative to the whole text). y is set to the real beginning
1125 * of this row */
1126 Row * LyXText::GetRowNearY(long & y) const
1127 {
1128         Row * tmprow = firstrow;
1129         long tmpy = 0;
1130
1131         while (tmprow->next && tmpy + tmprow->height <= y) {
1132                 tmpy += tmprow->height;
1133                 tmprow = tmprow->next;
1134         }
1135
1136         y = tmpy;   // return the real y
1137         return tmprow;
1138 }
1139
1140
1141 void LyXText::ToggleFree(LyXFont const & font, bool toggleall)
1142 {
1143         // If the mask is completely neutral, tell user
1144         if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1145                 // Could only happen with user style
1146                 owner_->owner()->getMiniBuffer()
1147                         ->Set(_("No font change defined. Use Character under"
1148                                   " the Layout menu to define font change."));
1149                 return;
1150         }
1151
1152         // Try implicit word selection
1153         // If there is a change in the language the implicit word selection 
1154         // is disabled.
1155         LyXCursor resetCursor = cursor;
1156         bool implicitSelection = (font.language() == ignore_language)
1157                 ? SelectWordWhenUnderCursor() : false;
1158
1159         // Set font
1160         SetFont(font, toggleall);
1161
1162         /* Implicit selections are cleared afterwards and cursor is set to the
1163            original position. */
1164         if (implicitSelection) {
1165                 ClearSelection();
1166                 cursor = resetCursor;
1167                 SetCursor( cursor.par, cursor.pos );
1168                 sel_cursor = cursor;
1169         }
1170 }
1171
1172
1173 LyXParagraph::size_type LyXText::BeginningOfMainBody(LyXParagraph * par) const
1174 {
1175         if (textclasslist.Style(buffer->params.textclass,
1176                                 par->GetLayout()).labeltype != LABEL_MANUAL)
1177                 return 0;
1178         else
1179                 return par->BeginningOfMainBody();
1180 }
1181
1182
1183 /* if there is a selection, reset every environment you can find
1184 * in the selection, otherwise just the environment you are in */ 
1185 void LyXText::MeltFootnoteEnvironment()
1186 {
1187         LyXParagraph * tmppar, * firsttmppar;
1188    
1189         ClearSelection();
1190    
1191         /* is is only allowed, if the cursor is IN an open footnote.
1192          * Otherwise it is too dangerous */ 
1193         if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1194                 return;
1195    
1196         SetUndo(Undo::FINISH, 
1197                 cursor.par->PreviousBeforeFootnote()->previous,
1198                 cursor.par->NextAfterFootnote()->next);
1199
1200         /* ok, move to the beginning of the footnote. */ 
1201         while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1202                 cursor.par = cursor.par->Previous();
1203    
1204         SetCursor(cursor.par, cursor.par->Last());
1205         /* this is just faster than using CursorLeft(); */ 
1206    
1207         firsttmppar = cursor.par->ParFromPos(cursor.pos);
1208         tmppar = firsttmppar;
1209         /* tmppar is now the paragraph right before the footnote */
1210
1211         bool first_footnote_par_is_not_empty = tmppar->next->size();
1212    
1213         while (tmppar->next
1214                && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1215                 tmppar = tmppar->next;   /* I use next instead of Next(),
1216                                           * because there cannot be any
1217                                           * footnotes in a footnote
1218                                           * environment */
1219                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1220       
1221                 /* remember the captions and empty paragraphs */
1222                 if ((textclasslist.Style(buffer->params.textclass,
1223                                          tmppar->GetLayout())
1224                      .labeltype == LABEL_SENSITIVE)
1225                     || !tmppar->Last())
1226                         tmppar->SetLayout(0);
1227         }
1228    
1229         // now we will paste the ex-footnote, if the layouts allow it
1230         // first restore the layout of the paragraph right behind
1231         // the footnote
1232         if (tmppar->next) 
1233                 tmppar->next->MakeSameLayout(cursor.par);
1234
1235         // first the end
1236         if ((!tmppar->GetLayout() && !tmppar->table)
1237             || (tmppar->Next()
1238                 && (!tmppar->Next()->Last()
1239                     || tmppar->Next()->HasSameLayout(tmppar)))) {
1240                 if (tmppar->Next()->Last()
1241                     && tmppar->Next()->IsLineSeparator(0))
1242                         tmppar->Next()->Erase(0);
1243                 tmppar->PasteParagraph();
1244         }
1245
1246         tmppar = tmppar->Next();  /* make sure tmppar cannot be touched
1247                                    * by the pasting of the beginning */
1248
1249         /* then the beginning */ 
1250         /* if there is no space between the text and the footnote, so we insert
1251          * a blank 
1252          * (only if the previous par and the footnotepar are not empty!) */
1253         if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1254             || firsttmppar->HasSameLayout(firsttmppar->next)) {
1255                 if (firsttmppar->size()
1256                     && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1257                     && first_footnote_par_is_not_empty) {
1258                         firsttmppar->next->InsertChar(0, ' ');
1259                 }
1260                 firsttmppar->PasteParagraph();
1261         }
1262    
1263         /* now redo the paragaphs */
1264         RedoParagraphs(cursor, tmppar);
1265    
1266         SetCursor(cursor.par, cursor.pos);
1267    
1268         /* sometimes it can happen, that there is a counter change */ 
1269         Row * row = cursor.row;
1270         while (row->next && row->par != tmppar && row->next->par != tmppar)
1271                 row = row->next;
1272         UpdateCounters(row);
1273    
1274    
1275         ClearSelection();
1276 }
1277
1278
1279 /* the DTP switches for paragraphs. LyX will store them in the 
1280 * first physicla paragraph. When a paragraph is broken, the top settings 
1281 * rest, the bottom settings are given to the new one. So I can make shure, 
1282 * they do not duplicate themself and you cannnot make dirty things with 
1283 * them!  */ 
1284
1285 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1286                            bool pagebreak_top, bool pagebreak_bottom,
1287                            VSpace const & space_top,
1288                            VSpace const & space_bottom,
1289                            LyXAlignment align, 
1290                            string labelwidthstring,
1291                            bool noindent) 
1292 {
1293         LyXCursor tmpcursor = cursor;
1294         if (!selection) {
1295                 sel_start_cursor = cursor;
1296                 sel_end_cursor = cursor;
1297         }
1298
1299         // make sure that the depth behind the selection are restored, too
1300         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1301         LyXParagraph * undoendpar = endpar;
1302
1303         if (endpar && endpar->GetDepth()) {
1304                 while (endpar && endpar->GetDepth()) {
1305                         endpar = endpar->LastPhysicalPar()->Next();
1306                         undoendpar = endpar;
1307                 }
1308         }
1309         else if (endpar) {
1310                 endpar = endpar->Next(); // because of parindents etc.
1311         }
1312    
1313         SetUndo(Undo::EDIT, 
1314                 sel_start_cursor
1315                 .par->ParFromPos(sel_start_cursor.pos)->previous, 
1316                 undoendpar);
1317
1318         
1319         LyXParagraph * tmppar = sel_end_cursor.par;
1320         while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1321                 SetCursor(tmppar->FirstPhysicalPar(), 0);
1322                 status = LyXText::NEED_MORE_REFRESH;
1323                 refresh_row = cursor.row;
1324                 refresh_y = cursor.y - cursor.row->baseline;
1325                 if (cursor.par->footnoteflag ==
1326                     sel_start_cursor.par->footnoteflag) {
1327                         cursor.par->line_top = line_top;
1328                         cursor.par->line_bottom = line_bottom;
1329                         cursor.par->pagebreak_top = pagebreak_top;
1330                         cursor.par->pagebreak_bottom = pagebreak_bottom;
1331                         cursor.par->added_space_top = space_top;
1332                         cursor.par->added_space_bottom = space_bottom;
1333                         // does the layout allow the new alignment?
1334                         if (align == LYX_ALIGN_LAYOUT)
1335                                 align = textclasslist
1336                                         .Style(buffer->params.textclass,
1337                                                cursor.par->GetLayout()).align;
1338                         if (align & textclasslist
1339                             .Style(buffer->params.textclass,
1340                                    cursor.par->GetLayout()).alignpossible) {
1341                                 if (align == textclasslist
1342                                     .Style(buffer->params.textclass,
1343                                            cursor.par->GetLayout()).align)
1344                                         cursor.par->align = LYX_ALIGN_LAYOUT;
1345                                 else
1346                                         cursor.par->align = align;
1347                         }
1348                         cursor.par->SetLabelWidthString(labelwidthstring);
1349                         cursor.par->noindent = noindent;
1350                 }
1351                 
1352                 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1353         }
1354         
1355         RedoParagraphs(sel_start_cursor, endpar);
1356         
1357         ClearSelection();
1358         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1359         sel_cursor = cursor;
1360         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1361         SetSelection();
1362         SetCursor(tmpcursor.par, tmpcursor.pos);
1363 }
1364
1365
1366 void LyXText::SetParagraphExtraOpt(int type,
1367                                    char const * width,
1368                                    char const * widthp,
1369                                    int alignment, bool hfill,
1370                                    bool start_minipage)
1371 {
1372         LyXCursor tmpcursor = cursor;
1373         LyXParagraph * tmppar;
1374         if (!selection) {
1375                 sel_start_cursor = cursor;
1376                 sel_end_cursor = cursor;
1377         }
1378
1379         // make sure that the depth behind the selection are restored, too
1380         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1381         LyXParagraph * undoendpar = endpar;
1382
1383         if (endpar && endpar->GetDepth()) {
1384                 while (endpar && endpar->GetDepth()) {
1385                         endpar = endpar->LastPhysicalPar()->Next();
1386                         undoendpar = endpar;
1387                 }
1388         }
1389         else if (endpar) {
1390                 endpar = endpar->Next(); // because of parindents etc.
1391         }
1392    
1393         SetUndo(Undo::EDIT, 
1394                 sel_start_cursor
1395                 .par->ParFromPos(sel_start_cursor.pos)->previous, 
1396                 undoendpar);
1397         
1398         tmppar = sel_end_cursor.par;
1399         while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1400                 SetCursor(tmppar->FirstPhysicalPar(), 0);
1401                 status = LyXText::NEED_MORE_REFRESH;
1402                 refresh_row = cursor.row;
1403                 refresh_y = cursor.y - cursor.row->baseline;
1404                 if (cursor.par->footnoteflag ==
1405                     sel_start_cursor.par->footnoteflag) {
1406                         if (type == LyXParagraph::PEXTRA_NONE) {
1407                                 if (cursor.par->pextra_type != LyXParagraph::PEXTRA_NONE) {
1408                                         cursor.par->UnsetPExtraType();
1409                                         cursor.par->pextra_type = LyXParagraph::PEXTRA_NONE;
1410                                 }
1411                         } else {
1412                                 cursor.par->SetPExtraType(type, width, widthp);
1413                                 cursor.par->pextra_hfill = hfill;
1414                                 cursor.par->pextra_start_minipage = start_minipage;
1415                                 cursor.par->pextra_alignment = alignment;
1416                         }
1417                 }
1418                 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1419         }
1420         RedoParagraphs(sel_start_cursor, endpar);
1421         ClearSelection();
1422         SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1423         sel_cursor = cursor;
1424         SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1425         SetSelection();
1426         SetCursor(tmpcursor.par, tmpcursor.pos);
1427 }
1428
1429
1430 char loweralphaCounter(int n)
1431 {
1432         if (n < 1 || n > 26)
1433                 return '?';
1434         else
1435                 return 'a' + n - 1;
1436 }
1437
1438 char alphaCounter(int n)
1439 {
1440         if (n < 1 || n > 26)
1441                 return '?';
1442         else
1443                 return 'A' + n - 1;
1444 }
1445
1446 char hebrewCounter(int n)
1447 {
1448         static const char hebrew[22] = {
1449                 'à', 'á', 'â', 'ã', 'ä', 'Ã¥', 'æ', 'ç', 'è',
1450                 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö', 
1451                 '÷', 'ø', 'ù', 'ú'
1452         };
1453         if (n < 1 || n > 22)
1454                 return '?';
1455         else
1456                 return hebrew[n-1];
1457 }
1458
1459 static char const * romanCounter(int n)
1460 {
1461         static char const * roman[20] = {
1462                 "i",   "ii",  "iii", "iv", "v",
1463                 "vi",  "vii", "viii", "ix", "x",
1464                 "xi",  "xii", "xiii", "xiv", "xv",
1465                 "xvi", "xvii", "xviii", "xix", "xx"
1466         };
1467         if (n < 1 || n > 20)
1468                 return "??";
1469         else
1470                 return roman[n-1];
1471 }
1472
1473 // set the counter of a paragraph. This includes the labels
1474 void LyXText::SetCounter(LyXParagraph * par) const
1475 {
1476         // this is only relevant for the beginning of paragraph
1477         par = par->FirstPhysicalPar();
1478
1479         LyXLayout const & layout =
1480                 textclasslist.Style(buffer->params.textclass, 
1481                                     par->GetLayout());
1482
1483         LyXTextClass const & textclass =
1484                 textclasslist.TextClass(buffer->params.textclass);
1485
1486         /* copy the prev-counters to this one, unless this is the start of a 
1487            footnote or of a bibliography or the very first paragraph */
1488         if (par->Previous()
1489             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1490                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1491                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1492             && !(textclasslist.Style(buffer->params.textclass,
1493                                 par->Previous()->GetLayout()
1494                                 ).labeltype != LABEL_BIBLIO
1495                  && layout.labeltype == LABEL_BIBLIO)) {
1496                 for (int i = 0; i < 10; ++i) {
1497                         par->setCounter(i, par->Previous()->GetFirstCounter(i));
1498                 }
1499                 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1500                 if (!par->appendix && par->start_of_appendix){
1501                   par->appendix = true;
1502                   for (int i = 0; i < 10; ++i) {
1503                     par->setCounter(i, 0);
1504                   }  
1505                 }
1506                 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1507                 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1508         }
1509         else {
1510                 for (int i = 0; i < 10; ++i) {
1511                         par->setCounter(i, 0);
1512                 }  
1513                 par->appendix = par->start_of_appendix;
1514                 par->enumdepth = 0;
1515                 par->itemdepth = 0;
1516         }
1517
1518         // if this is an open marginnote and this is the first
1519         // entry in the marginnote and the enclosing
1520         // environment is an enum/item then correct for the
1521         // LaTeX behaviour (ARRae)
1522         if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1523            && par->footnotekind == LyXParagraph::MARGIN
1524            && par->Previous()
1525            && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1526            && (par->PreviousBeforeFootnote()
1527                && textclasslist.Style(buffer->params.textclass,
1528                                  par->PreviousBeforeFootnote()->GetLayout()
1529                                  ).labeltype >= LABEL_COUNTER_ENUMI)) {
1530                 // Any itemize or enumerate environment in a marginnote
1531                 // that is embedded in an itemize or enumerate
1532                 // paragraph is seen by LaTeX as being at a deeper
1533                 // level within that enclosing itemization/enumeration
1534                 // even if there is a "standard" layout at the start of
1535                 // the marginnote.
1536                 par->enumdepth++;
1537                 par->itemdepth++;
1538         }
1539
1540         /* Maybe we have to increment the enumeration depth.
1541          * BUT, enumeration in a footnote is considered in isolation from its
1542          *      surrounding paragraph so don't increment if this is the
1543          *      first line of the footnote
1544          * AND, bibliographies can't have their depth changed ie. they
1545          *      are always of depth 0
1546          */
1547         if (par->Previous()
1548             && par->Previous()->GetDepth() < par->GetDepth()
1549             && textclasslist.Style(buffer->params.textclass,
1550                               par->Previous()->GetLayout()
1551                              ).labeltype == LABEL_COUNTER_ENUMI
1552             && par->enumdepth < 3
1553             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1554                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1555                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1556             && layout.labeltype != LABEL_BIBLIO) {
1557                 par->enumdepth++;
1558         }
1559
1560         /* Maybe we have to decrement the enumeration depth, see note above */
1561         if (par->Previous()
1562             && par->Previous()->GetDepth() > par->GetDepth()
1563             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1564                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1565                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1566             && layout.labeltype != LABEL_BIBLIO) {
1567                 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1568                 par->setCounter(6 + par->enumdepth,
1569                         par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1570                 /* reset the counters.
1571                  * A depth change is like a breaking layout
1572                  */
1573                 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1574                         par->setCounter(i, 0);
1575         }
1576    
1577         if (!par->labelstring.empty()) {
1578                 par->labelstring.erase();
1579         }
1580    
1581         if (layout.margintype == MARGIN_MANUAL) {
1582                 if (par->labelwidthstring.empty()) {
1583                         par->SetLabelWidthString(layout.labelstring());
1584                 }
1585         } else {
1586                 par->SetLabelWidthString(string());
1587         }
1588    
1589         /* is it a layout that has an automatic label ? */ 
1590         if (layout.labeltype >=  LABEL_FIRST_COUNTER) {
1591       
1592                 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1593                 if (i >= 0 && i<= buffer->params.secnumdepth) {
1594                         par->incCounter(i);     // increment the counter  
1595          
1596                         // Is there a label? Useful for Chapter layout
1597                         if (!par->appendix){
1598                                 if (!layout.labelstring().empty())
1599                                         par->labelstring = layout.labelstring();
1600                                 else
1601                                         par->labelstring.erase();
1602                         } else {
1603                                 if (!layout.labelstring_appendix().empty())
1604                                         par->labelstring = layout.labelstring_appendix();
1605                                 else
1606                                         par->labelstring.erase();
1607                         }
1608
1609 #ifdef HAVE_SSTREAM
1610                         std::ostringstream s;
1611 #else
1612                         ostrstream s;
1613 #endif
1614                         if (!par->appendix) {
1615                                 switch (2 * LABEL_FIRST_COUNTER -
1616                                         textclass.maxcounter() + i) {
1617                                 case LABEL_COUNTER_CHAPTER:
1618                                         s << par->getCounter(i);
1619                                         break;
1620                                 case LABEL_COUNTER_SECTION:
1621                                         s << par->getCounter(i - 1) << '.'
1622                                            << par->getCounter(i);
1623                                         break;
1624                                 case LABEL_COUNTER_SUBSECTION:
1625                                         s << par->getCounter(i - 2) << '.'
1626                                           << par->getCounter(i - 1) << '.'
1627                                           << par->getCounter(i);
1628                                         break;
1629                                 case LABEL_COUNTER_SUBSUBSECTION:
1630                                         s << par->getCounter(i - 3) << '.'
1631                                           << par->getCounter(i - 2) << '.'
1632                                           << par->getCounter(i - 1) << '.'
1633                                           << par->getCounter(i);
1634                                         
1635                                         break;
1636                                 case LABEL_COUNTER_PARAGRAPH:
1637                                         s << par->getCounter(i - 4) << '.'
1638                                           << par->getCounter(i - 3) << '.'
1639                                           << par->getCounter(i - 2) << '.'
1640                                           << par->getCounter(i - 1) << '.'
1641                                           << par->getCounter(i);
1642                                         break;
1643                                 case LABEL_COUNTER_SUBPARAGRAPH:
1644                                         s << par->getCounter(i - 5) << '.'
1645                                           << par->getCounter(i - 4) << '.'
1646                                           << par->getCounter(i - 3) << '.'
1647                                           << par->getCounter(i - 2) << '.'
1648                                           << par->getCounter(i - 1) << '.'
1649                                           << par->getCounter(i);
1650
1651                                         break;
1652                                 default:
1653                                         s << par->getCounter(i) << '.';
1654                                         break;
1655                                 }
1656                         } else { // appendix
1657                                 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1658                                 case LABEL_COUNTER_CHAPTER:
1659                                         if (par->isRightToLeftPar())
1660                                                 s << hebrewCounter(par->getCounter(i));
1661                                         else
1662                                                 s << alphaCounter(par->getCounter(i));
1663                                         break;
1664                                 case LABEL_COUNTER_SECTION:
1665                                         if (par->isRightToLeftPar())
1666                                                 s << hebrewCounter(par->getCounter(i - 1));
1667                                         else
1668                                                 s << alphaCounter(par->getCounter(i - 1));
1669
1670                                         s << '.'
1671                                           << par->getCounter(i);
1672
1673                                         break;
1674                                 case LABEL_COUNTER_SUBSECTION:
1675                                         if (par->isRightToLeftPar())
1676                                                 s << hebrewCounter(par->getCounter(i - 2));
1677                                         else
1678                                                 s << alphaCounter(par->getCounter(i - 2));
1679
1680                                         s << '.'
1681                                           << par->getCounter(i-1) << '.'
1682                                           << par->getCounter(i);
1683
1684                                         break;
1685                                 case LABEL_COUNTER_SUBSUBSECTION:
1686                                         if (par->isRightToLeftPar())
1687                                                 s << hebrewCounter(par->getCounter(i-3));
1688                                         else
1689                                                 s << alphaCounter(par->getCounter(i-3));
1690
1691                                         s << '.'
1692                                           << par->getCounter(i-2) << '.'
1693                                           << par->getCounter(i-1) << '.'
1694                                           << par->getCounter(i);
1695
1696                                         break;
1697                                 case LABEL_COUNTER_PARAGRAPH:
1698                                         if (par->isRightToLeftPar())
1699                                                 s << hebrewCounter(par->getCounter(i-4));
1700                                         else
1701                                                 s << alphaCounter(par->getCounter(i-4));
1702
1703                                         s << '.'
1704                                           << par->getCounter(i-3) << '.'
1705                                           << par->getCounter(i-2) << '.'
1706                                           << par->getCounter(i-1) << '.'
1707                                           << par->getCounter(i);
1708
1709                                         break;
1710                                 case LABEL_COUNTER_SUBPARAGRAPH:
1711                                         if (par->isRightToLeftPar())
1712                                                 s << hebrewCounter(par->getCounter(i-5));
1713                                         else
1714                                                 s << alphaCounter(par->getCounter(i-5));
1715
1716                                         s << '.'
1717                                           << par->getCounter(i-4) << '.'
1718                                           << par->getCounter(i-3) << '.'
1719                                           << par->getCounter(i-2) << '.'
1720                                           << par->getCounter(i-1) << '.'
1721                                           << par->getCounter(i);
1722
1723                                         break;
1724                                 default:
1725                                         // Can this ever be reached? And in the
1726                                         // case it is, how can this be correct?
1727                                         // (Lgb)
1728                                         s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1729                                         
1730                                         break;
1731                                 }
1732                         }
1733 #ifdef HAVE_SSTREAM
1734                         par->labelstring += s.str().c_str();
1735                         // We really want to remove the c_str as soon as
1736                         // possible...
1737 #else
1738                         s << '\0';
1739                         char * tmps = s.str();
1740                         par->labelstring += tmps;
1741                         delete [] tmps;
1742 #endif
1743                         
1744                         for (i++; i < 10; ++i) {
1745                                 // reset the following counters
1746                                 par->setCounter(i, 0);
1747                         }
1748                 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1749                         for (i++; i < 10; ++i) {
1750                                 // reset the following counters
1751                                 par->setCounter(i, 0);
1752                         }
1753                 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1754                         par->incCounter(i + par->enumdepth);
1755                         int number = par->getCounter(i + par->enumdepth);
1756
1757 #ifdef HAVE_SSTREAM
1758                         std::ostringstream s;
1759 #else
1760                         ostrstream s;
1761 #endif
1762                         switch (par->enumdepth) {
1763                         case 1:
1764                                 if (par->isRightToLeftPar())
1765                                         s << '('
1766                                           << hebrewCounter(number)
1767                                           << ')';
1768                                 else
1769                                         s << '('
1770                                           << loweralphaCounter(number)
1771                                           << ')';
1772                                 break;
1773                         case 2:
1774                                 if (par->isRightToLeftPar())
1775                                         s << '.' << romanCounter(number);
1776                                 else
1777                                         s << romanCounter(number) << '.';
1778                                 break;
1779                         case 3:
1780                                 if (par->isRightToLeftPar())
1781                                         s << '.'
1782                                           << alphaCounter(number);
1783                                 else
1784                                         s << alphaCounter(number)
1785                                           << '.';
1786                                 break;
1787                         default:
1788                                 if (par->isRightToLeftPar())
1789                                         s << '.' << number;
1790                                 else
1791                                         s << number << '.';
1792                                 break;
1793                         }
1794 #ifdef HAVE_SSTREAM
1795                         par->labelstring = s.str().c_str();
1796                         // we really want to get rid of that c_str()
1797 #else
1798                         s << '\0';
1799                         char * tmps = s.str();
1800                         par->labelstring = tmps;
1801                         delete [] tmps;
1802 #endif
1803
1804                         for (i += par->enumdepth + 1; i < 10; ++i)
1805                                 par->setCounter(i, 0);  /* reset the following counters  */
1806          
1807                 } 
1808         } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1809                 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1810                 par->incCounter(i);
1811                 int number = par->getCounter(i);
1812                 if (!par->bibkey)
1813                         par->bibkey = new InsetBibKey();
1814                 par->bibkey->setCounter(number);
1815                 par->labelstring = layout.labelstring();
1816                 
1817                 // In biblio should't be following counters but...
1818         } else {
1819                 string s = layout.labelstring();
1820                 
1821                 // the caption hack:
1822       
1823                 if (layout.labeltype == LABEL_SENSITIVE) {
1824                         if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1825                             && (par->footnotekind == LyXParagraph::FIG
1826                                 || par->footnotekind == LyXParagraph::WIDE_FIG))
1827                                 s = (par->getParLanguage()->lang == "hebrew")
1828                                         ? ":øåéà" : "Figure:";
1829                         else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1830                                  && (par->footnotekind == LyXParagraph::TAB
1831                                      || par->footnotekind == LyXParagraph::WIDE_TAB))
1832                                 s = (par->getParLanguage()->lang == "hebrew")
1833                                         ? ":äìáè" : "Table:";
1834                         else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1835                                  && par->footnotekind == LyXParagraph::ALGORITHM)
1836                                 s = (par->getParLanguage()->lang == "hebrew")
1837                                         ? ":íúéøåâìà" : "Algorithm:";
1838                         else {
1839                                 /* par->SetLayout(0); 
1840                                    s = layout->labelstring;  */
1841                                 s = (par->getParLanguage()->lang == "hebrew")
1842                                         ? " :úåòîùî Ã¸Ã±Ã§" : "Senseless: ";
1843                         }
1844                 }
1845                 par->labelstring = s;
1846                 
1847                 /* reset the enumeration counter. They are always resetted
1848                  * when there is any other layout between */ 
1849                 for (int i = 6 + par->enumdepth; i < 10; ++i)
1850                         par->setCounter(i, 0);
1851         }
1852 }
1853
1854
1855 /* Updates all counters BEHIND the row. Changed paragraphs
1856 * with a dynamic left margin will be rebroken. */ 
1857 void LyXText::UpdateCounters(Row * row) const
1858 {
1859         LyXParagraph * par;
1860         if (!row) {
1861                 row = firstrow;
1862                 par = row->par;
1863         }
1864         else {
1865                 if (row->par->next
1866                     && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1867                         par = row->par->LastPhysicalPar()->Next();
1868                 } else {
1869                         par = row->par->next;
1870                 }
1871         }
1872
1873         while (par) {
1874                 while (row->par != par)
1875                         row = row->next;
1876                 
1877                 SetCounter(par);
1878                 
1879                 /* now  check for the headline layouts. remember that they
1880                  * have a dynamic left margin */ 
1881                 if (!par->IsDummy()
1882                     && ( textclasslist.Style(buffer->params.textclass,
1883                                              par->layout).margintype == MARGIN_DYNAMIC
1884                          || textclasslist.Style(buffer->params.textclass,
1885                                                 par->layout).labeltype == LABEL_SENSITIVE)
1886                         ) {
1887          
1888                         /* Rebreak the paragraph */ 
1889                         RemoveParagraph(row);
1890                         AppendParagraph(row);
1891        
1892                         /* think about the damned open footnotes! */ 
1893                         while (par->Next() &&
1894                                (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1895                                 || par->Next()->IsDummy())){
1896                                 par = par->Next();
1897                                 if (par->IsDummy()) {
1898                                         while (row->par != par)
1899                                                 row = row->next;
1900                                         RemoveParagraph(row);
1901                                         AppendParagraph(row);
1902                                 }
1903                         }
1904                 }
1905      
1906                 par = par->LastPhysicalPar()->Next();
1907      
1908         }
1909 }
1910
1911
1912 /* insets an inset. */ 
1913 void LyXText::InsertInset(Inset *inset)
1914 {
1915         if (!cursor.par->InsertInsetAllowed(inset))
1916                 return;
1917         SetUndo(Undo::INSERT, 
1918                 cursor.par->ParFromPos(cursor.pos)->previous, 
1919                 cursor.par->ParFromPos(cursor.pos)->next);
1920         cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1921         cursor.par->InsertInset(cursor.pos, inset);
1922         InsertChar(LyXParagraph::META_INSET);  /* just to rebreak and refresh correctly.
1923                                       * The character will not be inserted a
1924                                       * second time */
1925 }
1926
1927
1928 #ifdef USE_OLD_CUT_AND_PASTE
1929 // this is for the simple cut and paste mechanism
1930 static LyXParagraph * simple_cut_buffer = 0;
1931 static char simple_cut_buffer_textclass = 0;
1932
1933 void DeleteSimpleCutBuffer()
1934 {
1935         if (!simple_cut_buffer)
1936                 return;
1937         LyXParagraph * tmppar;
1938
1939         while (simple_cut_buffer) {
1940                 tmppar =  simple_cut_buffer;
1941                 simple_cut_buffer = simple_cut_buffer->next;
1942                 delete tmppar;
1943         }
1944         simple_cut_buffer = 0;
1945 }
1946 #endif
1947
1948 void LyXText::copyEnvironmentType()
1949 {
1950         copylayouttype = cursor.par->GetLayout();
1951 }
1952
1953
1954 void LyXText::pasteEnvironmentType()
1955 {
1956         SetLayout(copylayouttype);
1957 }
1958
1959 #ifdef USE_OLD_CUT_AND_PASTE
1960 void LyXText::CutSelection(bool doclear)
1961 {
1962         // This doesn't make sense, if there is no selection
1963         if (!selection)
1964                 return;
1965    
1966         // OK, we have a selection. This is always between sel_start_cursor
1967         // and sel_end cursor
1968         LyXParagraph * tmppar;
1969    
1970         // Check whether there are half footnotes in the selection
1971         if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1972             || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1973                 tmppar = sel_start_cursor.par;
1974                 while (tmppar != sel_end_cursor.par){
1975                         if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
1976                                 WriteAlert(_("Impossible operation"),
1977                                            _("Don't know what to do with half floats."),
1978                                            _("sorry."));
1979                                 return;
1980                         }
1981                         tmppar = tmppar->Next();
1982                 }
1983         }
1984
1985         /* table stuff -- begin */
1986         if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
1987                 if ( sel_start_cursor.par != sel_end_cursor.par) {
1988                         WriteAlert(_("Impossible operation"),
1989                                    _("Don't know what to do with half tables."),
1990                                    _("sorry."));
1991                         return;
1992                 }
1993                 sel_start_cursor.par->table->Reinit();
1994         }
1995         /* table stuff -- end */
1996
1997         // make sure that the depth behind the selection are restored, too
1998         LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1999         LyXParagraph * undoendpar = endpar;
2000
2001         if (endpar && endpar->GetDepth()) {
2002                 while (endpar && endpar->GetDepth()) {
2003                         endpar = endpar->LastPhysicalPar()->Next();
2004                         undoendpar = endpar;
2005                 }
2006         } else if (endpar) {
2007                 endpar = endpar->Next(); // because of parindents etc.
2008         }
2009    
2010         SetUndo(Undo::DELETE, 
2011                 sel_start_cursor
2012                 .par->ParFromPos(sel_start_cursor.pos)->previous, 
2013                 undoendpar);
2014    
2015         // clear the simple_cut_buffer
2016         DeleteSimpleCutBuffer();
2017    
2018         // set the textclass
2019         simple_cut_buffer_textclass = buffer->params.textclass;
2020
2021 #ifdef WITH_WARNINGS
2022 #warning Asger: Make cut more intelligent here.
2023 #endif
2024         /* 
2025            White paper for "intelligent" cutting:
2026            
2027            Example: "This is our text."
2028            Using " our " as selection, cutting will give "This istext.".
2029            Using "our" as selection, cutting will give "This is text.".
2030            Using " our" as selection, cutting will give "This is text.".
2031            Using "our " as selection, cutting will give "This is text.".
2032            
2033            All those four selections will (however) paste identically:
2034            Pasting with the cursor right after the "is" will give the
2035            original text with all four selections.
2036            
2037            The rationale is to be intelligent such that words are copied,
2038            cut and pasted in a functional manner.
2039            
2040            This is not implemented yet. (Asger)
2041
2042            The changes below sees to do a lot of what you want. However
2043            I have not verified that all cases work as they should:
2044                      - cut in single row
2045                      - cut in multiple row
2046                      - cut with insets
2047                      - cut across footnotes and paragraph
2048            My simplistic tests show that the idea are basically sound but
2049            there are some items to fix up...we only need to find them
2050            first.
2051
2052            As do redo Asger's example above (with | beeing the cursor in the
2053            result after cutting.):
2054            
2055            Example: "This is our text."
2056            Using " our " as selection, cutting will give "This is|text.".
2057            Using "our"   as selection, cutting will give "This is | text.".
2058            Using " our"  as selection, cutting will give "This is| text.".
2059            Using "our "  as selection, cutting will give "This is |text.".
2060
2061            (Lgb)
2062         */
2063
2064         // there are two cases: cut only within one paragraph or
2065         // more than one paragraph
2066    
2067         if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
2068             == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2069                 // only within one paragraph
2070                 simple_cut_buffer = new LyXParagraph;
2071                 LyXParagraph::size_type i =
2072                         sel_start_cursor.pos;
2073                 for (; i < sel_end_cursor.pos; ++i) {
2074                         /* table stuff -- begin */
2075                         if (sel_start_cursor.par->table
2076                             && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)) {
2077                                 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2078                                 sel_start_cursor.pos++;
2079                         } else {
2080                                 /* table stuff -- end */
2081                                 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2082                                 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2083                         }
2084                         simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
2085                 }
2086                 endpar = sel_end_cursor.par->Next();
2087         } else {
2088                 // cut more than one paragraph
2089    
2090                 sel_end_cursor.par
2091                         ->BreakParagraphConservative(sel_end_cursor.pos);
2092                 sel_end_cursor.par = sel_end_cursor.par->Next();
2093                 sel_end_cursor.pos = 0;
2094    
2095                 cursor = sel_end_cursor;
2096
2097                 sel_start_cursor.par
2098                         ->BreakParagraphConservative(sel_start_cursor.pos);
2099                 // store the endparagraph for redoing later
2100                 endpar = sel_end_cursor.par->Next(); /* needed because
2101                                                         the sel_end_
2102                                                         cursor.par
2103                                                         will be pasted! */
2104    
2105                 // store the selection
2106                 simple_cut_buffer = sel_start_cursor.par
2107                         ->ParFromPos(sel_start_cursor.pos)->next;
2108                 simple_cut_buffer->previous = 0;
2109                 sel_end_cursor.par->previous->next = 0;
2110
2111                 // cut the selection
2112                 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next 
2113                         = sel_end_cursor.par;
2114    
2115                 sel_end_cursor.par->previous 
2116                         = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2117
2118                 // care about footnotes
2119                 if (simple_cut_buffer->footnoteflag) {
2120                         LyXParagraph * tmppar = simple_cut_buffer;
2121                         while (tmppar){
2122                                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2123                                 tmppar = tmppar->next;
2124                         }
2125                 }
2126
2127                 // the cut selection should begin with standard layout
2128                 simple_cut_buffer->Clear(); 
2129    
2130                 // paste the paragraphs again, if possible
2131                 if (doclear)
2132                         sel_start_cursor.par->Next()->ClearParagraph();
2133                 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
2134                     || 
2135                     !sel_start_cursor.par->Next()->Last())
2136                         sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
2137         }
2138
2139         // sometimes necessary
2140         if (doclear)
2141                 sel_start_cursor.par->ClearParagraph();
2142
2143         RedoParagraphs(sel_start_cursor, endpar);
2144    
2145         ClearSelection();
2146         cursor = sel_start_cursor;
2147         SetCursor(cursor.par, cursor.pos);
2148         sel_cursor = cursor;
2149         UpdateCounters(cursor.row);
2150 }
2151
2152 #else ///////////////////////////////////////////////////////////////////
2153
2154 void LyXText::CutSelection(bool doclear)
2155 {
2156     // This doesn't make sense, if there is no selection
2157     if (!selection)
2158         return;
2159    
2160     // OK, we have a selection. This is always between sel_start_cursor
2161     // and sel_end cursor
2162     LyXParagraph * tmppar;
2163     
2164     // Check whether there are half footnotes in the selection
2165     if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2166         || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2167         tmppar = sel_start_cursor.par;
2168         while (tmppar != sel_end_cursor.par){
2169             if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
2170                 WriteAlert(_("Impossible operation"),
2171                            _("Don't know what to do with half floats."),
2172                            _("sorry."));
2173                 return;
2174                         }
2175             tmppar = tmppar->Next();
2176         }
2177     }
2178     
2179     /* table stuff -- begin */
2180     if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
2181         if ( sel_start_cursor.par != sel_end_cursor.par) {
2182             WriteAlert(_("Impossible operation"),
2183                        _("Don't know what to do with half tables."),
2184                        _("sorry."));
2185             return;
2186         }
2187         sel_start_cursor.par->table->Reinit();
2188     }
2189     /* table stuff -- end */
2190     
2191     // make sure that the depth behind the selection are restored, too
2192     LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
2193     LyXParagraph * undoendpar = endpar;
2194     
2195     if (endpar && endpar->GetDepth()) {
2196         while (endpar && endpar->GetDepth()) {
2197             endpar = endpar->LastPhysicalPar()->Next();
2198             undoendpar = endpar;
2199         }
2200     } else if (endpar) {
2201         endpar = endpar->Next(); // because of parindents etc.
2202     }
2203     
2204     SetUndo(Undo::DELETE, sel_start_cursor
2205             .par->ParFromPos(sel_start_cursor.pos)->previous, undoendpar);
2206     
2207     CutAndPaste cap;
2208
2209     // there are two cases: cut only within one paragraph or
2210     // more than one paragraph
2211     if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
2212         == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2213         // only within one paragraph
2214         endpar = sel_start_cursor.par;
2215         cap.cutSelection(sel_start_cursor.par, &endpar,
2216                          sel_start_cursor.pos, sel_end_cursor.pos,
2217                          buffer->params.textclass, doclear);
2218     } else {
2219         endpar = sel_end_cursor.par;
2220
2221         cap.cutSelection(sel_start_cursor.par, &endpar,
2222                          sel_start_cursor.pos, sel_end_cursor.pos,
2223                          buffer->params.textclass, doclear);
2224         cursor.par = sel_end_cursor.par = endpar;
2225         cursor.pos = sel_end_cursor.pos;
2226     }
2227     endpar = endpar->Next();
2228
2229     // sometimes necessary
2230     if (doclear)
2231         sel_start_cursor.par->ClearParagraph();
2232
2233     RedoParagraphs(sel_start_cursor, endpar);
2234    
2235     ClearSelection();
2236     cursor = sel_start_cursor;
2237     SetCursor(cursor.par, cursor.pos);
2238     sel_cursor = cursor;
2239     UpdateCounters(cursor.row);
2240 }
2241 #endif
2242     
2243 #ifdef USE_OLD_CUT_AND_PASTE
2244 void LyXText::CopySelection()
2245 {
2246         // this doesnt make sense, if there is no selection
2247         if (!selection)
2248                 return;
2249
2250         // ok we have a selection. This is always between sel_start_cursor
2251         // and sel_end cursor
2252         LyXParagraph * tmppar;
2253    
2254         /* check wether there are half footnotes in the selection */
2255         if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2256             || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2257                 tmppar = sel_start_cursor.par;
2258                 while (tmppar != sel_end_cursor.par) {
2259                         if (tmppar->footnoteflag !=
2260                             sel_end_cursor.par->footnoteflag) {
2261                                 WriteAlert(_("Impossible operation"),
2262                                            _("Don't know what to do"
2263                                              " with half floats."),
2264                                            _("sorry."));
2265                                 return;
2266                         }
2267                         tmppar = tmppar->Next();
2268                 }
2269         }
2270
2271         /* table stuff -- begin */
2272         if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2273                 if ( sel_start_cursor.par != sel_end_cursor.par){
2274                         WriteAlert(_("Impossible operation"),
2275                                    _("Don't know what to do with half tables."),
2276                                    _("sorry."));
2277                         return;
2278                 }
2279         }
2280         /* table stuff -- end */
2281    
2282         // delete the simple_cut_buffer
2283         DeleteSimpleCutBuffer();
2284
2285         // set the textclass
2286         simple_cut_buffer_textclass = buffer->params.textclass;
2287
2288         // copy behind a space if there is one
2289         while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2290                && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2291                && (sel_start_cursor.par != sel_end_cursor.par
2292                    || sel_start_cursor.pos < sel_end_cursor.pos))
2293                 sel_start_cursor.pos++; 
2294
2295         // there are two cases: copy only within one paragraph
2296         // or more than one paragraph
2297         if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos) 
2298             == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2299                 // only within one paragraph
2300                 simple_cut_buffer = new LyXParagraph;
2301                 LyXParagraph::size_type i = 0;
2302                 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2303                         sel_start_cursor.par->CopyIntoMinibuffer(i);
2304                         simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2305                 }
2306         } else {
2307                 // copy more than one paragraph
2308                 // clone the paragraphs within the selection
2309                 tmppar =
2310                         sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2311                 simple_cut_buffer = tmppar->Clone();
2312                 LyXParagraph *tmppar2 = simple_cut_buffer;
2313      
2314                 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2315                        && tmppar->next) {
2316                         tmppar = tmppar->next;
2317                         tmppar2->next = tmppar->Clone();
2318                         tmppar2->next->previous = tmppar2;
2319                         tmppar2 = tmppar2->next;
2320                 }
2321                 tmppar2->next = 0;
2322
2323                 // care about footnotes
2324                 if (simple_cut_buffer->footnoteflag) {
2325                         tmppar = simple_cut_buffer;
2326                         while (tmppar){
2327                                 tmppar->footnoteflag =
2328                                         LyXParagraph::NO_FOOTNOTE;
2329                                 tmppar = tmppar->next;
2330                         }
2331                 }
2332                 
2333                 // the simple_cut_buffer paragraph is too big
2334                 LyXParagraph::size_type tmpi2 =
2335                         sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2336                 for (; tmpi2; --tmpi2)
2337                         simple_cut_buffer->Erase(0);
2338                 
2339                 // now tmppar 2 is too big, delete all after sel_end_cursor.pos
2340      
2341                 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2342                 while (tmppar2->size() > tmpi2) {
2343                         tmppar2->Erase(tmppar2->size() - 1);
2344                 }
2345         }
2346 }
2347
2348 #else //////////////////////////////////////////////////////////////////////
2349
2350 void LyXText::CopySelection()
2351 {
2352         // this doesnt make sense, if there is no selection
2353         if (!selection)
2354                 return;
2355
2356         // ok we have a selection. This is always between sel_start_cursor
2357         // and sel_end cursor
2358         LyXParagraph * tmppar;
2359    
2360         /* check wether there are half footnotes in the selection */
2361         if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2362             || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2363                 tmppar = sel_start_cursor.par;
2364                 while (tmppar != sel_end_cursor.par) {
2365                         if (tmppar->footnoteflag !=
2366                             sel_end_cursor.par->footnoteflag) {
2367                                 WriteAlert(_("Impossible operation"),
2368                                            _("Don't know what to do"
2369                                              " with half floats."),
2370                                            _("sorry."));
2371                                 return;
2372                         }
2373                         tmppar = tmppar->Next();
2374                 }
2375         }
2376
2377         /* table stuff -- begin */
2378         if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2379                 if ( sel_start_cursor.par != sel_end_cursor.par){
2380                         WriteAlert(_("Impossible operation"),
2381                                    _("Don't know what to do with half tables."),
2382                                    _("sorry."));
2383                         return;
2384                 }
2385         }
2386         /* table stuff -- end */
2387    
2388         // copy behind a space if there is one
2389         while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2390                && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2391                && (sel_start_cursor.par != sel_end_cursor.par
2392                    || sel_start_cursor.pos < sel_end_cursor.pos))
2393                 sel_start_cursor.pos++; 
2394
2395         CutAndPaste cap;
2396
2397         cap.copySelection(sel_start_cursor.par, sel_end_cursor.par,
2398                           sel_start_cursor.pos, sel_end_cursor.pos,
2399                           buffer->params.textclass);
2400 }
2401 #endif          
2402
2403 #ifdef USE_OLD_CUT_AND_PASTE
2404 void LyXText::PasteSelection()
2405 {
2406         // this does not make sense, if there is nothing to paste
2407         if (!simple_cut_buffer)
2408                 return;
2409
2410         LyXParagraph * tmppar;
2411         LyXParagraph * endpar;
2412
2413         LyXCursor tmpcursor;
2414
2415         // be carefull with footnotes in footnotes
2416         if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2417       
2418                 // check whether the cut_buffer includes a footnote
2419                 tmppar = simple_cut_buffer;
2420                 while (tmppar
2421                        && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2422                         tmppar = tmppar->next;
2423       
2424                 if (tmppar) {
2425                         WriteAlert(_("Impossible operation"),
2426                                    _("Can't paste float into float!"),
2427                                    _("Sorry."));
2428                         return;
2429                 }
2430         }
2431
2432         /* table stuff -- begin */
2433         if (cursor.par->table) {
2434                 if (simple_cut_buffer->next) {
2435                         WriteAlert(_("Impossible operation"),
2436                                    _("Table cell cannot include more than one paragraph!"),
2437                                    _("Sorry."));
2438                         return;
2439                 }
2440         }
2441         /* table stuff -- end */
2442    
2443         SetUndo(Undo::INSERT, 
2444                 cursor.par->ParFromPos(cursor.pos)->previous, 
2445                 cursor.par->ParFromPos(cursor.pos)->next); 
2446
2447         tmpcursor = cursor;
2448
2449         // There are two cases: cutbuffer only one paragraph or many
2450         if (!simple_cut_buffer->next) {
2451                 // only within a paragraph
2452
2453                 tmppar = simple_cut_buffer->Clone();
2454                 /* table stuff -- begin */
2455                 bool table_too_small = false;
2456                 if (tmpcursor.par->table) {
2457                         while (simple_cut_buffer->size()
2458                                && !table_too_small) {
2459                                 if (simple_cut_buffer->IsNewline(0)){
2460                                         while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2461                                                 tmpcursor.pos++;
2462                                         simple_cut_buffer->Erase(0);
2463                                         if (tmpcursor.pos < tmpcursor.par->Last())
2464                                                 tmpcursor.pos++;
2465                                         else
2466                                                 table_too_small = true;
2467                                 } else {
2468                                         // This is an attempt to fix the
2469                                         // "never insert a space at the
2470                                         // beginning of a paragraph" problem.
2471                                         if (tmpcursor.pos == 0
2472                                             && simple_cut_buffer->IsLineSeparator(0)) {
2473                                                 simple_cut_buffer->Erase(0);
2474                                         } else {
2475                                                 simple_cut_buffer->CutIntoMinibuffer(0);
2476                                                 simple_cut_buffer->Erase(0);
2477                                                 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2478                                                 tmpcursor.pos++;
2479                                         }
2480                                 }
2481                         }
2482                 } else {
2483                         /* table stuff -- end */
2484                         // Some provisions should be done here for checking
2485                         // if we are inserting at the beginning of a
2486                         // paragraph. If there are a space at the beginning
2487                         // of the text to insert and we are inserting at
2488                         // the beginning of the paragraph the space should
2489                         // be removed.
2490                         while (simple_cut_buffer->size()) {
2491                                 // This is an attempt to fix the
2492                                 // "never insert a space at the
2493                                 // beginning of a paragraph" problem.
2494                                 if (tmpcursor.pos == 0
2495                                     && simple_cut_buffer->IsLineSeparator(0)) {
2496                                         simple_cut_buffer->Erase(0);
2497                                 } else {
2498                                         simple_cut_buffer->CutIntoMinibuffer(0);
2499                                         simple_cut_buffer->Erase(0);
2500                                         tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2501                                         tmpcursor.pos++;
2502                                 }
2503                         }
2504                 }
2505                 delete simple_cut_buffer;
2506                 simple_cut_buffer = tmppar;
2507                 endpar = tmpcursor.par->Next();
2508         } else {
2509                 // many paragraphs
2510                 CutAndPaste cap;
2511
2512                 // make a copy of the simple cut_buffer
2513                 tmppar = simple_cut_buffer;
2514                 LyXParagraph * simple_cut_clone = tmppar->Clone();
2515                 LyXParagraph * tmppar2 = simple_cut_clone;
2516                 if (cursor.par->footnoteflag){
2517                         tmppar->footnoteflag = cursor.par->footnoteflag;
2518                         tmppar->footnotekind = cursor.par->footnotekind;
2519                 }
2520                 while (tmppar->next) {
2521                         tmppar = tmppar->next;
2522                         tmppar2->next = tmppar->Clone();
2523                         tmppar2->next->previous = tmppar2;
2524                         tmppar2 = tmppar2->next;
2525                         if (cursor.par->footnoteflag){
2526                                 tmppar->footnoteflag = cursor.par->footnoteflag;
2527                                 tmppar->footnotekind = cursor.par->footnotekind;
2528                         }
2529                 }
2530      
2531                 // make sure there is no class difference
2532                 cap.SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2533                                                 buffer->params.textclass,
2534                                                 simple_cut_buffer);
2535      
2536                 // make the simple_cut_buffer exactly the same layout than
2537                 // the cursor paragraph
2538                 simple_cut_buffer->MakeSameLayout(cursor.par);
2539      
2540                 // find the end of the buffer
2541                 LyXParagraph * lastbuffer = simple_cut_buffer;
2542                 while (lastbuffer->Next())
2543                         lastbuffer = lastbuffer->Next();
2544      
2545                 bool paste_the_end = false;
2546
2547                 // open the paragraph for inserting the simple_cut_buffer
2548                 // if necessary
2549                 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2550                         cursor.par->BreakParagraphConservative(cursor.pos);
2551                         paste_the_end = true;
2552                 }
2553
2554                 // set the end for redoing later
2555                 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2556      
2557                 // paste it!
2558                 lastbuffer->ParFromPos(lastbuffer->Last())->next =
2559                         cursor.par->ParFromPos(cursor.pos)->next;
2560                 cursor.par->ParFromPos(cursor.pos)->next->previous =
2561                         lastbuffer->ParFromPos(lastbuffer->Last());
2562      
2563                 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2564                 simple_cut_buffer->previous =
2565                         cursor.par->ParFromPos(cursor.pos);
2566    
2567                 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2568                         lastbuffer = cursor.par;
2569      
2570                 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2571      
2572                 // store the new cursor position
2573                 tmpcursor.par = lastbuffer;
2574                 tmpcursor.pos = lastbuffer->Last();
2575      
2576                 // maybe some pasting
2577                 if (lastbuffer->Next() && paste_the_end) {
2578                         if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2579                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2580          
2581                         } else if (!lastbuffer->Next()->Last()) {
2582                                 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2583                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2584          
2585                         } else if (!lastbuffer->Last()) {
2586                                 lastbuffer->MakeSameLayout(lastbuffer->next);
2587                                 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2588          
2589                         } else
2590                                 lastbuffer->Next()->ClearParagraph();
2591                 }
2592
2593                 // restore the simple cut buffer
2594                 simple_cut_buffer = simple_cut_clone;
2595         }
2596
2597         RedoParagraphs(cursor, endpar);
2598     
2599         SetCursor(cursor.par, cursor.pos);
2600         ClearSelection();
2601    
2602         sel_cursor = cursor;
2603         SetCursor(tmpcursor.par, tmpcursor.pos);
2604         SetSelection();
2605         UpdateCounters(cursor.row);
2606 }
2607
2608 #else ////////////////////////////////////////////////////////////////////
2609
2610 void LyXText::PasteSelection()
2611 {
2612     CutAndPaste cap;
2613
2614     // this does not make sense, if there is nothing to paste
2615     if (!cap.checkPastePossible(cursor.par, cursor.pos))
2616         return;
2617
2618     SetUndo(Undo::INSERT, 
2619             cursor.par->ParFromPos(cursor.pos)->previous, 
2620             cursor.par->ParFromPos(cursor.pos)->next); 
2621
2622     LyXParagraph *endpar;
2623     LyXParagraph *actpar = cursor.par;
2624     int endpos = cursor.pos;
2625
2626     cap.pasteSelection(&actpar, &endpar, endpos, buffer->params.textclass);
2627
2628     RedoParagraphs(cursor, endpar);
2629     
2630     SetCursor(cursor.par, cursor.pos);
2631     ClearSelection();
2632    
2633     sel_cursor = cursor;
2634     SetCursor(actpar, endpos);
2635     SetSelection();
2636     UpdateCounters(cursor.row);
2637 }
2638 #endif   
2639
2640 // returns a pointer to the very first LyXParagraph
2641 LyXParagraph * LyXText::FirstParagraph() const
2642 {
2643         return buffer->paragraph;
2644 }
2645
2646
2647 // returns true if the specified string is at the specified position
2648 bool LyXText::IsStringInText(LyXParagraph * par,
2649                              LyXParagraph::size_type pos,
2650                              char const * str) const
2651 {
2652         if (par) {
2653                 int i = 0;
2654                 while (pos + i < par->Last() && str[i] && 
2655                        str[i] == par->GetChar(pos + i)) {
2656                         ++i;
2657                 }
2658                 if (!str[i])
2659                         return true;
2660         }
2661         return false;
2662 }
2663
2664
2665 // sets the selection over the number of characters of string, no check!!
2666 void LyXText::SetSelectionOverString(char const * string)
2667 {
2668         sel_cursor = cursor;
2669         for (int i = 0; string[i]; ++i)
2670                 CursorRight();
2671         SetSelection();
2672 }
2673
2674
2675 // simple replacing. The font of the first selected character is used
2676 void LyXText::ReplaceSelectionWithString(char const * str)
2677 {
2678         SetCursorParUndo();
2679         FreezeUndo();
2680
2681         if (!selection) { // create a dummy selection
2682                 sel_end_cursor = cursor;
2683                 sel_start_cursor = cursor;
2684         }
2685
2686         // Get font setting before we cut
2687         LyXParagraph::size_type pos = sel_end_cursor.pos;
2688         LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2689
2690         // Insert the new string
2691         for (int i = 0; str[i]; ++i) {
2692                 sel_end_cursor.par->InsertChar(pos, str[i]);
2693                 sel_end_cursor.par->SetFont(pos, font);
2694                 ++pos;
2695         }
2696
2697         // Cut the selection
2698         CutSelection();
2699
2700         UnFreezeUndo();
2701 }
2702
2703
2704 // if the string can be found: return true and set the cursor to
2705 // the new position
2706 bool LyXText::SearchForward(char const * str) const
2707 {
2708         LyXParagraph * par = cursor.par;
2709         LyXParagraph::size_type pos = cursor.pos;
2710         while (par && !IsStringInText(par, pos, str)) {
2711                 if (pos < par->Last() - 1)
2712                         ++pos;
2713                 else {
2714                         pos = 0;
2715                         par = par->Next();
2716                 }
2717         }
2718         if (par) {
2719                 SetCursor(par, pos);
2720                 return true;
2721         }
2722         else
2723                 return false;
2724 }
2725
2726
2727 bool LyXText::SearchBackward(char const * string) const
2728 {
2729         LyXParagraph * par = cursor.par;
2730         int pos = cursor.pos;
2731
2732         do {
2733                 if (pos > 0)
2734                         --pos;
2735                 else {
2736                         // We skip empty paragraphs (Asger)
2737                         do {
2738                                 par = par->Previous();
2739                                 if (par)
2740                                         pos = par->Last() - 1;
2741                         } while (par && pos < 0);
2742                 }
2743         } while (par && !IsStringInText(par, pos, string));
2744   
2745         if (par) {
2746                 SetCursor(par, pos);
2747                 return true;
2748         } else
2749                 return false;
2750 }
2751
2752
2753 // needed to insert the selection
2754 void LyXText::InsertStringA(string const & str)
2755 {
2756         LyXParagraph * par = cursor.par;
2757         LyXParagraph::size_type pos = cursor.pos;
2758         LyXParagraph::size_type a = 0;
2759         int cell = 0;
2760         LyXParagraph * endpar = cursor.par->Next();
2761         
2762         SetCursorParUndo();
2763         
2764         bool flag =
2765                 textclasslist.Style(buffer->params.textclass, 
2766                                     cursor.par->GetLayout()).isEnvironment();
2767         // only to be sure, should not be neccessary
2768         ClearSelection();
2769         
2770         // insert the string, don't insert doublespace
2771         string::size_type i = 0;
2772         while (i < str.length()) {
2773                 if (str[i] != '\n') {
2774                         if (str[i] == ' ' 
2775                             && i + 1 < str.length() && str[i + 1] != ' '
2776                             && pos && par->GetChar(pos - 1)!= ' ') {
2777                                 par->InsertChar(pos,' ');
2778                                 par->SetFont(pos, current_font);
2779                                 ++pos;
2780                         } else if (par->table) {
2781                                 if (str[i] == '\t') {
2782                                         while((pos < par->size()) &&
2783                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2784                                                 ++pos;
2785                                         if (pos < par->size())
2786                                                 ++pos;
2787                                         else // no more fields to fill skip the rest
2788                                                 break;
2789                                 } else if ((str[i] != 13) &&
2790                                            ((str[i] & 127) >= ' ')) {
2791                                         par->InsertChar(pos, str[i]);
2792                                         par->SetFont(pos, current_font);
2793                                         ++pos;
2794                                 }
2795                         } else if (str[i] == ' ') {
2796                                 InsetSpecialChar * new_inset =
2797                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2798                                 if (par->InsertInsetAllowed(new_inset)) {
2799                                         par->InsertChar(pos, LyXParagraph::META_INSET);
2800                                         par->SetFont(pos, current_font);
2801                                         par->InsertInset(pos, new_inset);
2802                                 } else {
2803                                         delete new_inset;
2804                                 }
2805                                 ++pos;
2806                         } else if (str[i] == '\t') {
2807                                 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2808                                 InsetSpecialChar * new_inset =
2809                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2810                                 if (par->InsertInsetAllowed(new_inset)) {
2811                                         par->InsertChar(pos, LyXParagraph::META_INSET);
2812                                         par->SetFont(pos, current_font);
2813                                         par->InsertInset(pos, new_inset);
2814                                 } else {
2815                                         delete new_inset;
2816                                 }
2817                                 }
2818                                 pos = a;
2819                         } else if (str[i] != 13 && 
2820                                    // Ignore unprintables
2821                                    (str[i] & 127) >= ' ') {
2822                                 par->InsertChar(pos, str[i]);
2823                                 par->SetFont(pos, current_font);
2824                                 ++pos;
2825                         }
2826                 } else {
2827                         if (par->table) {
2828                                 if (i + 1 >= str.length()) {
2829                                         ++pos;
2830                                         break;
2831                                 }
2832                                 while((pos < par->size()) &&
2833                                       (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2834                                         ++pos;
2835                                 ++pos;
2836                                 cell = NumberOfCell(par, pos);
2837                                 while((pos < par->size()) &&
2838                                       !(par->table->IsFirstCell(cell))) {
2839
2840                                         while((pos < par->size()) &&
2841                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2842                                                 ++pos;
2843                                         ++pos;
2844                                         cell = NumberOfCell(par, pos);
2845                                 }
2846                                 if (pos >= par->size())
2847                                         // no more fields to fill skip the rest
2848                                         break;
2849                         } else {
2850                                 if (!par->size()) { // par is empty
2851                                         InsetSpecialChar * new_inset =
2852                                                 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2853                                         if (par->InsertInsetAllowed(new_inset)) {
2854                                                 par->InsertChar(pos, LyXParagraph::META_INSET);
2855                                                 par->SetFont(pos, current_font);
2856                                                 par->InsertInset(pos, new_inset);
2857                                         } else {
2858                                                 delete new_inset;
2859                                         }
2860                                         ++pos;
2861                                 }
2862                                 par->BreakParagraph(pos, flag);
2863                                 par = par->Next();
2864                                 pos = 0;
2865                         }
2866                 }
2867                 ++i;
2868         }
2869         
2870         RedoParagraphs(cursor, endpar);
2871         SetCursor(cursor.par, cursor.pos);
2872         sel_cursor = cursor;
2873         SetCursor(par, pos);
2874         SetSelection();
2875 }
2876
2877
2878 /* turns double-CR to single CR, others where converted into one blank and 13s 
2879  * that are ignored .Double spaces are also converted into one. Spaces at
2880  * the beginning of a paragraph are forbidden. tabs are converted into one
2881  * space. then InsertStringA is called */ 
2882 void LyXText::InsertStringB(string const & s)
2883 {
2884         string str(s);
2885         LyXParagraph * par = cursor.par;
2886         string::size_type i = 1;
2887         while (i < str.length()) {
2888                 if (str[i] == '\t' && !par->table)
2889                         str[i] = ' ';
2890                 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2891                         str[i] = 13;
2892                 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2893                         if (str[i + 1] != '\n') {
2894                                 if (str[i - 1] != ' ')
2895                                         str[i] = ' ';
2896                                 else
2897                                         str[i] = 13;
2898                         }
2899                         while (i + 1 < str.length() 
2900                                && (str[i + 1] == ' ' 
2901                                    || str[i + 1] == '\t'
2902                                    || str[i + 1] == '\n' 
2903                                    || str[i + 1] == 13)) {
2904                                 str[i + 1] = 13;
2905                                 ++i;
2906                         }
2907                 }
2908                 ++i;
2909         }
2910         InsertStringA(str);
2911 }
2912
2913
2914 bool LyXText::GotoNextError() const
2915 {
2916         LyXCursor res = cursor;
2917         do {
2918                 if (res.pos < res.par->Last() - 1) {
2919                         res.pos++;
2920                 }
2921                 else  {
2922                         res.par = res.par->Next();
2923                         res.pos = 0;
2924                 }
2925       
2926         } while (res.par && 
2927                  !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2928                    && res.par->GetInset(res.pos)->AutoDelete()));
2929    
2930         if (res.par) {
2931                 SetCursor(res.par, res.pos);
2932                 return true;
2933         }
2934         return false;
2935 }
2936
2937
2938 bool LyXText::GotoNextNote() const
2939 {
2940         LyXCursor res = cursor;
2941         do {
2942                 if (res.pos < res.par->Last() - 1) {
2943                         res.pos++;
2944                 } else  {
2945                         res.par = res.par->Next();
2946                         res.pos = 0;
2947                 }
2948       
2949         } while (res.par && 
2950                  !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2951                    && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
2952    
2953         if (res.par) {
2954                 SetCursor(res.par, res.pos);
2955                 return true;
2956         }
2957         return false;
2958 }
2959
2960
2961 void LyXText::CheckParagraph(LyXParagraph * par,
2962                              LyXParagraph::size_type pos)
2963 {
2964         LyXCursor tmpcursor;                    
2965
2966
2967         /* table stuff -- begin*/
2968    
2969         if (par->table) {
2970                 CheckParagraphInTable(par, pos);
2971         }
2972         else {
2973                 /* table stuff -- end*/
2974      
2975                 long y = 0;
2976                 LyXParagraph::size_type z;
2977                 Row * row = GetRow(par, pos, y);
2978      
2979                 // is there a break one row above
2980                 if (row->previous && row->previous->par == row->par) {
2981                         z = NextBreakPoint(row->previous, paperwidth);
2982                         if ( z >= row->pos) {
2983                                 // set the dimensions of the row above
2984                                 y -= row->previous->height;
2985                                 refresh_y = y;
2986                                 refresh_row = row->previous;
2987                                 status = LyXText::NEED_MORE_REFRESH;
2988        
2989                                 BreakAgain(row->previous);
2990
2991                                 // set the cursor again. Otherwise
2992                                 // dangling pointers are possible
2993                                 SetCursor(cursor.par, cursor.pos);
2994                                 sel_cursor = cursor;
2995                                 return;
2996                         }
2997                 }
2998
2999                 int tmpheight = row->height;
3000                 LyXParagraph::size_type tmplast = RowLast(row);
3001                 refresh_y = y;
3002                 refresh_row = row;
3003
3004                 BreakAgain(row);
3005                 if (row->height == tmpheight && RowLast(row) == tmplast)
3006                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
3007                 else
3008                         status = LyXText::NEED_MORE_REFRESH; 
3009    
3010                 // check the special right address boxes
3011                 if (textclasslist.Style(buffer->params.textclass,
3012                                         par->GetLayout()).margintype
3013                     == MARGIN_RIGHT_ADDRESS_BOX) {
3014                         tmpcursor.par = par;
3015                         tmpcursor.row = row;
3016                         tmpcursor.y = y;
3017                         tmpcursor.x = 0;
3018                         tmpcursor.x_fix = 0;
3019                         tmpcursor.pos = pos;
3020                         RedoDrawingOfParagraph(tmpcursor); 
3021                 }
3022    
3023         }
3024
3025         // set the cursor again. Otherwise dangling pointers are possible
3026         // also set the selection
3027    
3028         if (selection) {
3029                 tmpcursor = cursor;
3030                 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
3031                 sel_cursor = cursor; 
3032                 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
3033                 sel_start_cursor = cursor; 
3034                 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
3035                 sel_end_cursor = cursor; 
3036                 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
3037                 last_sel_cursor = cursor; 
3038                 cursor = tmpcursor;
3039         }
3040         SetCursorIntern(cursor.par, cursor.pos);
3041 }
3042
3043
3044 // returns 0 if inset wasn't found
3045 int LyXText::UpdateInset(Inset * inset)
3046 {
3047         // first check the current paragraph
3048         int pos = cursor.par->GetPositionOfInset(inset);
3049         if (pos != -1){
3050                 CheckParagraph(cursor.par, pos);
3051                 return 1;
3052         }
3053   
3054         // check every paragraph
3055   
3056         LyXParagraph * par = FirstParagraph();
3057         do {
3058                 // make sure the paragraph is open
3059                 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
3060                         pos = par->GetPositionOfInset(inset);
3061                         if (pos != -1){
3062                                 CheckParagraph(par, pos);
3063                                 return 1;
3064                         }
3065                 }
3066                 par = par->Next();
3067         } while (par);
3068   
3069         return 0;
3070 }
3071
3072
3073 void LyXText::SetCursor(LyXParagraph * par,
3074                         LyXParagraph::size_type pos, bool setfont) const
3075 {
3076         LyXCursor old_cursor = cursor;
3077         SetCursorIntern(par, pos, setfont);
3078         DeleteEmptyParagraphMechanism(old_cursor);
3079 }
3080
3081
3082 void LyXText::SetCursor(LyXCursor & cur, LyXParagraph * par,
3083                         LyXParagraph::size_type pos) const
3084 {
3085         // correct the cursor position if impossible
3086         if (pos > par->Last()){
3087                 LyXParagraph * tmppar = par->ParFromPos(pos);
3088                 pos = par->PositionInParFromPos(pos);
3089                 par = tmppar;
3090         }
3091         if (par->IsDummy() && par->previous &&
3092             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3093                 while (par->previous &&
3094                        ((par->previous->IsDummy() &&
3095                          (par->previous->previous->footnoteflag ==
3096                           LyXParagraph::CLOSED_FOOTNOTE)) ||
3097                         (par->previous->footnoteflag ==
3098                          LyXParagraph::CLOSED_FOOTNOTE))) {
3099                         par = par->previous ;
3100                         if (par->IsDummy() &&
3101                             (par->previous->footnoteflag ==
3102                              LyXParagraph::CLOSED_FOOTNOTE))
3103                                 pos += par->size() + 1;
3104                 }
3105                 if (par->previous) {
3106                         par = par->previous;
3107                 }
3108                 pos += par->size() + 1;
3109         }
3110
3111         cur.par = par;
3112         cur.pos = pos;
3113
3114         /* get the cursor y position in text  */
3115         long y = 0;
3116         Row * row = GetRow(par, pos, y);
3117         /* y is now the beginning of the cursor row */ 
3118         y += row->baseline;
3119         /* y is now the cursor baseline */ 
3120         cur.y = y;
3121    
3122         /* now get the cursors x position */
3123         float x;
3124         float fill_separator, fill_hfill, fill_label_hfill;
3125         PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3126         LyXParagraph::size_type cursor_vpos;
3127         LyXParagraph::size_type last = RowLastPrintable(row);
3128
3129         if (pos > last + 1)   // This shouldn't happen.
3130                 pos = last+1;
3131
3132         if (last < row->pos)
3133                 cursor_vpos = 0;
3134         else if ((pos > last) ||
3135                  ((pos - 1 >= row->pos) &&
3136                   (row->par->IsSeparator(pos) ||
3137                    (row->par->table && row->par->IsNewline(pos)))))
3138                 /// Place cursor after char at (logical) position pos-1
3139                 cursor_vpos = !(bidi_level(pos-1) % 2)
3140                         ? log2vis(pos-1) + 1 : log2vis(pos-1);
3141         else
3142                 /// Place cursor before char at (logical) position pos
3143                 cursor_vpos = !(bidi_level(pos) % 2)
3144                         ? log2vis(pos) : log2vis(pos) + 1;
3145
3146         /* table stuff -- begin*/
3147         if (row->par->table) {
3148                 int cell = NumberOfCell(row->par, row->pos);
3149                 float x_old = x;
3150                 x += row->par->table->GetBeginningOfTextInCell(cell);
3151                 for (LyXParagraph::size_type vpos = row->pos;
3152                      vpos < cursor_vpos; ++vpos) {
3153                         pos = vis2log(vpos);
3154                         if (row->par->IsNewline(pos)) {
3155                                 x = x_old + row->par->table->WidthOfColumn(cell);
3156                                 x_old = x;
3157                                 ++cell;
3158                                 x += row->par->table->GetBeginningOfTextInCell(cell);
3159                         } else {
3160                                 x += SingleWidth(row->par, pos);
3161                         }
3162                 }
3163         } else {
3164                 /* table stuff -- end*/
3165                 LyXParagraph::size_type main_body =
3166                         BeginningOfMainBody(row->par);
3167                 if ((main_body > 0) &&
3168                     ((main_body-1 > last) || 
3169                      !row->par->IsLineSeparator(main_body-1)))
3170                         main_body = 0;
3171
3172                 for (LyXParagraph::size_type vpos = row->pos;
3173                      vpos < cursor_vpos; ++vpos) {
3174                         pos = vis2log(vpos);
3175                         if (main_body > 0 && pos == main_body-1) {
3176                                 x += fill_label_hfill +
3177                                         lyxfont::width(textclasslist.Style(
3178                                                 buffer->params.textclass,
3179                                                 row->par->GetLayout())
3180                                                        .labelsep,
3181                                                        GetFont(row->par, -2));
3182                                 if (row->par->IsLineSeparator(main_body-1))
3183                                         x -= SingleWidth(row->par,main_body-1);
3184                         }
3185                         if (HfillExpansion(row, pos)) {
3186                                 x += SingleWidth(row->par, pos);
3187                                 if (pos >= main_body)
3188                                         x += fill_hfill;
3189                                 else 
3190                                         x += fill_label_hfill;
3191                         } else if (row->par->IsSeparator(pos)) {
3192                                 x += SingleWidth(row->par, pos);
3193                                 if (pos >= main_body)
3194                                         x += fill_separator;
3195                         } else
3196                                 x += SingleWidth(row->par, pos);
3197                 }
3198         }
3199    
3200         cur.x = int(x);
3201         cur.x_fix = cur.x;
3202         cur.row = row;
3203 }
3204
3205
3206 void LyXText::SetCursorIntern(LyXParagraph * par,
3207                               LyXParagraph::size_type pos, bool setfont) const
3208 {
3209         SetCursor(cursor, par, pos);
3210 #warning Remove this when verified working (Jug 20000413)
3211 #if 0
3212         // correct the cursor position if impossible
3213         if (pos > par->Last()){
3214                 LyXParagraph * tmppar = par->ParFromPos(pos);
3215                 pos = par->PositionInParFromPos(pos);
3216                 par = tmppar;
3217         }
3218         if (par->IsDummy() && par->previous &&
3219             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3220                 while (par->previous &&
3221                        ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
3222                         (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
3223                         par = par->previous ;
3224                         if (par->IsDummy() &&
3225                             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3226                                 pos += par->size() + 1;
3227                 }
3228                 if (par->previous) {
3229                         par = par->previous;
3230                 }
3231                 pos += par->size() + 1;
3232         }
3233
3234         cursor.par = par;
3235         cursor.pos = pos;
3236
3237         /* get the cursor y position in text  */
3238         long y = 0;
3239         Row * row = GetRow(par, pos, y);
3240         /* y is now the beginning of the cursor row */ 
3241         y += row->baseline;
3242         /* y is now the cursor baseline */ 
3243         cursor.y = y;
3244    
3245         /* now get the cursors x position */
3246         float x;
3247         float fill_separator, fill_hfill, fill_label_hfill;
3248         PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3249         LyXParagraph::size_type cursor_vpos;
3250         LyXParagraph::size_type last = RowLastPrintable(row);
3251
3252         if (pos > last + 1)   // This shouldn't happen.
3253                 pos = last+1;
3254
3255         if (last < row->pos)
3256                 cursor_vpos = 0;
3257         else if (pos > last ||
3258             (pos - 1 >= row->pos &&
3259              (row->par->IsSeparator(pos) ||
3260               (row->par->table && row->par->IsNewline(pos))
3261               )))
3262                 /// Place cursor after char at (logical) position pos-1
3263                 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
3264                         ? log2vis(pos-1) + 1 : log2vis(pos-1);
3265         else
3266                 /// Place cursor before char at (logical) position pos
3267                 cursor_vpos = (bidi_level(pos) % 2 == 0)
3268                         ? log2vis(pos) : log2vis(pos) + 1;
3269
3270         /* table stuff -- begin*/
3271         if (row->par->table) {
3272                 int cell = NumberOfCell(row->par, row->pos);
3273                 float x_old = x;
3274                 x += row->par->table->GetBeginningOfTextInCell(cell);
3275                 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos)  {
3276                         pos = vis2log(vpos);
3277                         if (row->par->IsNewline(pos)) {
3278                                 x = x_old + row->par->table->WidthOfColumn(cell);
3279                                 x_old = x;
3280                                 ++cell;
3281                                 x += row->par->table->GetBeginningOfTextInCell(cell);
3282                         } else {
3283                                 x += SingleWidth(row->par, pos);
3284                         }
3285                 }
3286         } else {
3287                 /* table stuff -- end*/
3288                 LyXParagraph::size_type main_body =
3289                         BeginningOfMainBody(row->par);
3290                 if (main_body > 0 &&
3291                     (main_body-1 > last || 
3292                      !row->par->IsLineSeparator(main_body-1)))
3293                         main_body = 0;
3294
3295                 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos)  {
3296                         pos = vis2log(vpos);
3297                         if (main_body > 0 && pos == main_body-1) {
3298                                 x += fill_label_hfill +
3299                                         lyxfont::width(textclasslist
3300                                                        .Style(buffer->params.textclass,
3301                                                               row->par->GetLayout())
3302                                                        .labelsep,
3303                                                        GetFont(row->par, -2));
3304                                 if (row->par->IsLineSeparator(main_body-1))
3305                                         x -= SingleWidth(row->par, main_body-1);
3306                         }
3307                         if (HfillExpansion(row, pos)) {
3308                                 x += SingleWidth(row->par, pos);
3309                                 if (pos >= main_body)
3310                                         x += fill_hfill;
3311                                 else 
3312                                         x += fill_label_hfill;
3313                         }
3314                         else if (row->par->IsSeparator(pos)) {
3315                                 x += SingleWidth(row->par, pos);
3316                                 if (pos >= main_body)
3317                                         x += fill_separator;
3318                         } else
3319                                 x += SingleWidth(row->par, pos);
3320                 }
3321         }
3322    
3323         cursor.x = int(x);
3324    
3325         cursor.x_fix = cursor.x;
3326         cursor.row = row;
3327 #endif
3328         if (setfont) {
3329                 if (cursor.pos && 
3330                     (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
3331                      || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3332                      )) {
3333                         current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3334                         real_current_font = GetFont(cursor.par, cursor.pos - 1);
3335                 } else {
3336                         current_font = cursor.par->GetFontSettings(cursor.pos);
3337                         real_current_font = GetFont(cursor.par, cursor.pos);
3338                 }
3339         }
3340 }
3341
3342
3343 void LyXText::SetCursorFromCoordinates(int x, long y) const
3344 {
3345         LyXCursor old_cursor = cursor;
3346    
3347         /* get the row first */ 
3348    
3349         Row * row = GetRowNearY(y);
3350    
3351         cursor.par = row->par;
3352    
3353         int column = GetColumnNearX(row, x);
3354         cursor.pos = row->pos + column;
3355         cursor.x = x;
3356         cursor.y = y + row->baseline;
3357    
3358         cursor.row = row;
3359     
3360         if (cursor.pos && 
3361             (cursor.pos == cursor.par->Last()
3362              || cursor.par->IsSeparator(cursor.pos)
3363              || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3364                  && !cursor.par->IsSeparator(cursor.pos))
3365              || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3366                     )) {
3367                 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3368                 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3369         } else {
3370                 current_font = cursor.par->GetFontSettings(cursor.pos);
3371                 real_current_font = GetFont(cursor.par, cursor.pos);
3372         }
3373         DeleteEmptyParagraphMechanism(old_cursor);
3374 }
3375
3376 void LyXText::SetCursorFromCoordinates(LyXCursor & cur, int x, long y) const
3377 {
3378         /* get the row first */ 
3379    
3380         Row * row = GetRowNearY(y);
3381         int column = GetColumnNearX(row, x);
3382    
3383         cur.par = row->par;
3384         cur.pos = row->pos + column;
3385         cur.x = x;
3386         cur.y = y + row->baseline;
3387         cur.row = row;
3388 }
3389
3390
3391 void LyXText::CursorLeft() const
3392 {
3393         CursorLeftIntern();
3394         if (cursor.par->table) {
3395                 int cell = NumberOfCell(cursor.par, cursor.pos);
3396                 if (cursor.par->table->IsContRow(cell) &&
3397                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell)) < 0) {
3398                         CursorUp();
3399                 }
3400         }
3401 }
3402
3403
3404 void LyXText::CursorLeftIntern() const
3405 {
3406         if (cursor.pos > 0) {
3407                 SetCursor(cursor.par, cursor.pos - 1);
3408         }
3409         else if (cursor.par->Previous()) { // steps into the above paragraph.
3410                 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3411         }
3412 }
3413
3414
3415 void LyXText::CursorRight() const
3416 {
3417         CursorRightIntern();
3418         if (cursor.par->table) {
3419                 int cell = NumberOfCell(cursor.par, cursor.pos);
3420                 if (cursor.par->table->IsContRow(cell) &&
3421                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3422                         CursorUp();
3423                 }
3424         }
3425 }
3426
3427
3428 void LyXText::CursorRightIntern() const
3429 {
3430         if (cursor.pos < cursor.par->Last()) {
3431                 SetCursor(cursor.par, cursor.pos + 1);
3432         }
3433         else if (cursor.par->Next()) {
3434                 SetCursor(cursor.par->Next(), 0);
3435         }
3436 }
3437
3438
3439 void LyXText::CursorUp() const
3440 {
3441         SetCursorFromCoordinates(cursor.x_fix, 
3442                                  cursor.y - cursor.row->baseline - 1);
3443         if (cursor.par->table) {
3444                 int cell = NumberOfCell(cursor.par, cursor.pos);
3445                 if (cursor.par->table->IsContRow(cell) &&
3446                     cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3447                         CursorUp();
3448                 }
3449         }
3450 }
3451
3452
3453 void LyXText::CursorDown() const
3454 {
3455         if (cursor.par->table &&
3456             cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3457             !cursor.par->next)
3458                 return;
3459         SetCursorFromCoordinates(cursor.x_fix, 
3460                                  cursor.y - cursor.row->baseline
3461                                  + cursor.row->height + 1);
3462         if (cursor.par->table) {
3463                 int cell = NumberOfCell(cursor.par, cursor.pos);
3464                 int cell_above = cursor.par->table->GetCellAbove(cell);
3465                 while(cursor.par->table &&
3466                       cursor.par->table->IsContRow(cell) &&
3467                       (cursor.par->table->CellHasContRow(cell_above)<0)) {
3468                     SetCursorFromCoordinates(cursor.x_fix, 
3469                                              cursor.y - cursor.row->baseline
3470                                              + cursor.row->height + 1);
3471                     if (cursor.par->table) {
3472                         cell = NumberOfCell(cursor.par, cursor.pos);
3473                         cell_above = cursor.par->table->GetCellAbove(cell);
3474                     }
3475                 }
3476         }
3477 }
3478
3479
3480 void LyXText::CursorUpParagraph() const
3481 {
3482         if (cursor.pos > 0) {
3483                 SetCursor(cursor.par, 0);
3484         }
3485         else if (cursor.par->Previous()) {
3486                 SetCursor(cursor.par->Previous(), 0);
3487         }
3488 }
3489
3490
3491 void LyXText::CursorDownParagraph() const
3492 {
3493         if (cursor.par->Next()) {
3494                 SetCursor(cursor.par->Next(), 0);
3495         } else {
3496                 SetCursor(cursor.par, cursor.par->Last());
3497         }
3498 }
3499
3500
3501
3502 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3503 {
3504         // Would be wrong to delete anything if we have a selection.
3505         if (selection) return;
3506
3507         // We allow all kinds of "mumbo-jumbo" when freespacing.
3508         if (textclasslist.Style(buffer->params.textclass,
3509                                 old_cursor.par->GetLayout()).free_spacing)
3510                 return;
3511
3512         bool deleted = false;
3513         
3514         /* Ok I'll put some comments here about what is missing.
3515            I have fixed BackSpace (and thus Delete) to not delete
3516            double-spaces automagically. I have also changed Cut,
3517            Copy and Paste to hopefully do some sensible things.
3518            There are still some small problems that can lead to
3519            double spaces stored in the document file or space at
3520            the beginning of paragraphs. This happens if you have
3521            the cursor betwenn to spaces and then save. Or if you
3522            cut and paste and the selection have a space at the
3523            beginning and then save right after the paste. I am
3524            sure none of these are very hard to fix, but I will
3525            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3526            that I can get some feedback. (Lgb)
3527         */
3528
3529         // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3530         // delete the LineSeparator.
3531         // MISSING
3532
3533         // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3534         // delete the LineSeparator.
3535         // MISSING
3536
3537         // If the pos around the old_cursor were spaces, delete one of them.
3538         if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) { // Only if the cursor has really moved
3539                 
3540                 if (old_cursor.pos > 0
3541                     && old_cursor.pos < old_cursor.par->Last()
3542                     && old_cursor.par->IsLineSeparator(old_cursor.pos)
3543                     && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3544                         old_cursor.par->Erase(old_cursor.pos - 1);
3545                         RedoParagraphs(old_cursor, old_cursor.par->Next());
3546                         // correct cursor
3547                         if (old_cursor.par == cursor.par &&
3548                             cursor.pos > old_cursor.pos) {
3549                                 SetCursorIntern(cursor.par, cursor.pos - 1);
3550                         } else
3551                                 SetCursorIntern(cursor.par, cursor.pos);
3552                         return;
3553                 }
3554         }
3555
3556         // Do not delete empty paragraphs with keepempty set.
3557         if ((textclasslist.Style(buffer->params.textclass,
3558                                  old_cursor.par->GetLayout())).keepempty)
3559                 return;
3560
3561         LyXCursor tmpcursor;
3562
3563         if (old_cursor.par != cursor.par) {
3564                 if ( (old_cursor.par->Last() == 0
3565                       || (old_cursor.par->Last() == 1
3566                           && old_cursor.par->IsLineSeparator(0)))
3567                      && old_cursor.par->FirstPhysicalPar()
3568                      == old_cursor.par->LastPhysicalPar()) {
3569                         // ok, we will delete anything
3570                         
3571                         // make sure that you do not delete any environments
3572                         if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3573                              !(old_cursor.row->previous 
3574                                && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3575                              && !(old_cursor.row->next 
3576                                   && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3577                             || (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3578                                 && ((old_cursor.row->previous 
3579                                      && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3580                                     || (old_cursor.row->next
3581                                         && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3582                                     )) {
3583                                 status = LyXText::NEED_MORE_REFRESH;
3584                                 deleted = true;
3585                                 
3586                                 if (old_cursor.row->previous) {
3587                                         refresh_row = old_cursor.row->previous;
3588                                         refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3589                                         tmpcursor = cursor;
3590                                         cursor = old_cursor; // that undo can restore the right cursor position
3591                                         LyXParagraph * endpar = old_cursor.par->next;
3592                                         if (endpar && endpar->GetDepth()) {
3593                                                 while (endpar && endpar->GetDepth()) {
3594                                                         endpar = endpar->LastPhysicalPar()->Next();
3595                                                 }
3596                                         }
3597                                         SetUndo(Undo::DELETE,
3598                                                 old_cursor.par->previous,
3599                                                 endpar);
3600                                         cursor = tmpcursor;
3601
3602                                         // delete old row
3603                                         RemoveRow(old_cursor.row);
3604                                         if (buffer->paragraph == old_cursor.par) {
3605                                                 buffer->paragraph = buffer->paragraph->next;
3606                                         }
3607                                         // delete old par
3608                                         delete old_cursor.par;
3609                                         
3610                                         /* Breakagain the next par. Needed
3611                                          * because of the parindent that
3612                                          * can occur or dissappear. The
3613                                          * next row can change its height,
3614                                          * if there is another layout before */
3615                                         if (refresh_row->next) {
3616                                                 BreakAgain(refresh_row->next);
3617                                                 UpdateCounters(refresh_row);
3618                                         }
3619                                         SetHeightOfRow(refresh_row);
3620                                 } else {
3621                                         refresh_row = old_cursor.row->next;
3622                                         refresh_y = old_cursor.y - old_cursor.row->baseline;
3623                                         
3624                                         tmpcursor = cursor;
3625                                         cursor = old_cursor; // that undo can restore the right cursor position
3626                                         LyXParagraph *endpar = old_cursor.par->next;
3627                                         if (endpar && endpar->GetDepth()) {
3628                                                 while (endpar && endpar->GetDepth()) {
3629                                                         endpar = endpar->LastPhysicalPar()->Next();
3630                                                 }
3631                                         }
3632                                         SetUndo(Undo::DELETE,
3633                                                 old_cursor.par->previous,
3634                                                 endpar);
3635                                         cursor = tmpcursor;
3636
3637                                         // delete old row
3638                                         RemoveRow(old_cursor.row);
3639                                         // delete old par
3640                                         if (buffer->paragraph == old_cursor.par) {
3641                                                 buffer->paragraph = buffer->paragraph->next;
3642                                         }
3643                                         delete old_cursor.par;
3644                                         
3645                                         /* Breakagain the next par. Needed
3646                                            because of the parindent that can
3647                                            occur or dissappear.
3648                                            The next row can change its height,
3649                                            if there is another layout before
3650                                         */ 
3651                                         if (refresh_row) {
3652                                                 BreakAgain(refresh_row);
3653                                                 UpdateCounters(refresh_row->previous);
3654                                         }
3655                                 }
3656                                 
3657                                 // correct cursor y
3658
3659                                 SetCursorIntern(cursor.par, cursor.pos);
3660
3661                                 if (sel_cursor.par  == old_cursor.par
3662                                     && sel_cursor.pos == sel_cursor.pos) {
3663                                         // correct selection
3664                                         sel_cursor = cursor;
3665                                 }
3666                         }
3667                 }
3668                 if (!deleted) {
3669                         if (old_cursor.par->ClearParagraph()) {
3670                                 RedoParagraphs(old_cursor, old_cursor.par->Next());
3671                                 // correct cursor y
3672                                 SetCursorIntern(cursor.par, cursor.pos);
3673                                 sel_cursor = cursor;
3674                         }
3675                 }
3676         }
3677 }
3678
3679
3680 LyXParagraph * LyXText::GetParFromID(int id)
3681 {
3682         LyXParagraph * result = FirstParagraph();
3683         while (result && result->id() != id)
3684                 result = result->next;
3685         return result;
3686 }
3687
3688
3689 // undo functions
3690 bool LyXText::TextUndo()
3691 {
3692         // returns false if no undo possible
3693         Undo * undo = buffer->undostack.pop();
3694         if (undo) {
3695                 FinishUndo();
3696                 if (!undo_frozen)
3697                         buffer->redostack
3698                                 .push(CreateUndo(undo->kind, 
3699                                                  GetParFromID(undo->number_of_before_par),
3700                                                  GetParFromID(undo->number_of_behind_par)));
3701         }
3702         return TextHandleUndo(undo);
3703 }
3704
3705
3706 bool LyXText::TextRedo()
3707 {
3708         // returns false if no redo possible
3709         Undo * undo = buffer->redostack.pop();
3710         if (undo) {
3711                 FinishUndo();
3712                 if (!undo_frozen)
3713                         buffer->undostack
3714                                 .push(CreateUndo(undo->kind, 
3715                                                  GetParFromID(undo->number_of_before_par),
3716                                                  GetParFromID(undo->number_of_behind_par)));
3717         }
3718         return TextHandleUndo(undo);
3719 }
3720
3721
3722 bool LyXText::TextHandleUndo(Undo * undo)
3723 {
3724         // returns false if no undo possible
3725         bool result = false;
3726         if (undo) {
3727                 LyXParagraph * before =
3728                         GetParFromID(undo->number_of_before_par); 
3729                 LyXParagraph * behind =
3730                         GetParFromID(undo->number_of_behind_par); 
3731                 LyXParagraph * tmppar;
3732                 LyXParagraph * tmppar2;
3733                 LyXParagraph * endpar;
3734                 LyXParagraph * tmppar5;
3735     
3736                 // if there's no before take the beginning
3737                 // of the document for redoing
3738                 if (!before)
3739                         SetCursorIntern(FirstParagraph(), 0);
3740
3741                 // replace the paragraphs with the undo informations
3742
3743                 LyXParagraph * tmppar3 = undo->par;
3744                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3745                 LyXParagraph * tmppar4 = tmppar3;
3746                 if (tmppar4){
3747                         while (tmppar4->next)
3748                                 tmppar4 = tmppar4->next;
3749                 } // get last undo par
3750     
3751                 // now remove the old text if there is any
3752                 if (before != behind || (!behind && !before)){
3753                         if (before)
3754                                 tmppar5 = before->next;
3755                         else
3756                                 tmppar5 = buffer->paragraph;
3757                         tmppar2 = tmppar3;
3758                         while (tmppar5 && tmppar5 != behind){
3759                                 tmppar = tmppar5;
3760                                 tmppar5 = tmppar5->next;
3761                                 // a memory optimization for edit: Only layout information
3762                                 // is stored in the undo. So restore the text informations.
3763                                 if (undo->kind == Undo::EDIT) {
3764                                         tmppar2->setContentsFromPar(tmppar);
3765                                         tmppar->clearContents();
3766                                         tmppar2 = tmppar2->next;
3767                                 }
3768                         }
3769                 }
3770     
3771                 // put the new stuff in the list if there is one
3772                 if (tmppar3){
3773                         if (before)
3774                                 before->next = tmppar3;
3775                         else
3776                                 buffer->paragraph = tmppar3;
3777                         tmppar3->previous = before;
3778                 }
3779                 else {
3780                         if (!before)
3781                                 buffer->paragraph = behind;
3782                 }
3783                 if (tmppar4) {
3784                         tmppar4->next = behind;
3785                         if (behind)
3786                                 behind->previous = tmppar4;
3787                 }
3788     
3789     
3790                 // Set the cursor for redoing
3791                 if (before) {
3792                         SetCursorIntern(before->FirstSelfrowPar(), 0);
3793                         // check wether before points to a closed float and open it if necessary
3794                         if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3795                             && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3796                                 tmppar4 = before;
3797                                 while (tmppar4->previous && 
3798                                        tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3799                                         tmppar4 = tmppar4->previous;
3800                                 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3801                                         tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3802                                         tmppar4 = tmppar4->next;
3803                                 }
3804                         }
3805                 }
3806     
3807                 // open a cosed footnote at the end if necessary
3808                 if (behind && behind->previous && 
3809                     behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3810                     behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3811                         while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3812                                 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3813                                 behind = behind->next;
3814                         }
3815                 }
3816     
3817                 // calculate the endpar for redoing the paragraphs.
3818                 if (behind){
3819                         if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3820                                 endpar = behind->LastPhysicalPar()->Next();
3821                         else
3822                                 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3823                 }
3824                 else
3825                         endpar = behind;
3826     
3827                 tmppar = GetParFromID(undo->number_of_cursor_par);
3828                 RedoParagraphs(cursor, endpar); 
3829                 if (tmppar){
3830                         SetCursorIntern(tmppar, undo->cursor_pos);
3831                         UpdateCounters(cursor.row);
3832                 }
3833                 result = true;
3834                 delete undo;
3835         }
3836         FinishUndo();
3837         return result;
3838 }
3839
3840
3841 void LyXText::FinishUndo()
3842 {
3843         // makes sure the next operation will be stored
3844         undo_finished = True;
3845 }
3846
3847
3848 void LyXText::FreezeUndo()
3849 {
3850         // this is dangerous and for internal use only
3851         undo_frozen = True;
3852 }
3853
3854
3855 void LyXText::UnFreezeUndo()
3856 {
3857         // this is dangerous and for internal use only
3858         undo_frozen = false;
3859 }
3860
3861
3862 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3863                       LyXParagraph const * behind) const
3864 {
3865         if (!undo_frozen)
3866                 buffer->undostack.push(CreateUndo(kind, before, behind));
3867         buffer->redostack.clear();
3868 }
3869
3870
3871 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3872                       LyXParagraph const * behind)
3873 {
3874         buffer->redostack.push(CreateUndo(kind, before, behind));
3875 }
3876
3877
3878 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3879                           LyXParagraph const * behind) const
3880 {
3881         int before_number = -1;
3882         int behind_number = -1;
3883         if (before)
3884                 before_number = before->id();
3885         if (behind)
3886                 behind_number = behind->id();
3887         // Undo::EDIT  and Undo::FINISH are
3888         // always finished. (no overlapping there)
3889         // overlapping only with insert and delete inside one paragraph: 
3890         // Nobody wants all removed  character
3891         // appear one by one when undoing. 
3892         // EDIT is special since only layout information, not the
3893         // contents of a paragaph are stored.
3894         if (!undo_finished && kind != Undo::EDIT && 
3895             kind != Undo::FINISH){
3896                 // check wether storing is needed
3897                 if (!buffer->undostack.empty() && 
3898                     buffer->undostack.top()->kind == kind &&
3899                     buffer->undostack.top()->number_of_before_par ==  before_number &&
3900                     buffer->undostack.top()->number_of_behind_par ==  behind_number ){
3901                         // no undo needed
3902                         return 0;
3903                 }
3904         }
3905         // create a new Undo
3906         LyXParagraph * undopar;
3907         LyXParagraph * tmppar;
3908         LyXParagraph * tmppar2;
3909
3910         LyXParagraph * start = 0;
3911         LyXParagraph * end = 0;
3912   
3913         if (before)
3914                 start = before->next;
3915         else
3916                 start = FirstParagraph();
3917         if (behind)
3918                 end = behind->previous;
3919         else {
3920                 end = FirstParagraph();
3921                 while (end->next)
3922                         end = end->next;
3923         }
3924
3925         if (start && end
3926             && start != end->next
3927             && (before != behind || (!before && !behind))) {
3928                 tmppar = start;
3929                 tmppar2 = tmppar->Clone();
3930                 tmppar2->id(tmppar->id());
3931
3932                 // a memory optimization: Just store the layout information
3933                 // when only edit
3934                 if (kind == Undo::EDIT){
3935                         //tmppar2->text.clear();
3936                         tmppar2->clearContents();
3937                 }
3938
3939                 undopar = tmppar2;
3940   
3941                 while (tmppar != end && tmppar->next) {
3942                         tmppar = tmppar->next;
3943                         tmppar2->next = tmppar->Clone();
3944                         tmppar2->next->id(tmppar->id());
3945                         // a memory optimization: Just store the layout
3946                         // information when only edit
3947                         if (kind == Undo::EDIT){
3948                                 //tmppar2->next->text.clear();
3949                                 tmppar2->clearContents();
3950                         }
3951                         tmppar2->next->previous = tmppar2;
3952                         tmppar2 = tmppar2->next;
3953                 }
3954                 tmppar2->next = 0;
3955         } else
3956                 undopar = 0; // nothing to replace (undo of delete maybe)
3957   
3958         int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
3959         int cursor_pos =  cursor.par->PositionInParFromPos(cursor.pos);
3960
3961         Undo * undo = new Undo(kind, 
3962                                before_number, behind_number,  
3963                                cursor_par, cursor_pos, 
3964                                undopar);
3965   
3966         undo_finished = false;
3967         return undo;
3968 }
3969
3970
3971 void LyXText::SetCursorParUndo()
3972 {
3973         SetUndo(Undo::FINISH, 
3974                 cursor.par->ParFromPos(cursor.pos)->previous, 
3975                 cursor.par->ParFromPos(cursor.pos)->next); 
3976 }
3977
3978
3979 void LyXText::RemoveTableRow(LyXCursor * cur) const
3980 {
3981         int cell = -1;
3982         int cell_org = 0;
3983         int ocell = 0;
3984     
3985         // move to the previous row
3986         int cell_act = NumberOfCell(cur->par, cur->pos);
3987         if (cell < 0)
3988                 cell = cell_act;
3989         while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3990                 cur->pos--;
3991         while (cur->pos && 
3992                !cur->par->table->IsFirstCell(cell_act)) {
3993                 cur->pos--;
3994                 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3995                         cur->pos--;
3996                 --cell;
3997                 --cell_act;
3998         }
3999         // now we have to pay attention if the actual table is the
4000         //   main row of TableContRows and if yes to delete all of them
4001         if (!cell_org)
4002                 cell_org = cell;
4003         do {
4004                 ocell = cell;
4005                 // delete up to the next row
4006                 while (cur->pos < cur->par->Last() && 
4007                        (cell_act == ocell
4008                         || !cur->par->table->IsFirstCell(cell_act))) {
4009                         while (cur->pos < cur->par->Last() &&
4010                                !cur->par->IsNewline(cur->pos))
4011                                 cur->par->Erase(cur->pos);
4012                         ++cell;
4013                         ++cell_act;
4014                         if (cur->pos < cur->par->Last())
4015                                 cur->par->Erase(cur->pos);
4016                 }
4017                 if (cur->pos && cur->pos == cur->par->Last()) {
4018                         cur->pos--;
4019                         cur->par->Erase(cur->pos); // no newline at very end!
4020                 }
4021         } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
4022                  !cur->par->table->IsContRow(cell_org) &&
4023                  cur->par->table->IsContRow(cell));
4024         cur->par->table->DeleteRow(cell_org);
4025         return;
4026 }
4027
4028
4029 bool LyXText::IsEmptyTableCell() const
4030 {
4031         LyXParagraph::size_type pos = cursor.pos - 1;
4032         while (pos >= 0 && pos < cursor.par->Last()
4033                && !cursor.par->IsNewline(pos))
4034                 --pos;
4035         return cursor.par->IsNewline(pos + 1);
4036 }
4037
4038
4039 void LyXText::toggleAppendix(){
4040         LyXParagraph * par = cursor.par->FirstPhysicalPar();
4041         bool start = !par->start_of_appendix;
4042
4043         // ensure that we have only one start_of_appendix in this document
4044         LyXParagraph * tmp = FirstParagraph();
4045         for (; tmp; tmp = tmp->next)
4046                 tmp->start_of_appendix = 0;
4047         par->start_of_appendix = start;
4048
4049         // we can set the refreshing parameters now
4050         status = LyXText::NEED_MORE_REFRESH;
4051         refresh_y = 0;
4052         refresh_row = 0; // not needed for full update
4053         UpdateCounters(0);
4054         SetCursor(cursor.par, cursor.pos);
4055 }
4056