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