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