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