]> git.lyx.org Git - features.git/blob - src/text2.C
Various fixes to Tabular, InsetTabular and InsetText. Fixed left border for
[features.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 "lyxtext.h"
21 #include "LString.h"
22 #include "lyxparagraph.h"
23 #include "insets/inseterror.h"
24 #include "insets/insetbib.h"
25 #include "insets/insetspecialchar.h"
26 #include "insets/insettext.h"
27 #include "insets/insetfloat.h"
28 #include "layout.h"
29 #include "LyXView.h"
30 #include "support/textutils.h"
31 #include "undo.h"
32 #include "buffer.h"
33 #include "bufferparams.h"
34 #include "lyx_gui_misc.h"
35 #include "gettext.h"
36 #include "BufferView.h"
37 #include "LyXView.h"
38 #include "CutAndPaste.h"
39 #include "Painter.h"
40 #include "font.h"
41 #include "debug.h"
42 #include "lyxrc.h"
43 #include "FloatList.h"
44 #include "language.h"
45
46 using std::copy;
47 using std::find;
48 using std::endl;
49 using std::find;
50 using std::pair;
51
52
53 LyXText::LyXText(BufferView * bv)
54 {
55         bv_owner = bv;
56         inset_owner = 0;
57         init();
58 }
59
60
61 LyXText::LyXText(InsetText * inset)
62 {
63         inset_owner = inset;
64         bv_owner = 0;
65         init();
66 }
67
68
69 void LyXText::init()
70 {
71         the_locking_inset = 0;
72         firstrow = 0;
73         lastrow = 0;
74         number_of_rows = 0;
75         refresh_y = 0;
76         height = 0;
77         width = 0;
78         first = 0;
79         status = LyXText::UNCHANGED;
80         // set cursor at the very top position
81         selection = true;           /* these setting is necessary 
82                                        because of the delete-empty-
83                                        paragraph mechanism in
84                                        SetCursor */
85         if (bv_owner) {
86                 LyXParagraph * par = OwnerParagraph();
87                 current_font = GetFont(bv_owner->buffer(), par, 0);
88                 while (par) {
89                         InsertParagraph(bv_owner, par, lastrow);
90                         par = par->next();
91                 }
92                 SetCursor(bv_owner, firstrow->par(), 0);
93         } else
94                 current_font = LyXFont(LyXFont::ALL_SANE);
95
96         sel_cursor = cursor;
97         selection = false;
98         mark_set = false;
99    
100         // no rebreak necessary
101         need_break_row = 0;
102    
103         undo_finished = true;
104         undo_frozen = false;
105
106         // Default layouttype for copy environment type
107         copylayouttype = 0;
108
109 #if 0
110         // Dump all rowinformation:
111         Row * tmprow = firstrow;
112         lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
113         while (tmprow) {
114                 lyxerr << tmprow->baseline() << '\t'
115                        << tmprow->par << '\t'
116                        << tmprow->pos() << '\t'
117                        << tmprow->height << '\t'
118                        << tmprow->ascent_of_text << '\t'
119                        << tmprow->fill << '\n';
120                 tmprow = tmprow->next();
121         }
122         lyxerr.flush();
123 #endif
124 }
125
126
127 void LyXText::init(BufferView * bview)
128 {
129         if (firstrow)
130                 return;
131
132         LyXParagraph * par = OwnerParagraph();
133         current_font = GetFont(bview->buffer(), par, 0);
134         while (par) {
135                 InsertParagraph(bview, par, lastrow);
136                 par = par->next();
137         }
138         SetCursorIntern(bview, firstrow->par(), 0);
139         sel_cursor = cursor;
140 #if 0
141         printf("TP = %x\n",inset_owner->owner());
142         // Dump all rowinformation:
143         Row * tmprow = firstrow;
144         lyxerr << "Width = " << width << endl;
145         lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
146         while (tmprow) {
147                 lyxerr << tmprow->baseline() << '\t'
148                        << tmprow->par() << '\t'
149                        << tmprow->pos() << '\t'
150                        << tmprow->height() << '\t'
151                        << tmprow->ascent_of_text() << '\t'
152                        << tmprow->fill() << '\n';
153                 tmprow = tmprow->next();
154         }
155         lyxerr.flush();
156 #endif
157 }
158
159 LyXText::~LyXText()
160 {
161         // Delete all rows, this does not touch the paragraphs!
162         Row * tmprow = firstrow;
163         while (firstrow) {
164                 tmprow = firstrow->next();
165                 delete firstrow;
166                 firstrow = tmprow;
167         }
168 }
169
170
171 // Gets the fully instantiated font at a given position in a paragraph
172 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
173 // The difference is that this one is used for displaying, and thus we
174 // are allowed to make cosmetic improvements. For instance make footnotes
175 // smaller. (Asger)
176 // If position is -1, we get the layout font of the paragraph.
177 // If position is -2, we get the font of the manual label of the paragraph.
178 LyXFont const LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
179                          LyXParagraph::size_type pos) const
180 {
181         LyXLayout const & layout = 
182                 textclasslist.Style(buf->params.textclass, par->GetLayout());
183
184         char par_depth = par->GetDepth();
185         // We specialize the 95% common case:
186         if (!par_depth) {
187                 if (pos >= 0){
188                         // 95% goes here
189                         if (layout.labeltype == LABEL_MANUAL
190                             && pos < BeginningOfMainBody(buf, par)) {
191                                 // 1% goes here
192                                 LyXFont f = par->GetFontSettings(buf->params,
193                                                                  pos);
194                                 return f.realize(layout.reslabelfont);
195                         } else {
196                                 LyXFont f = par->GetFontSettings(buf->params, pos);
197                                 return f.realize(layout.resfont);
198                         }
199                         
200                 } else {
201                         // 5% goes here.
202                         // process layoutfont for pos == -1 and labelfont for pos < -1
203                         if (pos == -1)
204                                 return layout.resfont;
205                         else
206                                 return layout.reslabelfont;
207                 }
208         }
209
210         // The uncommon case need not be optimized as much
211
212         LyXFont layoutfont, tmpfont;
213
214         if (pos >= 0){
215                 // 95% goes here
216                 if (pos < BeginningOfMainBody(buf, par)) {
217                         // 1% goes here
218                         layoutfont = layout.labelfont;
219                 } else {
220                         // 99% goes here
221                         layoutfont = layout.font;
222                 }
223                 tmpfont = par->GetFontSettings(buf->params, pos);
224                 tmpfont.realize(layoutfont);
225         } else {
226                 // 5% goes here.
227                 // process layoutfont for pos == -1 and labelfont for pos < -1
228                 if (pos == -1)
229                         tmpfont = layout.font;
230                 else
231                         tmpfont = layout.labelfont;
232         }
233
234         // Resolve against environment font information
235         while (par && par_depth && !tmpfont.resolved()) {
236                 par = par->DepthHook(par_depth - 1);
237                 if (par) {
238                         tmpfont.realize(textclasslist.
239                                         Style(buf->params.textclass,
240                                               par->GetLayout()).font);
241                         par_depth = par->GetDepth();
242                 }
243         }
244
245         tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
246
247         return tmpfont;
248 }
249
250
251 void LyXText::SetCharFont(BufferView * bv, LyXParagraph * par,
252                           LyXParagraph::size_type pos, LyXFont const & fnt,
253                           bool toggleall)
254 {
255         Buffer const * buf = bv->buffer();
256         LyXFont font = GetFont(buf, par, pos);
257         font.update(fnt, buf->params.language, toggleall);
258         // Let the insets convert their font
259         if (par->GetChar(pos) == LyXParagraph::META_INSET) {
260                 Inset * inset = par->GetInset(pos);
261                 if (inset) {
262                         if (inset->Editable()==Inset::HIGHLY_EDITABLE) {
263                                 UpdatableInset * uinset = static_cast<UpdatableInset *>(inset);
264                                 uinset->SetFont(bv, fnt, toggleall, true);
265                         }
266                         font = inset->ConvertFont(font);
267                 }
268         }
269
270         LyXLayout const & layout =
271                 textclasslist.Style(buf->params.textclass,
272                                     par->GetLayout());
273
274         // Get concrete layout font to reduce against
275         LyXFont layoutfont;
276
277         if (pos < BeginningOfMainBody(buf, par))
278                 layoutfont = layout.labelfont;
279         else
280                 layoutfont = layout.font;
281
282         // Realize against environment font information
283         if (par->GetDepth()){
284                 LyXParagraph * tp = par;
285                 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
286                         tp = tp->DepthHook(tp->GetDepth()-1);
287                         if (tp)
288                                 layoutfont.realize(textclasslist.
289                                                 Style(buf->params.textclass,
290                                                       tp->GetLayout()).font);
291                 }
292         }
293
294         layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
295
296         // Now, reduce font against full layout font
297         font.reduce(layoutfont);
298
299         par->SetFont(pos, font);
300 }
301
302 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
303                           LyXParagraph::size_type pos, LyXFont const & fnt)
304 {
305         LyXFont font(fnt);
306         // Let the insets convert their font
307         if (par->GetChar(pos) == LyXParagraph::META_INSET) {
308                 font = par->GetInset(pos)->ConvertFont(font);
309         }
310
311         LyXLayout const & layout =
312                 textclasslist.Style(buf->params.textclass,
313                                     par->GetLayout());
314
315         // Get concrete layout font to reduce against
316         LyXFont layoutfont;
317
318         if (pos < BeginningOfMainBody(buf, par))
319                 layoutfont = layout.labelfont;
320         else
321                 layoutfont = layout.font;
322
323         // Realize against environment font information
324         if (par->GetDepth()){
325                 LyXParagraph * tp = par;
326                 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
327                         tp = tp->DepthHook(tp->GetDepth()-1);
328                         if (tp)
329                                 layoutfont.realize(textclasslist.
330                                                 Style(buf->params.textclass,
331                                                       tp->GetLayout()).font);
332                 }
333         }
334
335         layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
336
337         // Now, reduce font against full layout font
338         font.reduce(layoutfont);
339
340         par->SetFont(pos, font);
341 }
342
343
344 /* inserts a new row behind the specified row, increments
345  * the touched counters */
346 void LyXText::InsertRow(Row * row, LyXParagraph * par,
347                         LyXParagraph::size_type pos) const
348 {
349         Row * tmprow = new Row;
350         if (!row) {
351                 tmprow->previous(0);
352                 tmprow->next(firstrow);
353                 firstrow = tmprow;
354         } else {
355                 tmprow->previous(row);
356                 tmprow->next(row->next());
357                 row->next(tmprow);
358         }
359    
360         if (tmprow->next())
361                 tmprow->next()->previous(tmprow);
362    
363         if (tmprow->previous())
364                 tmprow->previous()->next(tmprow);
365    
366    
367         tmprow->par(par);
368         tmprow->pos(pos);
369
370         if (row == lastrow)
371                 lastrow = tmprow;
372         ++number_of_rows; // one more row
373 }
374
375
376 // removes the row and reset the touched counters
377 void LyXText::RemoveRow(Row * row) const
378 {
379         /* this must not happen before the currentrow for clear reasons.
380            so the trick is just to set the current row onto the previous
381            row of this row */
382         int unused_y;
383         GetRow(row->par(), row->pos(), unused_y);
384    
385         if (row->next())
386                 row->next()->previous(row->previous());
387         if (!row->previous()) {
388                 firstrow = row->next();
389         } else  {
390                 row->previous()->next(row->next());
391         }
392         if (row == lastrow)
393                 lastrow = row->previous();
394    
395         height -= row->height(); // the text becomes smaller
396    
397         delete row;
398         --number_of_rows;       // one row less
399 }
400
401
402 // remove all following rows of the paragraph of the specified row.
403 void LyXText::RemoveParagraph(Row * row) const
404 {
405         LyXParagraph * tmppar = row->par();
406         row = row->next();
407     
408         Row * tmprow;
409         while (row && row->par() == tmppar) {
410                 tmprow = row->next();
411                 RemoveRow(row);
412                 row = tmprow;
413         }
414 }
415    
416
417 // insert the specified paragraph behind the specified row
418 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
419                               Row * row) const
420 {
421         InsertRow(row, par, 0);        /* insert a new row, starting 
422                                         * at postition 0 */
423
424         SetCounter(bview->buffer(), par);  // set the counters
425    
426         // and now append the whole paragraph behind the new row
427         if (!row) {
428                 firstrow->height(0);
429                 AppendParagraph(bview, firstrow);
430         } else {
431                 row->next()->height(0);
432                 AppendParagraph(bview, row->next());
433         }
434 }
435
436
437 /* used in setlayout */
438 // Asger is not sure we want to do this...
439 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
440                                             LyXParagraph * par)
441 {
442    
443         LyXLayout const & layout =
444                 textclasslist.Style(buf->params.textclass, par->GetLayout());
445
446         LyXFont layoutfont, tmpfont;
447         for (LyXParagraph::size_type pos = 0;
448              pos < par->size(); ++pos) {
449                 if (pos < BeginningOfMainBody(buf, par))
450                         layoutfont = layout.labelfont;
451                 else
452                         layoutfont = layout.font;
453       
454                 tmpfont = par->GetFontSettings(buf->params, pos);
455                 tmpfont.reduce(layoutfont);
456                 par->SetFont(pos, tmpfont);
457         }
458 }
459
460
461 LyXParagraph * LyXText::SetLayout(BufferView * bview,
462                                   LyXCursor & cur, LyXCursor & sstart_cur,
463                                   LyXCursor & send_cur,
464                                   LyXTextClass::size_type layout)
465 {
466         LyXParagraph * endpar = send_cur.par()->next();
467         LyXParagraph * undoendpar = endpar;
468         
469         if (endpar && endpar->GetDepth()) {
470                 while (endpar && endpar->GetDepth()) {
471                         endpar = endpar->next();
472                         undoendpar = endpar;
473                 }
474         } else if (endpar) {
475                 endpar = endpar->next(); // because of parindents etc.
476         }
477         
478         SetUndo(bview->buffer(), Undo::EDIT,
479                 sstart_cur.par()->previous(),
480                 undoendpar);
481         
482         /* ok we have a selection. This is always between sstart_cur
483          * and sel_end cursor */ 
484         cur = sstart_cur;
485         
486         LyXLayout const & lyxlayout =
487                 textclasslist.Style(bview->buffer()->params.textclass, layout);
488         
489         while (cur.par() != send_cur.par()) {
490                 cur.par()->SetLayout(layout);
491                 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
492                 LyXParagraph * fppar = cur.par();
493                 fppar->params.spaceTop(lyxlayout.fill_top ?
494                                        VSpace(VSpace::VFILL)
495                                        : VSpace(VSpace::NONE));
496                 fppar->params.spaceBottom(lyxlayout.fill_bottom ? 
497                                           VSpace(VSpace::VFILL)
498                                           : VSpace(VSpace::NONE));
499                 if (lyxlayout.margintype == MARGIN_MANUAL)
500                         cur.par()->SetLabelWidthString(lyxlayout.labelstring());
501                 if (lyxlayout.labeltype != LABEL_BIBLIO
502                     && fppar->bibkey) {
503                         delete fppar->bibkey;
504                         fppar->bibkey = 0;
505                 }
506                 cur.par(cur.par()->next());
507         }
508         cur.par()->SetLayout(layout);
509         MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
510         LyXParagraph * fppar = cur.par();
511         fppar->params.spaceTop(lyxlayout.fill_top ?
512                                VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
513         fppar->params.spaceBottom(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         return endpar;
523 }
524
525
526 // set layout over selection and make a total rebreak of those paragraphs
527 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
528 {
529         LyXCursor tmpcursor = cursor;  /* store the current cursor  */
530
531         // if there is no selection just set the layout
532         // of the current paragraph  */
533         if (!selection) {
534                 sel_start_cursor = cursor;  // dummy selection
535                 sel_end_cursor = cursor;
536         }
537         LyXParagraph *
538                 endpar = SetLayout(bview, cursor, sel_start_cursor,
539                                    sel_end_cursor, layout);
540         RedoParagraphs(bview, sel_start_cursor, endpar);
541    
542         // we have to reset the selection, because the
543         // geometry could have changed
544         SetCursor(bview, sel_start_cursor.par(),
545                   sel_start_cursor.pos(), false);
546         sel_cursor = cursor;
547         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
548                   false);
549         UpdateCounters(bview, cursor.row());
550         ClearSelection(bview);
551         SetSelection(bview);
552         SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
553 }
554
555
556 // increment depth over selection and
557 // make a total rebreak of those paragraphs
558 void  LyXText::IncDepth(BufferView * bview)
559 {
560         // If there is no selection, just use the current paragraph
561         if (!selection) {
562                 sel_start_cursor = cursor; // dummy selection
563                 sel_end_cursor = cursor;
564         }
565
566         // We end at the next paragraph with depth 0
567         LyXParagraph * endpar = sel_end_cursor.par()->next();
568
569         LyXParagraph * undoendpar = endpar;
570
571         if (endpar && endpar->GetDepth()) {
572                 while (endpar && endpar->GetDepth()) {
573                         endpar = endpar->next();
574                         undoendpar = endpar;
575                 }
576         }
577         else if (endpar) {
578                 endpar = endpar->next(); // because of parindents etc.
579         }
580         
581         SetUndo(bview->buffer(), Undo::EDIT,
582                 sel_start_cursor.par()->previous(),
583                 undoendpar);
584
585         LyXCursor tmpcursor = cursor; // store the current cursor
586
587         // ok we have a selection. This is always between sel_start_cursor
588         // and sel_end cursor
589         cursor = sel_start_cursor;
590    
591         bool anything_changed = false;
592    
593         while (true) {
594                 // NOTE: you can't change the depth of a bibliography entry
595                 if (
596                     textclasslist.Style(bview->buffer()->params.textclass,
597                                       cursor.par()->GetLayout()
598                                      ).labeltype != LABEL_BIBLIO) {
599                         LyXParagraph * prev = cursor.par()->previous();
600
601                         if (prev 
602                             && (prev->GetDepth() - cursor.par()->GetDepth() > 0
603                                 || (prev->GetDepth() == cursor.par()->GetDepth()
604                                     && textclasslist.Style(bview->buffer()->params.textclass,
605                                                       prev->GetLayout()).isEnvironment()))) {
606                                 cursor.par()->params.depth(cursor.par()->params.depth() + 1);
607                                 anything_changed = true;
608                                 }
609                 }
610                 if (cursor.par() == sel_end_cursor.par())
611                        break;
612                 cursor.par(cursor.par()->next());
613         }
614    
615         // if nothing changed set all depth to 0
616         if (!anything_changed) {
617                 cursor = sel_start_cursor;
618                 while (cursor.par() != sel_end_cursor.par()) {
619                         cursor.par()->params.depth(0);
620                         cursor.par(cursor.par()->next());
621                 }
622                 cursor.par()->params.depth(0);
623         }
624    
625         RedoParagraphs(bview, sel_start_cursor, endpar);
626    
627         // we have to reset the selection, because the
628         // geometry could have changed
629         SetCursor(bview, sel_start_cursor.par(),
630                   sel_start_cursor.pos());
631         sel_cursor = cursor;
632         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
633         UpdateCounters(bview, cursor.row());
634         ClearSelection(bview);
635         SetSelection(bview);
636         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
637 }
638
639
640 // decrement depth over selection and
641 // make a total rebreak of those paragraphs
642 void  LyXText::DecDepth(BufferView * bview)
643 {
644         // if there is no selection just set the layout
645         // of the current paragraph
646         if (!selection) {
647                 sel_start_cursor = cursor; // dummy selection
648                 sel_end_cursor = cursor;
649         }
650         LyXParagraph * endpar = sel_end_cursor.par()->next();
651         LyXParagraph * undoendpar = endpar;
652
653         if (endpar && endpar->GetDepth()) {
654                 while (endpar && endpar->GetDepth()) {
655                         endpar = endpar->next();
656                         undoendpar = endpar;
657                 }
658         }
659         else if (endpar) {
660                 endpar = endpar->next(); // because of parindents etc.
661         }
662    
663         SetUndo(bview->buffer(), Undo::EDIT,
664                 sel_start_cursor.par()->previous(),
665                 undoendpar);
666
667         LyXCursor tmpcursor = cursor; // store the current cursor
668
669         // ok we have a selection. This is always between sel_start_cursor
670         // and sel_end cursor
671         cursor = sel_start_cursor;
672
673         while (true) {
674                 if (cursor.par()->params.depth())
675                         cursor.par()->params.depth(cursor.par()->params.depth() - 1);
676                 if (cursor.par() == sel_end_cursor.par())
677                         break;
678                 cursor.par(cursor.par()->next());
679         }
680
681         RedoParagraphs(bview, sel_start_cursor, endpar);
682    
683         // we have to reset the selection, because the
684         // geometry could have changed
685         SetCursor(bview, sel_start_cursor.par(),
686                   sel_start_cursor.pos());
687         sel_cursor = cursor;
688         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
689         UpdateCounters(bview, cursor.row());
690         ClearSelection(bview);
691         SetSelection(bview);
692         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
693 }
694
695
696 // set font over selection and make a total rebreak of those paragraphs
697 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
698 {
699         // if there is no selection just set the current_font
700         if (!selection) {
701                 // Determine basis font
702                 LyXFont layoutfont;
703                 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
704                                                        cursor.par()))
705                         layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
706                 else
707                         layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
708                 // Update current font
709                 real_current_font.update(font,
710                                          bview->buffer()->params.language,
711                                          toggleall);
712
713                 // Reduce to implicit settings
714                 current_font = real_current_font;
715                 current_font.reduce(layoutfont);
716                 // And resolve it completely
717                 real_current_font.realize(layoutfont);
718                 return;
719         }
720
721         LyXCursor tmpcursor = cursor; // store the current cursor
722    
723         // ok we have a selection. This is always between sel_start_cursor
724         // and sel_end cursor
725    
726         SetUndo(bview->buffer(), Undo::EDIT,
727                 sel_start_cursor.par()->previous(),
728                 sel_end_cursor.par()->next()); 
729         FreezeUndo();
730         cursor = sel_start_cursor;
731         while (cursor.par() != sel_end_cursor.par() ||
732                (cursor.pos() < sel_end_cursor.pos())) {
733                 if (cursor.pos() < cursor.par()->size()) {
734                         // an open footnote should behave
735                         // like a closed one
736                         SetCharFont(bview, cursor.par(), cursor.pos(), font, toggleall);
737                         cursor.pos(cursor.pos() + 1);
738                 } else {
739                         cursor.pos(0);
740                         cursor.par(cursor.par()->next());
741                 }
742         }
743         UnFreezeUndo();
744    
745         RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->next());
746    
747         // we have to reset the selection, because the
748         // geometry could have changed
749         SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
750         sel_cursor = cursor;
751         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
752         ClearSelection(bview);
753         SetSelection(bview);
754         SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
755                   tmpcursor.boundary());
756 }
757
758
759 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
760 {
761         Row * tmprow = cur.row();
762         int y = cur.y() - tmprow->baseline();
763
764         SetHeightOfRow(bview, tmprow);
765         LyXParagraph * first_phys_par = tmprow->par();
766
767         // find the first row of the paragraph
768         if (first_phys_par != tmprow->par())
769                 while (tmprow->previous()
770                        && tmprow->previous()->par() != first_phys_par) {
771                         tmprow = tmprow->previous();
772                         y -= tmprow->height();
773                         SetHeightOfRow(bview, tmprow);
774                 }
775         while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
776                 tmprow = tmprow->previous();
777                 y -= tmprow->height();
778                 SetHeightOfRow(bview, tmprow);
779         }
780         
781         // we can set the refreshing parameters now
782         status = LyXText::NEED_MORE_REFRESH;
783         refresh_y = y;
784         refresh_row = tmprow;
785         SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
786 }
787
788
789 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
790 {
791         Row * tmprow = cur.row();
792    
793         int y = cur.y() - tmprow->baseline();
794         SetHeightOfRow(bview, tmprow);
795         LyXParagraph * first_phys_par = tmprow->par();
796
797         // find the first row of the paragraph
798         if (first_phys_par != tmprow->par())
799                 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par)  {
800                         tmprow = tmprow->previous();
801                         y -= tmprow->height();
802                 }
803         while (tmprow->previous() && tmprow->previous()->par() == first_phys_par)  {
804                 tmprow = tmprow->previous();
805                 y -= tmprow->height();
806         }
807    
808         // we can set the refreshing parameters now
809         if (status == LyXText::UNCHANGED || y < refresh_y) {
810                 refresh_y = y;
811                 refresh_row = tmprow;
812         }
813         status = LyXText::NEED_MORE_REFRESH;
814         SetCursor(bview, cur.par(), cur.pos());
815 }
816
817
818 /* deletes and inserts again all paragaphs between the cursor
819 * and the specified par 
820 * This function is needed after SetLayout and SetFont etc. */
821 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
822                              LyXParagraph const * endpar) const
823 {
824         Row * tmprow2;
825         LyXParagraph * tmppar = 0, * first_phys_par = 0;
826    
827         Row * tmprow = cur.row();
828    
829         int y = cur.y() - tmprow->baseline();
830    
831         if (!tmprow->previous()){
832                 first_phys_par = FirstParagraph();   // a trick/hack for UNDO
833         } else {
834                 first_phys_par = tmprow->par();
835                 // find the first row of the paragraph
836                 if (first_phys_par != tmprow->par())
837                         while (tmprow->previous() &&
838                                (tmprow->previous()->par() != first_phys_par)) {
839                                 tmprow = tmprow->previous();
840                                 y -= tmprow->height();
841                         }
842                 while (tmprow->previous()
843                        && tmprow->previous()->par() == first_phys_par) {
844                         tmprow = tmprow->previous();
845                         y -= tmprow->height();
846                 }
847         }
848    
849         // we can set the refreshing parameters now
850         status = LyXText::NEED_MORE_REFRESH;
851         refresh_y = y;
852         refresh_row = tmprow->previous();        /* the real refresh row will
853                                             be deleted, so I store
854                                             the previous here */ 
855         // remove it
856         if (tmprow->next())
857                 tmppar = tmprow->next()->par();
858         else
859                 tmppar = 0;
860         while (tmppar != endpar) {
861                 RemoveRow(tmprow->next());
862                 if (tmprow->next())
863                         tmppar = tmprow->next()->par();
864                 else
865                         tmppar = 0;
866         }  
867    
868         // remove the first one
869         tmprow2 = tmprow;     /* this is because tmprow->previous()
870                                  can be 0 */
871         tmprow = tmprow->previous();
872         RemoveRow(tmprow2);
873    
874         tmppar = first_phys_par;
875
876         do {
877                 if (tmppar) {
878                         InsertParagraph(bview, tmppar, tmprow);
879                         if (!tmprow)
880                                 tmprow = firstrow;
881                         while (tmprow->next() && tmprow->next()->par() == tmppar)
882                                 tmprow = tmprow->next();
883                         tmppar = tmppar->next();
884                 }
885         } while (tmppar != endpar);
886    
887         // this is because of layout changes
888         if (refresh_row) {
889                 refresh_y -= refresh_row->height();
890                 SetHeightOfRow(bview, refresh_row);   
891         } else {
892                 refresh_row = firstrow;
893                 refresh_y = 0;
894                 SetHeightOfRow(bview, refresh_row);   
895         }
896    
897         if (tmprow && tmprow->next())
898                 SetHeightOfRow(bview, tmprow->next());
899 }
900
901
902 bool LyXText::FullRebreak(BufferView * bview)
903 {
904         if (!firstrow) {
905                 init(bview);
906                 return true;
907         }
908         if (need_break_row) {
909                 BreakAgain(bview, need_break_row);
910                 need_break_row = 0;
911                 return true;
912         }
913         return false;
914 }
915
916
917 /* important for the screen */
918
919
920 /* the cursor set functions have a special mechanism. When they
921  * realize, that you left an empty paragraph, they will delete it.
922  * They also delete the corresponding row */
923    
924 // need the selection cursor:
925 void LyXText::SetSelection(BufferView * bview)
926 {
927         const bool lsel = selection;
928
929         if (!selection) {
930                 last_sel_cursor = sel_cursor;
931                 sel_start_cursor = sel_cursor;
932                 sel_end_cursor = sel_cursor;
933         }
934    
935         selection = true;
936    
937         // first the toggling area
938         if (cursor.y() < last_sel_cursor.y()
939             || (cursor.y() == last_sel_cursor.y()
940              && cursor.x() < last_sel_cursor.x())) {
941                 toggle_end_cursor = last_sel_cursor;
942                 toggle_cursor = cursor;
943         } else {
944                 toggle_end_cursor = cursor;
945                 toggle_cursor = last_sel_cursor;
946         }
947    
948         last_sel_cursor = cursor;
949    
950         // and now the whole selection
951
952         if (sel_cursor.par() == cursor.par())
953            if (sel_cursor.pos() < cursor.pos()) {
954                 sel_end_cursor = cursor;
955                 sel_start_cursor = sel_cursor;
956         } else {
957                 sel_end_cursor = sel_cursor; 
958                 sel_start_cursor = cursor;
959         }
960         else if (sel_cursor.y() < cursor.y() ||
961             (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
962                 sel_end_cursor = cursor;
963                 sel_start_cursor = sel_cursor;
964         }
965         else {
966                 sel_end_cursor = sel_cursor; 
967                 sel_start_cursor = cursor;
968         }
969    
970         // a selection with no contents is not a selection
971         if (sel_start_cursor.par() == sel_end_cursor.par() && 
972             sel_start_cursor.pos() == sel_end_cursor.pos())
973                 selection = false;
974
975         if (inset_owner && (selection || lsel))
976                 inset_owner->SetUpdateStatus(bview, InsetText::SELECTION);
977 }
978
979
980 string const LyXText::selectionAsString(Buffer const * buffer) const
981 {
982         if (!selection) return string();
983         string result;
984         
985         // Special handling if the whole selection is within one paragraph
986         if (sel_start_cursor.par() == sel_end_cursor.par()) {
987                 result += sel_start_cursor.par()->String(buffer,
988                                                          sel_start_cursor.pos(),
989                                                          sel_end_cursor.pos());
990                 return result;
991         }
992         
993         // The selection spans more than one paragraph
994
995         // First paragraph in selection
996         result += sel_start_cursor.par()->String(buffer,
997                                                  sel_start_cursor.pos(),
998                                                  sel_start_cursor.par()->size())
999                 + "\n\n";
1000         
1001         // The paragraphs in between (if any)
1002         LyXCursor tmpcur(sel_start_cursor);
1003         tmpcur.par(tmpcur.par()->next());
1004         while (tmpcur.par() != sel_end_cursor.par()) {
1005                 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->size()) + "\n\n";
1006                 tmpcur.par(tmpcur.par()->next()); // Or NextAfterFootnote??
1007         }
1008
1009         // Last paragraph in selection
1010         result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1011         
1012         return result;
1013 }
1014
1015
1016 void LyXText::ClearSelection(BufferView * /*bview*/) const
1017 {
1018         selection = false;
1019         mark_set = false;
1020         sel_end_cursor = sel_start_cursor = cursor;
1021 }
1022
1023
1024 void LyXText::CursorHome(BufferView * bview) const
1025 {
1026         SetCursor(bview, cursor.par(), cursor.row()->pos());
1027 }
1028
1029
1030 void LyXText::CursorEnd(BufferView * bview) const
1031 {
1032         if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1033                 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1034         else {
1035                 if (cursor.par()->size() &&
1036                     (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1037                      || cursor.par()->IsNewline(RowLast(cursor.row()))))
1038                         SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1039                 else
1040                         SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1041         }
1042 }
1043
1044
1045 void LyXText::CursorTop(BufferView * bview) const
1046 {
1047         while (cursor.par()->previous())
1048                 cursor.par(cursor.par()->previous());
1049         SetCursor(bview, cursor.par(), 0);
1050 }
1051
1052
1053 void LyXText::CursorBottom(BufferView * bview) const
1054 {
1055         while (cursor.par()->next())
1056                 cursor.par(cursor.par()->next());
1057         SetCursor(bview, cursor.par(), cursor.par()->size());
1058 }
1059    
1060    
1061 void LyXText::ToggleFree(BufferView * bview,
1062                          LyXFont const & font, bool toggleall)
1063 {
1064         // If the mask is completely neutral, tell user
1065         if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1066                 // Could only happen with user style
1067                 bview->owner()->message(_("No font change defined. Use Character under the Layout menu to define font change."));
1068                 return;
1069         }
1070
1071         // Try implicit word selection
1072         // If there is a change in the language the implicit word selection 
1073         // is disabled.
1074         LyXCursor resetCursor = cursor;
1075         bool implicitSelection = (font.language() == ignore_language
1076                                   && font.number() == LyXFont::IGNORE)
1077                 ? SelectWordWhenUnderCursor(bview) : false;
1078
1079         // Set font
1080         SetFont(bview, font, toggleall);
1081
1082         /* Implicit selections are cleared afterwards and cursor is set to the
1083            original position. */
1084         if (implicitSelection) {
1085                 ClearSelection(bview);
1086                 cursor = resetCursor;
1087                 SetCursor(bview, cursor.par(), cursor.pos());
1088                 sel_cursor = cursor;
1089         }
1090         if (inset_owner)
1091                 inset_owner->SetUpdateStatus(bview, InsetText::CURSOR_PAR);
1092 }
1093
1094
1095 LyXParagraph::size_type
1096 LyXText::BeginningOfMainBody(Buffer const * buf,
1097                              LyXParagraph const * par) const
1098 {
1099         if (textclasslist.Style(buf->params.textclass,
1100                                 par->GetLayout()).labeltype != LABEL_MANUAL)
1101                 return 0;
1102         else
1103                 return par->BeginningOfMainBody();
1104 }
1105
1106
1107 /* the DTP switches for paragraphs. LyX will store them in the 
1108 * first physicla paragraph. When a paragraph is broken, the top settings 
1109 * rest, the bottom settings are given to the new one. So I can make shure, 
1110 * they do not duplicate themself and you cannnot make dirty things with 
1111 * them!  */ 
1112
1113 void LyXText::SetParagraph(BufferView * bview,
1114                            bool line_top, bool line_bottom,
1115                            bool pagebreak_top, bool pagebreak_bottom,
1116                            VSpace const & space_top,
1117                            VSpace const & space_bottom,
1118                            LyXAlignment align, 
1119                            string labelwidthstring,
1120                            bool noindent) 
1121 {
1122         LyXCursor tmpcursor = cursor;
1123         if (!selection) {
1124                 sel_start_cursor = cursor;
1125                 sel_end_cursor = cursor;
1126         }
1127
1128         // make sure that the depth behind the selection are restored, too
1129         LyXParagraph * endpar = sel_end_cursor.par()->next();
1130         LyXParagraph * undoendpar = endpar;
1131
1132         if (endpar && endpar->GetDepth()) {
1133                 while (endpar && endpar->GetDepth()) {
1134                         endpar = endpar->next();
1135                         undoendpar = endpar;
1136                 }
1137         }
1138         else if (endpar) {
1139                 endpar = endpar->next(); // because of parindents etc.
1140         }
1141    
1142         SetUndo(bview->buffer(), Undo::EDIT,
1143                 sel_start_cursor.par()->previous(),
1144                 undoendpar);
1145
1146         
1147         LyXParagraph * tmppar = sel_end_cursor.par();
1148         while (tmppar != sel_start_cursor.par()->previous()) {
1149                 SetCursor(bview, tmppar, 0);
1150                 status = LyXText::NEED_MORE_REFRESH;
1151                 refresh_row = cursor.row();
1152                 refresh_y = cursor.y() - cursor.row()->baseline();
1153                         cursor.par()->params.lineTop(line_top);
1154                         cursor.par()->params.lineBottom(line_bottom);
1155                         cursor.par()->params.pagebreakTop(pagebreak_top);
1156                         cursor.par()->params.pagebreakBottom(pagebreak_bottom);
1157                         cursor.par()->params.spaceTop(space_top);
1158                         cursor.par()->params.spaceBottom(space_bottom);
1159                         // does the layout allow the new alignment?
1160                         if (align == LYX_ALIGN_LAYOUT)
1161                                 align = textclasslist
1162                                         .Style(bview->buffer()->params.textclass,
1163                                                cursor.par()->GetLayout()).align;
1164                         if (align & textclasslist
1165                             .Style(bview->buffer()->params.textclass,
1166                                    cursor.par()->GetLayout()).alignpossible) {
1167                                 if (align == textclasslist
1168                                     .Style(bview->buffer()->params.textclass,
1169                                            cursor.par()->GetLayout()).align)
1170                                         cursor.par()->params.align(LYX_ALIGN_LAYOUT);
1171                                 else
1172                                         cursor.par()->params.align(align);
1173                         }
1174                         cursor.par()->SetLabelWidthString(labelwidthstring);
1175                         cursor.par()->params.noindent(noindent);
1176                 tmppar = cursor.par()->previous();
1177         }
1178         
1179         RedoParagraphs(bview, sel_start_cursor, endpar);
1180         
1181         ClearSelection(bview);
1182         SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1183         sel_cursor = cursor;
1184         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1185         SetSelection(bview);
1186         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1187         if (inset_owner)
1188             bview->updateInset(inset_owner, true);
1189 }
1190
1191
1192 char loweralphaCounter(int n)
1193 {
1194         if (n < 1 || n > 26)
1195                 return '?';
1196         else
1197                 return 'a' + n - 1;
1198 }
1199
1200
1201 namespace {
1202
1203 inline
1204 char alphaCounter(int n)
1205 {
1206         if (n < 1 || n > 26)
1207                 return '?';
1208         else
1209                 return 'A' + n - 1;
1210 }
1211
1212
1213 inline
1214 char hebrewCounter(int n)
1215 {
1216         static const char hebrew[22] = {
1217                 'à', 'á', 'â', 'ã', 'ä', 'Ã¥', 'æ', 'ç', 'è',
1218                 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö', 
1219                 '÷', 'ø', 'ù', 'ú'
1220         };
1221         if (n < 1 || n > 22)
1222                 return '?';
1223         else
1224                 return hebrew[n-1];
1225 }
1226
1227
1228 inline
1229 string const romanCounter(int n)
1230 {
1231         static char const * roman[20] = {
1232                 "i",   "ii",  "iii", "iv", "v",
1233                 "vi",  "vii", "viii", "ix", "x",
1234                 "xi",  "xii", "xiii", "xiv", "xv",
1235                 "xvi", "xvii", "xviii", "xix", "xx"
1236         };
1237         if (n < 1 || n > 20)
1238                 return "??";
1239         else
1240                 return roman[n-1];
1241 }
1242
1243 } // namespace anon
1244
1245
1246 // set the counter of a paragraph. This includes the labels
1247 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1248 {
1249         LyXLayout const & layout =
1250                 textclasslist.Style(buf->params.textclass, 
1251                                     par->GetLayout());
1252
1253         LyXTextClass const & textclass =
1254                 textclasslist.TextClass(buf->params.textclass);
1255
1256         /* copy the prev-counters to this one, unless this is the start of a 
1257            footnote or of a bibliography or the very first paragraph */
1258         if (par->previous()
1259             && !(textclasslist.Style(buf->params.textclass,
1260                                 par->previous()->GetLayout()
1261                                 ).labeltype != LABEL_BIBLIO
1262                  && layout.labeltype == LABEL_BIBLIO)) {
1263                 for (int i = 0; i < 10; ++i) {
1264                         par->setCounter(i, par->previous()->GetFirstCounter(i));
1265                 }
1266                 par->params.appendix(par->previous()->params.appendix());
1267                 if (!par->params.appendix() && par->params.startOfAppendix()) {
1268                   par->params.appendix(true);
1269                   for (int i = 0; i < 10; ++i) {
1270                     par->setCounter(i, 0);
1271                   }  
1272                 }
1273                 par->enumdepth = par->previous()->enumdepth;
1274                 par->itemdepth = par->previous()->itemdepth;
1275         } else {
1276                 for (int i = 0; i < 10; ++i) {
1277                         par->setCounter(i, 0);
1278                 }  
1279                 par->params.appendix(par->params.startOfAppendix());
1280                 par->enumdepth = 0;
1281                 par->itemdepth = 0;
1282         }
1283
1284         /* Maybe we have to increment the enumeration depth.
1285          * BUT, enumeration in a footnote is considered in isolation from its
1286          *      surrounding paragraph so don't increment if this is the
1287          *      first line of the footnote
1288          * AND, bibliographies can't have their depth changed ie. they
1289          *      are always of depth 0
1290          */
1291         if (par->previous()
1292             && par->previous()->GetDepth() < par->GetDepth()
1293             && textclasslist.Style(buf->params.textclass,
1294                               par->previous()->GetLayout()
1295                              ).labeltype == LABEL_COUNTER_ENUMI
1296             && par->enumdepth < 3
1297             && layout.labeltype != LABEL_BIBLIO) {
1298                 par->enumdepth++;
1299         }
1300
1301         /* Maybe we have to decrement the enumeration depth, see note above */
1302         if (par->previous()
1303             && par->previous()->GetDepth() > par->GetDepth()
1304             && layout.labeltype != LABEL_BIBLIO) {
1305                 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1306                 par->setCounter(6 + par->enumdepth,
1307                         par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1308                 /* reset the counters.
1309                  * A depth change is like a breaking layout
1310                  */
1311                 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1312                         par->setCounter(i, 0);
1313         }
1314    
1315         if (!par->params.labelString().empty()) {
1316                 par->params.labelString(string());
1317         }
1318    
1319         if (layout.margintype == MARGIN_MANUAL) {
1320                 if (par->params.labelWidthString().empty()) {
1321                         par->SetLabelWidthString(layout.labelstring());
1322                 }
1323         } else {
1324                 par->SetLabelWidthString(string());
1325         }
1326    
1327         /* is it a layout that has an automatic label ? */ 
1328         if (layout.labeltype >=  LABEL_COUNTER_CHAPTER) {
1329       
1330                 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1331                 if (i >= 0 && i<= buf->params.secnumdepth) {
1332                         par->incCounter(i);     // increment the counter  
1333          
1334                         // Is there a label? Useful for Chapter layout
1335                         if (!par->params.appendix()) {
1336                                 if (!layout.labelstring().empty())
1337                                         par->params.labelString(layout.labelstring());
1338                                 else
1339                                         par->params.labelString(string());
1340                         } else {
1341                                 if (!layout.labelstring_appendix().empty())
1342                                         par->params.labelString(layout.labelstring_appendix());
1343                                 else
1344                                         par->params.labelString(string());
1345                         }
1346
1347                         std::ostringstream s;
1348
1349                         if (!par->params.appendix()) {
1350                                 switch (2 * LABEL_COUNTER_CHAPTER -
1351                                         textclass.maxcounter() + i) {
1352                                 case LABEL_COUNTER_CHAPTER:
1353                                         s << par->getCounter(i);
1354                                         break;
1355                                 case LABEL_COUNTER_SECTION:
1356                                         s << par->getCounter(i - 1) << '.'
1357                                            << par->getCounter(i);
1358                                         break;
1359                                 case LABEL_COUNTER_SUBSECTION:
1360                                         s << par->getCounter(i - 2) << '.'
1361                                           << par->getCounter(i - 1) << '.'
1362                                           << par->getCounter(i);
1363                                         break;
1364                                 case LABEL_COUNTER_SUBSUBSECTION:
1365                                         s << par->getCounter(i - 3) << '.'
1366                                           << par->getCounter(i - 2) << '.'
1367                                           << par->getCounter(i - 1) << '.'
1368                                           << par->getCounter(i);
1369                                         
1370                                         break;
1371                                 case LABEL_COUNTER_PARAGRAPH:
1372                                         s << par->getCounter(i - 4) << '.'
1373                                           << par->getCounter(i - 3) << '.'
1374                                           << par->getCounter(i - 2) << '.'
1375                                           << par->getCounter(i - 1) << '.'
1376                                           << par->getCounter(i);
1377                                         break;
1378                                 case LABEL_COUNTER_SUBPARAGRAPH:
1379                                         s << par->getCounter(i - 5) << '.'
1380                                           << par->getCounter(i - 4) << '.'
1381                                           << par->getCounter(i - 3) << '.'
1382                                           << par->getCounter(i - 2) << '.'
1383                                           << par->getCounter(i - 1) << '.'
1384                                           << par->getCounter(i);
1385
1386                                         break;
1387                                 default:
1388                                         // Can this ever be reached? And in the
1389                                         // case it is, how can this be correct?
1390                                         // (Lgb)
1391                                         s << par->getCounter(i) << '.';
1392                                         break;
1393                                 }
1394                         } else { // appendix
1395                                 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1396                                 case LABEL_COUNTER_CHAPTER:
1397                                         if (par->isRightToLeftPar(buf->params))
1398                                                 s << hebrewCounter(par->getCounter(i));
1399                                         else
1400                                                 s << alphaCounter(par->getCounter(i));
1401                                         break;
1402                                 case LABEL_COUNTER_SECTION:
1403                                         if (par->isRightToLeftPar(buf->params))
1404                                                 s << hebrewCounter(par->getCounter(i - 1));
1405                                         else
1406                                                 s << alphaCounter(par->getCounter(i - 1));
1407
1408                                         s << '.'
1409                                           << par->getCounter(i);
1410
1411                                         break;
1412                                 case LABEL_COUNTER_SUBSECTION:
1413                                         if (par->isRightToLeftPar(buf->params))
1414                                                 s << hebrewCounter(par->getCounter(i - 2));
1415                                         else
1416                                                 s << alphaCounter(par->getCounter(i - 2));
1417
1418                                         s << '.'
1419                                           << par->getCounter(i-1) << '.'
1420                                           << par->getCounter(i);
1421
1422                                         break;
1423                                 case LABEL_COUNTER_SUBSUBSECTION:
1424                                         if (par->isRightToLeftPar(buf->params))
1425                                                 s << hebrewCounter(par->getCounter(i-3));
1426                                         else
1427                                                 s << alphaCounter(par->getCounter(i-3));
1428
1429                                         s << '.'
1430                                           << par->getCounter(i-2) << '.'
1431                                           << par->getCounter(i-1) << '.'
1432                                           << par->getCounter(i);
1433
1434                                         break;
1435                                 case LABEL_COUNTER_PARAGRAPH:
1436                                         if (par->isRightToLeftPar(buf->params))
1437                                                 s << hebrewCounter(par->getCounter(i-4));
1438                                         else
1439                                                 s << alphaCounter(par->getCounter(i-4));
1440
1441                                         s << '.'
1442                                           << par->getCounter(i-3) << '.'
1443                                           << par->getCounter(i-2) << '.'
1444                                           << par->getCounter(i-1) << '.'
1445                                           << par->getCounter(i);
1446
1447                                         break;
1448                                 case LABEL_COUNTER_SUBPARAGRAPH:
1449                                         if (par->isRightToLeftPar(buf->params))
1450                                                 s << hebrewCounter(par->getCounter(i-5));
1451                                         else
1452                                                 s << alphaCounter(par->getCounter(i-5));
1453
1454                                         s << '.'
1455                                           << par->getCounter(i-4) << '.'
1456                                           << par->getCounter(i-3) << '.'
1457                                           << par->getCounter(i-2) << '.'
1458                                           << par->getCounter(i-1) << '.'
1459                                           << par->getCounter(i);
1460
1461                                         break;
1462                                 default:
1463                                         // Can this ever be reached? And in the
1464                                         // case it is, how can this be correct?
1465                                         // (Lgb)
1466                                         s << par->getCounter(i) << '.';
1467                                         
1468                                         break;
1469                                 }
1470                         }
1471
1472                         par->params.labelString(par->params.labelString() +s.str().c_str());
1473                         // We really want to remove the c_str as soon as
1474                         // possible...
1475                         
1476                         for (i++; i < 10; ++i) {
1477                                 // reset the following counters
1478                                 par->setCounter(i, 0);
1479                         }
1480                 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1481                         for (i++; i < 10; ++i) {
1482                                 // reset the following counters
1483                                 par->setCounter(i, 0);
1484                         }
1485                 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1486                         par->incCounter(i + par->enumdepth);
1487                         int number = par->getCounter(i + par->enumdepth);
1488
1489                         std::ostringstream s;
1490
1491                         switch (par->enumdepth) {
1492                         case 1:
1493                                 if (par->isRightToLeftPar(buf->params))
1494                                         s << '('
1495                                           << hebrewCounter(number)
1496                                           << ')';
1497                                 else
1498                                         s << '('
1499                                           << loweralphaCounter(number)
1500                                           << ')';
1501                                 break;
1502                         case 2:
1503                                 if (par->isRightToLeftPar(buf->params))
1504                                         s << '.' << romanCounter(number);
1505                                 else
1506                                         s << romanCounter(number) << '.';
1507                                 break;
1508                         case 3:
1509                                 if (par->isRightToLeftPar(buf->params))
1510                                         s << '.'
1511                                           << alphaCounter(number);
1512                                 else
1513                                         s << alphaCounter(number)
1514                                           << '.';
1515                                 break;
1516                         default:
1517                                 if (par->isRightToLeftPar(buf->params))
1518                                         s << '.' << number;
1519                                 else
1520                                         s << number << '.';
1521                                 break;
1522                         }
1523
1524                         par->params.labelString(s.str().c_str());
1525                         // we really want to get rid of that c_str()
1526
1527                         for (i += par->enumdepth + 1; i < 10; ++i)
1528                                 par->setCounter(i, 0);  /* reset the following counters  */
1529          
1530                 } 
1531         } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1532                 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1533                 par->incCounter(i);
1534                 int number = par->getCounter(i);
1535                 if (!par->bibkey) {
1536                         InsetCommandParams p( "bibitem" );
1537                         par->bibkey = new InsetBibKey(p);
1538                 }
1539                 par->bibkey->setCounter(number);
1540                 par->params.labelString(layout.labelstring());
1541                 
1542                 // In biblio should't be following counters but...
1543         } else {
1544                 string s = layout.labelstring();
1545                 
1546                 // the caption hack:
1547                 if (layout.labeltype == LABEL_SENSITIVE) {
1548                         bool isOK (par->InInset() && par->InInset()->owner() &&
1549                                    (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
1550                         if (isOK) {
1551                                 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
1552                                 Floating const & fl
1553                                         = floatList.getType(tmp->type());
1554                                 // We should get the correct number here too.
1555                                 s = fl.name() + " #:";
1556                         } else {
1557                                 /* par->SetLayout(0); 
1558                                    s = layout->labelstring;  */
1559                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1560                                         ? " :úåòîùî Ã¸Ã±Ã§" : "Senseless: ";
1561                         }
1562                 }
1563                 par->params.labelString(s);
1564                 
1565                 /* reset the enumeration counter. They are always resetted
1566                  * when there is any other layout between */ 
1567                 for (int i = 6 + par->enumdepth; i < 10; ++i)
1568                         par->setCounter(i, 0);
1569         }
1570 }
1571
1572
1573 /* Updates all counters BEHIND the row. Changed paragraphs
1574 * with a dynamic left margin will be rebroken. */ 
1575 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1576 {
1577         LyXParagraph * par;
1578
1579         if (!row) {
1580                 row = firstrow;
1581                 par = row->par();
1582         } else {
1583                 par = row->par()->next();
1584         }
1585
1586         while (par) {
1587                 while (row->par() != par)
1588                         row = row->next();
1589                 
1590                 SetCounter(bview->buffer(), par);
1591                 
1592                 /* now  check for the headline layouts. remember that they
1593                  * have a dynamic left margin */ 
1594                 if ((textclasslist.Style(bview->buffer()->params.textclass,
1595                                          par->layout).margintype == MARGIN_DYNAMIC
1596                      || textclasslist.Style(bview->buffer()->params.textclass,
1597                                             par->layout).labeltype == LABEL_SENSITIVE)) {
1598                         
1599                         /* Rebreak the paragraph */ 
1600                         RemoveParagraph(row);
1601                         AppendParagraph(bview, row);
1602                 }
1603                 par = par->next();
1604         }
1605 }
1606
1607
1608 /* insets an inset. */ 
1609 void LyXText::InsertInset(BufferView * bview, Inset * inset)
1610 {
1611         if (!cursor.par()->InsertInsetAllowed(inset))
1612                 return;
1613         SetUndo(bview->buffer(), Undo::INSERT,
1614                 cursor.par()->previous(),
1615                 cursor.par()->next());
1616         cursor.par()->InsertInset(cursor.pos(), inset);
1617         InsertChar(bview, LyXParagraph::META_INSET);  /* just to rebreak and refresh correctly.
1618                                       * The character will not be inserted a
1619                                       * second time */
1620 #if 1
1621         // If we enter a highly editable inset the cursor should be to before
1622         // the inset. This couldn't happen before as Undo was not handled inside
1623         // inset now after the Undo LyX tries to call inset->Edit(...) again
1624         // and cannot do this as the cursor is behind the inset and GetInset
1625         // does not return the inset!
1626         if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
1627                 CursorLeft(bview, true);
1628         }
1629 #endif
1630 }
1631
1632
1633 void LyXText::copyEnvironmentType()
1634 {
1635         copylayouttype = cursor.par()->GetLayout();
1636 }
1637
1638
1639 void LyXText::pasteEnvironmentType(BufferView * bview)
1640 {
1641         SetLayout(bview, copylayouttype);
1642 }
1643
1644
1645 void LyXText::CutSelection(BufferView * bview, bool doclear)
1646 {
1647         // Stuff what we got on the clipboard. Even if there is no selection.
1648
1649         // There is a problem with having the stuffing here in that the
1650         // larger the selection the slower LyX will get. This can be
1651         // solved by running the line below only when the selection has
1652         // finished. The solution used currently just works, to make it
1653         // faster we need to be more clever and probably also have more
1654         // calls to stuffClipboard. (Lgb)
1655         bview->stuffClipboard(selectionAsString(bview->buffer()));
1656
1657         // This doesn't make sense, if there is no selection
1658         if (!selection)
1659                 return;
1660    
1661         // OK, we have a selection. This is always between sel_start_cursor
1662         // and sel_end_cursor
1663
1664         // make sure that the depth behind the selection are restored, too
1665         LyXParagraph * endpar = sel_end_cursor.par()->next();
1666         LyXParagraph * undoendpar = endpar;
1667     
1668         if (endpar && endpar->GetDepth()) {
1669                 while (endpar && endpar->GetDepth()) {
1670                         endpar = endpar->next();
1671                         undoendpar = endpar;
1672                 }
1673         } else if (endpar) {
1674                 endpar = endpar->next(); // because of parindents etc.
1675         }
1676     
1677         SetUndo(bview->buffer(), Undo::DELETE,
1678                 sel_start_cursor.par()->previous(),
1679                 undoendpar);
1680     
1681         CutAndPaste cap;
1682
1683         // there are two cases: cut only within one paragraph or
1684         // more than one paragraph
1685         if (sel_start_cursor.par() == sel_end_cursor.par()) {
1686                 // only within one paragraph
1687                 endpar = sel_start_cursor.par();
1688                 int pos = sel_end_cursor.pos();
1689                 cap.cutSelection(sel_start_cursor.par(), &endpar,
1690                                  sel_start_cursor.pos(), pos,
1691                                  bview->buffer()->params.textclass, doclear);
1692                 sel_end_cursor.pos(pos);
1693         } else {
1694                 endpar = sel_end_cursor.par();
1695
1696                 int pos = sel_end_cursor.pos();
1697                 cap.cutSelection(sel_start_cursor.par(), &endpar,
1698                                  sel_start_cursor.pos(), pos,
1699                                  bview->buffer()->params.textclass, doclear);
1700                 cursor.par(endpar);
1701                 sel_end_cursor.par(endpar);
1702                 sel_end_cursor.pos(pos);
1703                 cursor.pos(sel_end_cursor.pos());
1704         }
1705         endpar = endpar->next();
1706
1707         // sometimes necessary
1708         if (doclear)
1709                 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
1710
1711         RedoParagraphs(bview, sel_start_cursor, endpar);
1712    
1713         ClearSelection(bview);
1714         cursor = sel_start_cursor;
1715         SetCursor(bview, cursor.par(), cursor.pos());
1716         sel_cursor = cursor;
1717         UpdateCounters(bview, cursor.row());
1718 }
1719
1720
1721 void LyXText::CopySelection(BufferView * bview)
1722 {
1723         // Stuff what we got on the clipboard. Even if there is no selection.
1724
1725         // There is a problem with having the stuffing here in that the
1726         // larger the selection the slower LyX will get. This can be
1727         // solved by running the line below only when the selection has
1728         // finished. The solution used currently just works, to make it
1729         // faster we need to be more clever and probably also have more
1730         // calls to stuffClipboard. (Lgb)
1731         bview->stuffClipboard(selectionAsString(bview->buffer()));
1732
1733         // this doesnt make sense, if there is no selection
1734         if (!selection)
1735                 return;
1736
1737         // ok we have a selection. This is always between sel_start_cursor
1738         // and sel_end cursor
1739
1740         // copy behind a space if there is one
1741         while (sel_start_cursor.par()->size() > sel_start_cursor.pos()
1742                && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
1743                && (sel_start_cursor.par() != sel_end_cursor.par()
1744                    || sel_start_cursor.pos() < sel_end_cursor.pos()))
1745                 sel_start_cursor.pos(sel_start_cursor.pos() + 1); 
1746
1747         CutAndPaste cap;
1748
1749         cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
1750                           sel_start_cursor.pos(), sel_end_cursor.pos(),
1751                           bview->buffer()->params.textclass);
1752 }
1753
1754
1755 void LyXText::PasteSelection(BufferView * bview)
1756 {
1757         CutAndPaste cap;
1758
1759         // this does not make sense, if there is nothing to paste
1760         if (!cap.checkPastePossible(cursor.par()))
1761                 return;
1762
1763         SetUndo(bview->buffer(), Undo::INSERT,
1764                 cursor.par()->previous(),
1765                 cursor.par()->next()); 
1766
1767         LyXParagraph * endpar;
1768         LyXParagraph * actpar = cursor.par();
1769
1770         int pos = cursor.pos();
1771         cap.pasteSelection(&actpar, &endpar, pos,
1772                            bview->buffer()->params.textclass);
1773     
1774         RedoParagraphs(bview, cursor, endpar);
1775         
1776         SetCursor(bview, cursor.par(), cursor.pos());
1777         ClearSelection(bview);
1778    
1779         sel_cursor = cursor;
1780         SetCursor(bview, actpar, pos);
1781         SetSelection(bview);
1782         UpdateCounters(bview, cursor.row());
1783 }
1784
1785
1786 // returns a pointer to the very first LyXParagraph
1787 LyXParagraph * LyXText::FirstParagraph() const
1788 {
1789         return OwnerParagraph();
1790 }
1791
1792
1793 // sets the selection over the number of characters of string, no check!!
1794 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
1795 {
1796         sel_cursor = cursor;
1797         for (int i = 0; str[i]; ++i)
1798                 CursorRight(bview);
1799         SetSelection(bview);
1800 }
1801
1802
1803 // simple replacing. The font of the first selected character is used
1804 void LyXText::ReplaceSelectionWithString(BufferView * bview,
1805                                          string const & str)
1806 {
1807         SetCursorParUndo(bview->buffer());
1808         FreezeUndo();
1809
1810         if (!selection) { // create a dummy selection
1811                 sel_end_cursor = cursor;
1812                 sel_start_cursor = cursor;
1813         }
1814
1815         // Get font setting before we cut
1816         LyXParagraph::size_type pos = sel_end_cursor.pos();
1817         LyXFont const font = sel_start_cursor.par()
1818                 ->GetFontSettings(bview->buffer()->params,
1819                                   sel_start_cursor.pos());
1820
1821         // Insert the new string
1822         for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
1823                 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
1824                 ++pos;
1825         }
1826         
1827         // Cut the selection
1828         CutSelection(bview);
1829
1830         UnFreezeUndo();
1831 }
1832
1833
1834 // needed to insert the selection
1835 void LyXText::InsertStringA(BufferView * bview, string const & str)
1836 {
1837         LyXParagraph * par = cursor.par();
1838         LyXParagraph::size_type pos = cursor.pos();
1839         LyXParagraph::size_type a = 0;
1840         LyXParagraph * endpar = cursor.par()->next();
1841         
1842         SetCursorParUndo(bview->buffer());
1843         
1844         bool flag =
1845                 textclasslist.Style(bview->buffer()->params.textclass, 
1846                                     cursor.par()->GetLayout()).isEnvironment();
1847         // only to be sure, should not be neccessary
1848         ClearSelection(bview);
1849         
1850         // insert the string, don't insert doublespace
1851         string::size_type i = 0;
1852         while (i < str.length()) {
1853                 if (str[i] != '\n') {
1854                         if (str[i] == ' ' 
1855                             && i + 1 < str.length() && str[i + 1] != ' '
1856                             && pos && par->GetChar(pos - 1)!= ' ') {
1857                                 par->InsertChar(pos, ' ', current_font);
1858                                 ++pos;
1859                         } else if (str[i] == ' ') {
1860                                 InsetSpecialChar * new_inset =
1861                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1862                                 if (par->InsertInsetAllowed(new_inset)) {
1863                                         par->InsertInset(pos, new_inset,
1864                                                          current_font);
1865                                 } else {
1866                                         delete new_inset;
1867                                 }
1868                                 ++pos;
1869                         } else if (str[i] == '\t') {
1870                                 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
1871                                 InsetSpecialChar * new_inset =
1872                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1873                                 if (par->InsertInsetAllowed(new_inset)) {
1874                                         par->InsertInset(pos, new_inset,
1875                                                          current_font);
1876                                 } else {
1877                                         delete new_inset;
1878                                 }
1879                                 }
1880                                 pos = a;
1881                         } else if (str[i] != 13 && 
1882                                    // Ignore unprintables
1883                                    (str[i] & 127) >= ' ') {
1884                                 par->InsertChar(pos, str[i], current_font);
1885                                 ++pos;
1886                         }
1887                 } else {
1888                         if (!par->size()) { // par is empty
1889                                 InsetSpecialChar * new_inset =
1890                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1891                                 if (par->InsertInsetAllowed(new_inset)) {
1892                                         par->InsertInset(pos,
1893                                                          new_inset,
1894                                                          current_font);
1895                                 } else {
1896                                         delete new_inset;
1897                                 }
1898                                 ++pos;
1899                         }
1900                         par->BreakParagraph(bview->buffer()->params, pos, flag);
1901                         par = par->next();
1902                         pos = 0;
1903                 }
1904                 ++i;
1905         }
1906         
1907         RedoParagraphs(bview, cursor, endpar);
1908         SetCursor(bview, cursor.par(), cursor.pos());
1909         sel_cursor = cursor;
1910         SetCursor(bview, par, pos);
1911         SetSelection(bview);
1912 }
1913
1914
1915 /* turns double-CR to single CR, others where converted into one blank and 13s 
1916  * that are ignored .Double spaces are also converted into one. Spaces at
1917  * the beginning of a paragraph are forbidden. tabs are converted into one
1918  * space. then InsertStringA is called */ 
1919 void LyXText::InsertStringB(BufferView * bview, string const & s)
1920 {
1921         string str(s);
1922         string::size_type i = 1;
1923         while (i < str.length()) {
1924                 if (str[i] == '\t')
1925                         str[i] = ' ';
1926                 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
1927                         str[i] = 13;
1928                 if (str[i] == '\n' && i + 1 < str.length()) {
1929                         if (str[i + 1] != '\n') {
1930                                 if (str[i - 1] != ' ')
1931                                         str[i] = ' ';
1932                                 else
1933                                         str[i] = 13;
1934                         }
1935                         while (i + 1 < str.length() 
1936                                && (str[i + 1] == ' ' 
1937                                    || str[i + 1] == '\t'
1938                                    || str[i + 1] == '\n' 
1939                                    || str[i + 1] == 13)) {
1940                                 str[i + 1] = 13;
1941                                 ++i;
1942                         }
1943                 }
1944                 ++i;
1945         }
1946         InsertStringA(bview, str);
1947 }
1948
1949
1950 bool LyXText::GotoNextInset(BufferView * bview,
1951                             std::vector<Inset::Code> const & codes,
1952                             string const & contents) const
1953 {
1954         LyXCursor res = cursor;
1955         Inset * inset;
1956         do {
1957                 if (res.pos() < res.par()->size() - 1) {
1958                         res.pos(res.pos() + 1);
1959                 } else  {
1960                         res.par(res.par()->next());
1961                         res.pos(0);
1962                 }
1963       
1964         } while (res.par() && 
1965                  !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
1966                    && (inset = res.par()->GetInset(res.pos())) != 0
1967                    && find(codes.begin(), codes.end(), inset->LyxCode())
1968                       != codes.end()
1969                    && (contents.empty() ||
1970                        static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
1971                        == contents)));
1972
1973         if (res.par()) {
1974                 SetCursor(bview, res.par(), res.pos());
1975                 return true;
1976         }
1977         return false;
1978 }
1979
1980
1981 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
1982                              LyXParagraph::size_type pos)
1983 {
1984         LyXCursor tmpcursor;                    
1985
1986         int y = 0;
1987         LyXParagraph::size_type z;
1988         Row * row = GetRow(par, pos, y);
1989         
1990         // is there a break one row above
1991         if (row->previous() && row->previous()->par() == row->par()) {
1992                 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
1993                 if (z >= row->pos()) {
1994                         // set the dimensions of the row above
1995                         y -= row->previous()->height();
1996                         refresh_y = y;
1997                         refresh_row = row->previous();
1998                         status = LyXText::NEED_MORE_REFRESH;
1999                         
2000                         BreakAgain(bview, row->previous());
2001                         
2002                         // set the cursor again. Otherwise
2003                         // dangling pointers are possible
2004                         SetCursor(bview, cursor.par(), cursor.pos(),
2005                                   false, cursor.boundary());
2006                         sel_cursor = cursor;
2007                         return;
2008                 }
2009         }
2010
2011         int const tmpheight = row->height();
2012         LyXParagraph::size_type const tmplast = RowLast(row);
2013         refresh_y = y;
2014         refresh_row = row;
2015         
2016         BreakAgain(bview, row);
2017         if (row->height() == tmpheight && RowLast(row) == tmplast)
2018                 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2019         else
2020                 status = LyXText::NEED_MORE_REFRESH; 
2021         
2022         // check the special right address boxes
2023         if (textclasslist.Style(bview->buffer()->params.textclass,
2024                                 par->GetLayout()).margintype
2025             == MARGIN_RIGHT_ADDRESS_BOX) {
2026                 tmpcursor.par(par);
2027                 tmpcursor.row(row);
2028                 tmpcursor.y(y);
2029                 tmpcursor.x(0);
2030                 tmpcursor.x_fix(0);
2031                 tmpcursor.pos(pos);
2032                 RedoDrawingOfParagraph(bview, tmpcursor); 
2033         }
2034
2035         // set the cursor again. Otherwise dangling pointers are possible
2036         // also set the selection
2037    
2038         if (selection) {
2039                 tmpcursor = cursor;
2040                 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2041                                 false, sel_cursor.boundary());
2042                 sel_cursor = cursor; 
2043                 SetCursorIntern(bview, sel_start_cursor.par(),
2044                                 sel_start_cursor.pos(),
2045                                 false, sel_start_cursor.boundary());
2046                 sel_start_cursor = cursor; 
2047                 SetCursorIntern(bview, sel_end_cursor.par(),
2048                                 sel_end_cursor.pos(),
2049                                 false, sel_end_cursor.boundary());
2050                 sel_end_cursor = cursor; 
2051                 SetCursorIntern(bview, last_sel_cursor.par(),
2052                                 last_sel_cursor.pos(),
2053                                 false, last_sel_cursor.boundary());
2054                 last_sel_cursor = cursor; 
2055                 cursor = tmpcursor;
2056         }
2057         SetCursorIntern(bview, cursor.par(), cursor.pos(),
2058                         false, cursor.boundary());
2059 }
2060
2061
2062 // returns false if inset wasn't found
2063 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2064 {
2065         // first check the current paragraph
2066         int pos = cursor.par()->GetPositionOfInset(inset);
2067         if (pos != -1){
2068                 CheckParagraph(bview, cursor.par(), pos);
2069                 return true;
2070         }
2071   
2072         // check every paragraph
2073   
2074         LyXParagraph * par = FirstParagraph();
2075         do {
2076                         pos = par->GetPositionOfInset(inset);
2077                         if (pos != -1){
2078                                 CheckParagraph(bview, par, pos);
2079                                 return true;
2080                         }
2081                 par = par->next();
2082         } while (par);
2083   
2084         return false;
2085 }
2086
2087
2088 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2089                         LyXParagraph::size_type pos, 
2090                         bool setfont, bool boundary) const
2091 {
2092         LyXCursor old_cursor = cursor;
2093         SetCursorIntern(bview, par, pos, setfont, boundary);
2094         DeleteEmptyParagraphMechanism(bview, old_cursor);
2095 }
2096
2097
2098 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2099                         LyXParagraph::size_type pos, bool boundary) const
2100 {
2101         cur.par(par);
2102         cur.pos(pos);
2103         cur.boundary(boundary);
2104
2105         /* get the cursor y position in text  */
2106         int y = 0;
2107         Row * row = GetRow(par, pos, y);
2108         /* y is now the beginning of the cursor row */ 
2109         y += row->baseline();
2110         /* y is now the cursor baseline */ 
2111         cur.y(y);
2112    
2113         /* now get the cursors x position */
2114         float x;
2115         float fill_separator, fill_hfill, fill_label_hfill;
2116         PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2117                        fill_label_hfill);
2118         LyXParagraph::size_type cursor_vpos = 0;
2119         LyXParagraph::size_type last = RowLastPrintable(row);
2120
2121         if (pos > last + 1)   // This shouldn't happen.
2122                 pos = last + 1;
2123         else if (pos < row->pos())
2124                 pos = row->pos();
2125
2126         if (last < row->pos())
2127                 cursor_vpos = row->pos();
2128         else if (pos > last && !boundary)
2129                 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2130                         ? row->pos() : last + 1; 
2131         else if (pos > row->pos() &&
2132                  (pos > last || boundary))
2133                 /// Place cursor after char at (logical) position pos - 1
2134                 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2135                         ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2136         else
2137                 /// Place cursor before char at (logical) position pos
2138                 cursor_vpos = (bidi_level(pos) % 2 == 0)
2139                         ? log2vis(pos) : log2vis(pos) + 1;
2140         
2141         LyXParagraph::size_type main_body =
2142                 BeginningOfMainBody(bview->buffer(), row->par());
2143         if ((main_body > 0) &&
2144             ((main_body-1 > last) || 
2145              !row->par()->IsLineSeparator(main_body-1)))
2146                 main_body = 0;
2147         
2148         for (LyXParagraph::size_type vpos = row->pos();
2149              vpos < cursor_vpos; ++vpos) {
2150                 pos = vis2log(vpos);
2151                 if (main_body > 0 && pos == main_body - 1) {
2152                         x += fill_label_hfill +
2153                                 lyxfont::width(textclasslist.Style(
2154                                         bview->buffer()->params.textclass,
2155                                         row->par()->GetLayout())
2156                                                .labelsep,
2157                                                GetFont(bview->buffer(), row->par(), -2));
2158                         if (row->par()->IsLineSeparator(main_body-1))
2159                                 x -= SingleWidth(bview, row->par(),main_body-1);
2160                 }
2161                 if (HfillExpansion(bview->buffer(), row, pos)) {
2162                         x += SingleWidth(bview, row->par(), pos);
2163                         if (pos >= main_body)
2164                                 x += fill_hfill;
2165                         else 
2166                                 x += fill_label_hfill;
2167                 } else if (row->par()->IsSeparator(pos)) {
2168                         x += SingleWidth(bview, row->par(), pos);
2169                         if (pos >= main_body)
2170                                 x += fill_separator;
2171                 } else
2172                         x += SingleWidth(bview, row->par(), pos);
2173         }
2174         
2175         cur.x(int(x));
2176         cur.x_fix(cur.x());
2177         cur.row(row);
2178 }
2179
2180
2181 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2182                               LyXParagraph::size_type pos,
2183                               bool setfont, bool boundary) const
2184 {
2185         SetCursor(bview, cursor, par, pos, boundary);
2186         if (setfont)
2187                 SetCurrentFont(bview);
2188 }
2189
2190
2191 void LyXText::SetCurrentFont(BufferView * bview) const
2192 {
2193         LyXParagraph::size_type pos = cursor.pos();
2194         if (cursor.boundary() && pos > 0)
2195                 --pos;
2196
2197         if (pos > 0) {
2198                 if (pos == cursor.par()->size())
2199                         --pos;
2200                 else if (cursor.par()->IsSeparator(pos)) {
2201                         if (pos > cursor.row()->pos() &&
2202                             bidi_level(pos) % 2 == 
2203                             bidi_level(pos - 1) % 2)
2204                                 --pos;
2205                         else if (pos + 1 < cursor.par()->size())
2206                                 ++pos;
2207                 }
2208         }
2209
2210         current_font =
2211                 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2212         real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2213
2214         if (cursor.pos() == cursor.par()->size() &&
2215             IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2216             !cursor.boundary()) {
2217                 Language const * lang =
2218                         cursor.par()->getParLanguage(bview->buffer()->params);
2219                 current_font.setLanguage(lang);
2220                 current_font.setNumber(LyXFont::OFF);
2221                 real_current_font.setLanguage(lang);
2222                 real_current_font.setNumber(LyXFont::OFF);
2223         }
2224 }
2225
2226
2227 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2228 {
2229         LyXCursor old_cursor = cursor;
2230    
2231         /* get the row first */ 
2232    
2233         Row * row = GetRowNearY(y);
2234         cursor.par(row->par());
2235
2236         bool bound = false;
2237         int column = GetColumnNearX(bview, row, x, bound);
2238         cursor.pos(row->pos() + column);
2239         cursor.x(x);
2240         cursor.y(y + row->baseline());
2241         cursor.row(row);
2242         cursor.boundary(bound);
2243         SetCurrentFont(bview);
2244         DeleteEmptyParagraphMechanism(bview, old_cursor);
2245 }
2246
2247
2248 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2249                                        int x, int y) const
2250 {
2251         /* get the row first */ 
2252    
2253         Row * row = GetRowNearY(y);
2254         bool bound = false;
2255         int column = GetColumnNearX(bview, row, x, bound);
2256    
2257         cur.par(row->par());
2258         cur.pos(row->pos() + column);
2259         cur.x(x);
2260         cur.y(y + row->baseline());
2261         cur.row(row);
2262         cur.boundary(bound);
2263 }
2264
2265
2266 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2267 {
2268         if (cursor.pos() > 0) {
2269                 bool boundary = cursor.boundary();
2270                 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2271                 if (!internal && !boundary &&
2272                     IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2273                         SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2274         } else if (cursor.par()->previous()) { // steps into the above paragraph.
2275                 LyXParagraph * par = cursor.par()->previous();
2276                 SetCursor(bview, par, par->size());
2277         }
2278 }
2279
2280
2281 void LyXText::CursorRight(BufferView * bview, bool internal) const
2282 {
2283         if (!internal && cursor.boundary() &&
2284             !cursor.par()->IsNewline(cursor.pos()))
2285                 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2286         else if (cursor.pos() < cursor.par()->size()) {
2287                 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2288                 if (!internal &&
2289                     IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2290                         SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2291         } else if (cursor.par()->next())
2292                 SetCursor(bview, cursor.par()->next(), 0);
2293 }
2294
2295
2296 void LyXText::CursorUp(BufferView * bview) const
2297 {
2298         SetCursorFromCoordinates(bview, cursor.x_fix(), 
2299                                  cursor.y() - cursor.row()->baseline() - 1);
2300 }
2301
2302
2303 void LyXText::CursorDown(BufferView * bview) const
2304 {
2305         SetCursorFromCoordinates(bview, cursor.x_fix(), 
2306                                  cursor.y() - cursor.row()->baseline()
2307                                  + cursor.row()->height() + 1);
2308 }
2309
2310
2311 void LyXText::CursorUpParagraph(BufferView * bview) const
2312 {
2313         if (cursor.pos() > 0) {
2314                 SetCursor(bview, cursor.par(), 0);
2315         }
2316         else if (cursor.par()->previous()) {
2317                 SetCursor(bview, cursor.par()->previous(), 0);
2318         }
2319 }
2320
2321
2322 void LyXText::CursorDownParagraph(BufferView * bview) const
2323 {
2324         if (cursor.par()->next()) {
2325                 SetCursor(bview, cursor.par()->next(), 0);
2326         } else {
2327                 SetCursor(bview, cursor.par(), cursor.par()->size());
2328         }
2329 }
2330
2331
2332 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
2333                                             LyXCursor const & old_cursor) const
2334 {
2335         // Would be wrong to delete anything if we have a selection.
2336         if (selection) return;
2337
2338         // We allow all kinds of "mumbo-jumbo" when freespacing.
2339         if (textclasslist.Style(bview->buffer()->params.textclass,
2340                                 old_cursor.par()->GetLayout()).free_spacing)
2341                 return;
2342
2343         bool deleted = false;
2344         
2345         /* Ok I'll put some comments here about what is missing.
2346            I have fixed BackSpace (and thus Delete) to not delete
2347            double-spaces automagically. I have also changed Cut,
2348            Copy and Paste to hopefully do some sensible things.
2349            There are still some small problems that can lead to
2350            double spaces stored in the document file or space at
2351            the beginning of paragraphs. This happens if you have
2352            the cursor betwenn to spaces and then save. Or if you
2353            cut and paste and the selection have a space at the
2354            beginning and then save right after the paste. I am
2355            sure none of these are very hard to fix, but I will
2356            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2357            that I can get some feedback. (Lgb)
2358         */
2359
2360         // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2361         // delete the LineSeparator.
2362         // MISSING
2363
2364         // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2365         // delete the LineSeparator.
2366         // MISSING
2367
2368         // If the pos around the old_cursor were spaces, delete one of them.
2369         if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) { 
2370                 // Only if the cursor has really moved
2371                 
2372                 if (old_cursor.pos() > 0
2373                     && old_cursor.pos() < old_cursor.par()->size()
2374                     && old_cursor.par()->IsLineSeparator(old_cursor.pos())
2375                     && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
2376                         old_cursor.par()->Erase(old_cursor.pos() - 1);
2377                         RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
2378                         // correct cursor
2379                         if (old_cursor.par() == cursor.par() &&
2380                             cursor.pos() > old_cursor.pos()) {
2381                                 SetCursorIntern(bview, cursor.par(),
2382                                                 cursor.pos() - 1);
2383                         } else
2384                                 SetCursorIntern(bview, cursor.par(),
2385                                                 cursor.pos());
2386                         return;
2387                 }
2388         }
2389
2390         // Do not delete empty paragraphs with keepempty set.
2391         if ((textclasslist.Style(bview->buffer()->params.textclass,
2392                                  old_cursor.par()->GetLayout())).keepempty)
2393                 return;
2394
2395         LyXCursor tmpcursor;
2396
2397         if (old_cursor.par() != cursor.par()) {
2398                 if ((old_cursor.par()->size() == 0
2399                       || (old_cursor.par()->size() == 1
2400                           && old_cursor.par()->IsLineSeparator(0)))) {
2401                         // ok, we will delete anything
2402                         
2403                         // make sure that you do not delete any environments
2404                                 status = LyXText::NEED_MORE_REFRESH;
2405                                 deleted = true;
2406                                 
2407                                 if (old_cursor.row()->previous()) {
2408                                         refresh_row = old_cursor.row()->previous();
2409                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2410                                         tmpcursor = cursor;
2411                                         cursor = old_cursor; // that undo can restore the right cursor position
2412                                         LyXParagraph * endpar = old_cursor.par()->next();
2413                                         if (endpar && endpar->GetDepth()) {
2414                                                 while (endpar && endpar->GetDepth()) {
2415                                                         endpar = endpar->next();
2416                                                 }
2417                                         }
2418                                         SetUndo(bview->buffer(), Undo::DELETE,
2419                                                 old_cursor.par()->previous(),
2420                                                 endpar);
2421                                         cursor = tmpcursor;
2422
2423                                         // delete old row
2424                                         RemoveRow(old_cursor.row());
2425                                         if (OwnerParagraph() == old_cursor.par()) {
2426                                                 OwnerParagraph(OwnerParagraph()->next());
2427                                         }
2428                                         // delete old par
2429                                         delete old_cursor.par();
2430                                         
2431                                         /* Breakagain the next par. Needed
2432                                          * because of the parindent that
2433                                          * can occur or dissappear. The
2434                                          * next row can change its height,
2435                                          * if there is another layout before */
2436                                         if (refresh_row->next()) {
2437                                                 BreakAgain(bview, refresh_row->next());
2438                                                 UpdateCounters(bview, refresh_row);
2439                                         }
2440                                         SetHeightOfRow(bview, refresh_row);
2441                                 } else {
2442                                         refresh_row = old_cursor.row()->next();
2443                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2444                                         
2445                                         tmpcursor = cursor;
2446                                         cursor = old_cursor; // that undo can restore the right cursor position
2447                                         LyXParagraph * endpar = old_cursor.par()->next();
2448                                         if (endpar && endpar->GetDepth()) {
2449                                                 while (endpar && endpar->GetDepth()) {
2450                                                         endpar = endpar->next();
2451                                                 }
2452                                         }
2453                                         SetUndo(bview->buffer(), Undo::DELETE,
2454                                                 old_cursor.par()->previous(),
2455                                                 endpar);
2456                                         cursor = tmpcursor;
2457
2458                                         // delete old row
2459                                         RemoveRow(old_cursor.row());
2460                                         // delete old par
2461                                         if (OwnerParagraph() == old_cursor.par()) {
2462                                                 OwnerParagraph(OwnerParagraph()->next());
2463                                         }
2464
2465                                         delete old_cursor.par();
2466                                         
2467                                         /* Breakagain the next par. Needed
2468                                            because of the parindent that can
2469                                            occur or dissappear.
2470                                            The next row can change its height,
2471                                            if there is another layout before
2472                                         */ 
2473                                         if (refresh_row) {
2474                                                 BreakAgain(bview, refresh_row);
2475                                                 UpdateCounters(bview, refresh_row->previous());
2476                                         }
2477                                 }
2478                                 
2479                                 // correct cursor y
2480
2481                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
2482
2483                                 if (sel_cursor.par()  == old_cursor.par()
2484                                     && sel_cursor.pos() == sel_cursor.pos()) {
2485                                         // correct selection
2486                                         sel_cursor = cursor;
2487                                 }
2488                 }
2489                 if (!deleted) {
2490                         if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
2491                                 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
2492                                 // correct cursor y
2493                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
2494                                 sel_cursor = cursor;
2495                         }
2496                 }
2497         }
2498 }
2499
2500
2501 LyXParagraph * LyXText::GetParFromID(int id)
2502 {
2503         LyXParagraph * result = FirstParagraph();
2504         while (result && result->id() != id)
2505                 result = result->next();
2506         return result;
2507 }
2508
2509
2510 // undo functions
2511 bool LyXText::TextUndo(BufferView * bview)
2512 {
2513         if (inset_owner)
2514                 return false;
2515         // returns false if no undo possible
2516         Undo * undo = bview->buffer()->undostack.pop();
2517         if (undo) {
2518                 FinishUndo();
2519                 if (!undo_frozen)
2520                         bview->buffer()->redostack
2521                                 .push(CreateUndo(bview->buffer(), undo->kind, 
2522                                                  GetParFromID(undo->number_of_before_par),
2523                                                  GetParFromID(undo->number_of_behind_par)));
2524         }
2525         return TextHandleUndo(bview, undo);
2526 }
2527
2528
2529 bool LyXText::TextRedo(BufferView * bview)
2530 {
2531         if (inset_owner)
2532                 return false;
2533         // returns false if no redo possible
2534         Undo * undo = bview->buffer()->redostack.pop();
2535         if (undo) {
2536                 FinishUndo();
2537                 if (!undo_frozen)
2538                         bview->buffer()->undostack
2539                                 .push(CreateUndo(bview->buffer(), undo->kind, 
2540                                                  GetParFromID(undo->number_of_before_par),
2541                                                  GetParFromID(undo->number_of_behind_par)));
2542         }
2543         return TextHandleUndo(bview, undo);
2544 }
2545
2546
2547 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
2548 {
2549         if (inset_owner)
2550                 return false;
2551         // returns false if no undo possible
2552         bool result = false;
2553         if (undo) {
2554                 LyXParagraph * before =
2555                         GetParFromID(undo->number_of_before_par); 
2556                 LyXParagraph * behind =
2557                         GetParFromID(undo->number_of_behind_par); 
2558                 LyXParagraph * tmppar;
2559                 LyXParagraph * tmppar2;
2560                 LyXParagraph * endpar;
2561                 LyXParagraph * tmppar5;
2562     
2563                 // if there's no before take the beginning
2564                 // of the document for redoing
2565                 if (!before)
2566                         SetCursorIntern(bview, FirstParagraph(), 0);
2567
2568                 // replace the paragraphs with the undo informations
2569
2570                 LyXParagraph * tmppar3 = undo->par;
2571                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
2572                 LyXParagraph * tmppar4 = tmppar3;
2573
2574                 if (tmppar4) {
2575                         while (tmppar4->next())
2576                                 tmppar4 = tmppar4->next();
2577                 } // get last undo par
2578     
2579                 // now remove the old text if there is any
2580                 if (before != behind || (!behind && !before)) {
2581                         if (before)
2582                                 tmppar5 = before->next();
2583                         else
2584                                 tmppar5 = OwnerParagraph();
2585                         tmppar2 = tmppar3;
2586                         while (tmppar5 && tmppar5 != behind) {
2587                                 tmppar = tmppar5;
2588                                 tmppar5 = tmppar5->next();
2589                                 // a memory optimization for edit: Only layout information
2590                                 // is stored in the undo. So restore the text informations.
2591                                 if (undo->kind == Undo::EDIT) {
2592                                         tmppar2->setContentsFromPar(tmppar);
2593                                         tmppar->clearContents();
2594                                         tmppar2 = tmppar2->next();
2595                                 }
2596                         }
2597                 }
2598     
2599                 // put the new stuff in the list if there is one
2600                 if (tmppar3){
2601                         if (before)
2602                                 before->next(tmppar3);
2603                         else
2604                                 OwnerParagraph(tmppar3);
2605                         tmppar3->previous(before);
2606                 } else {
2607                         if (!before)
2608                                 OwnerParagraph(behind);
2609                 }
2610                 if (tmppar4) {
2611                         tmppar4->next(behind);
2612                         if (behind)
2613                                 behind->previous(tmppar4);
2614                 }
2615     
2616     
2617                 // Set the cursor for redoing
2618                 if (before) {
2619                         SetCursorIntern(bview, before, 0);
2620                 }
2621
2622                 // calculate the endpar for redoing the paragraphs.
2623                 if (behind) {
2624                                 endpar = behind->next();
2625                 } else
2626                         endpar = behind;
2627     
2628                 tmppar = GetParFromID(undo->number_of_cursor_par);
2629                 RedoParagraphs(bview, cursor, endpar); 
2630                 if (tmppar){
2631                         SetCursorIntern(bview, tmppar, undo->cursor_pos);
2632                         UpdateCounters(bview, cursor.row());
2633                 }
2634                 result = true;
2635                 delete undo;
2636         }
2637         FinishUndo();
2638         return result;
2639 }
2640
2641
2642 void LyXText::FinishUndo()
2643 {
2644         if (inset_owner)
2645                 return;
2646         // makes sure the next operation will be stored
2647         undo_finished = true;
2648 }
2649
2650
2651 void LyXText::FreezeUndo()
2652 {
2653         if (inset_owner)
2654                 return;
2655         // this is dangerous and for internal use only
2656         undo_frozen = true;
2657 }
2658
2659
2660 void LyXText::UnFreezeUndo()
2661 {
2662         if (inset_owner)
2663                 return;
2664         // this is dangerous and for internal use only
2665         undo_frozen = false;
2666 }
2667
2668
2669 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
2670                       LyXParagraph const * before,
2671                       LyXParagraph const * behind) const
2672 {
2673         if (inset_owner)
2674                 return;
2675         if (!undo_frozen)
2676                 buf->undostack.push(CreateUndo(buf, kind, before, behind));
2677         buf->redostack.clear();
2678 }
2679
2680
2681 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
2682                       LyXParagraph const * before, LyXParagraph const * behind)
2683 {
2684         if (inset_owner)
2685                 return;
2686         buf->redostack.push(CreateUndo(buf, kind, before, behind));
2687 }
2688
2689
2690 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
2691                            LyXParagraph const * before,
2692                            LyXParagraph const * behind) const
2693 {
2694         if (inset_owner)
2695                 return 0;
2696
2697         int before_number = -1;
2698         int behind_number = -1;
2699         if (before)
2700                 before_number = before->id();
2701         if (behind)
2702                 behind_number = behind->id();
2703         // Undo::EDIT  and Undo::FINISH are
2704         // always finished. (no overlapping there)
2705         // overlapping only with insert and delete inside one paragraph: 
2706         // Nobody wants all removed  character
2707         // appear one by one when undoing. 
2708         // EDIT is special since only layout information, not the
2709         // contents of a paragaph are stored.
2710         if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
2711                 // check wether storing is needed
2712                 if (!buf->undostack.empty() && 
2713                     buf->undostack.top()->kind == kind &&
2714                     buf->undostack.top()->number_of_before_par ==  before_number &&
2715                     buf->undostack.top()->number_of_behind_par ==  behind_number ){
2716                         // no undo needed
2717                         return 0;
2718                 }
2719         }
2720         // create a new Undo
2721         LyXParagraph * undopar;
2722
2723         LyXParagraph * start = 0;
2724         LyXParagraph * end = 0;
2725
2726         if (before)
2727                 start = const_cast<LyXParagraph*>(before->next());
2728         else
2729                 start = FirstParagraph();
2730         if (behind)
2731                 end = const_cast<LyXParagraph*>(behind->previous());
2732         else {
2733                 end = FirstParagraph();
2734                 while (end->next())
2735                         end = end->next();
2736         }
2737         if (start && end && (start != end->next()) &&
2738             ((before != behind) || (!before && !behind))) {
2739                 LyXParagraph * tmppar = start;
2740                 LyXParagraph * tmppar2 = new LyXParagraph(*tmppar);
2741                 tmppar2->id(tmppar->id());
2742                 
2743                 // a memory optimization: Just store the layout information
2744                 // when only edit
2745                 if (kind == Undo::EDIT){
2746                         //tmppar2->text.clear();
2747                         tmppar2->clearContents();
2748                 }
2749
2750                 undopar = tmppar2;
2751   
2752                 while (tmppar != end && tmppar->next()) {
2753                         tmppar = tmppar->next();
2754                         tmppar2->next(new LyXParagraph(*tmppar));
2755                         tmppar2->next()->id(tmppar->id());
2756                         // a memory optimization: Just store the layout
2757                         // information when only edit
2758                         if (kind == Undo::EDIT){
2759                                 //tmppar2->next->text.clear();
2760                                 tmppar2->clearContents();
2761                         }
2762                         tmppar2->next()->previous(tmppar2);
2763                         tmppar2 = tmppar2->next();
2764                 }
2765                 tmppar2->next(0);
2766         } else
2767                 undopar = 0; // nothing to replace (undo of delete maybe)
2768
2769         int cursor_par = cursor.par()->id();
2770         int cursor_pos =  cursor.pos();
2771         
2772         Undo * undo = new Undo(kind, 
2773                                before_number, behind_number,  
2774                                cursor_par, cursor_pos, 
2775                                undopar);
2776   
2777         undo_finished = false;
2778         return undo;
2779 }
2780
2781
2782 void LyXText::SetCursorParUndo(Buffer * buf)
2783 {
2784         if (inset_owner)
2785                 return;
2786         SetUndo(buf, Undo::FINISH,
2787                 cursor.par()->previous(),
2788                 cursor.par()->next()); 
2789 }
2790
2791
2792 void LyXText::toggleAppendix(BufferView * bview)
2793 {
2794         LyXParagraph * par = cursor.par();
2795         bool start = !par->params.startOfAppendix();
2796
2797         // ensure that we have only one start_of_appendix in this document
2798         LyXParagraph * tmp = FirstParagraph();
2799         for (; tmp; tmp = tmp->next())
2800                 tmp->params.startOfAppendix(false);
2801
2802         par->params.startOfAppendix(start);
2803
2804         // we can set the refreshing parameters now
2805         status = LyXText::NEED_MORE_REFRESH;
2806         refresh_y = 0;
2807         refresh_row = 0; // not needed for full update
2808         UpdateCounters(bview, 0);
2809         SetCursor(bview, cursor.par(), cursor.pos());
2810 }
2811
2812
2813 LyXParagraph * LyXText::OwnerParagraph() const
2814 {
2815         if (inset_owner)
2816                 return inset_owner->par;
2817
2818         return bv_owner->buffer()->paragraph;
2819 }
2820
2821
2822 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
2823 {
2824         if (inset_owner)
2825                 inset_owner->par = p;
2826         else
2827                 bv_owner->buffer()->paragraph = p;
2828         return 0;
2829 }