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