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