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