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