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