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