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