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