]> git.lyx.org Git - lyx.git/blob - src/text2.C
start native C++ support for Octave, Maple and MathML
[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,
1017                                         bool label) const
1018 {
1019         if (!selection.set()) return string();
1020         string result;
1021         
1022         // Special handling if the whole selection is within one paragraph
1023         if (selection.start.par() == selection.end.par()) {
1024                 result += selection.start.par()->asString(buffer,
1025                                                           selection.start.pos(),
1026                                                           selection.end.pos(),
1027                                                           label);
1028                 return result;
1029         }
1030         
1031         // The selection spans more than one paragraph
1032
1033         // First paragraph in selection
1034         result += selection.start.par()->asString(buffer,
1035                                                   selection.start.pos(),
1036                                                   selection.start.par()->size(),
1037                                                   label)
1038                 + "\n\n";
1039         
1040         // The paragraphs in between (if any)
1041         LyXCursor tmpcur(selection.start);
1042         tmpcur.par(tmpcur.par()->next());
1043         while (tmpcur.par() != selection.end.par()) {
1044                 result += tmpcur.par()->asString(buffer, 0,
1045                                                  tmpcur.par()->size(),
1046                                                  label) + "\n\n";
1047                 tmpcur.par(tmpcur.par()->next());
1048         }
1049
1050         // Last paragraph in selection
1051         result += selection.end.par()->asString(buffer, 0,
1052                                                 selection.end.pos(), label);
1053         
1054         return result;
1055 }
1056
1057
1058 void LyXText::clearSelection() const
1059 {
1060         selection.set(false);
1061         selection.mark(false);
1062         selection.end = selection.start = selection.cursor = cursor;
1063 }
1064
1065
1066 void LyXText::cursorHome(BufferView * bview) const
1067 {
1068         setCursor(bview, cursor.par(), cursor.row()->pos());
1069 }
1070
1071
1072 void LyXText::cursorEnd(BufferView * bview) const
1073 {
1074         if (!cursor.row()->next()
1075             || cursor.row()->next()->par() != cursor.row()->par()) {
1076                 setCursor(bview, cursor.par(), rowLast(cursor.row()) + 1);
1077         } else {
1078                 if (cursor.par()->size() &&
1079                     (cursor.par()->getChar(rowLast(cursor.row())) == ' '
1080                      || cursor.par()->isNewline(rowLast(cursor.row())))) {
1081                         setCursor(bview, cursor.par(), rowLast(cursor.row()));
1082                 } else {
1083                         setCursor(bview,cursor.par(),
1084                                   rowLast(cursor.row()) + 1);
1085                 }
1086         }
1087 }
1088
1089
1090 void LyXText::cursorTop(BufferView * bview) const
1091 {
1092         while (cursor.par()->previous())
1093                 cursor.par(cursor.par()->previous());
1094         setCursor(bview, cursor.par(), 0);
1095 }
1096
1097
1098 void LyXText::cursorBottom(BufferView * bview) const
1099 {
1100         while (cursor.par()->next())
1101                 cursor.par(cursor.par()->next());
1102         setCursor(bview, cursor.par(), cursor.par()->size());
1103 }
1104    
1105    
1106 void LyXText::toggleFree(BufferView * bview,
1107                          LyXFont const & font, bool toggleall)
1108 {
1109         // If the mask is completely neutral, tell user
1110         if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1111                 // Could only happen with user style
1112                 bview->owner()->message(_("No font change defined. Use Character under the Layout menu to define font change."));
1113                 return;
1114         }
1115
1116         // Try implicit word selection
1117         // If there is a change in the language the implicit word selection 
1118         // is disabled.
1119         LyXCursor resetCursor = cursor;
1120         bool implicitSelection = (font.language() == ignore_language
1121                                   && font.number() == LyXFont::IGNORE)
1122                 ? selectWordWhenUnderCursor(bview, WHOLE_WORD_STRICT) : false;
1123
1124         // Set font
1125         setFont(bview, font, toggleall);
1126
1127         // Implicit selections are cleared afterwards
1128         //and cursor is set to the original position.
1129         if (implicitSelection) {
1130                 clearSelection();
1131                 cursor = resetCursor;
1132                 setCursor(bview, cursor.par(), cursor.pos());
1133                 selection.cursor = cursor;
1134         }
1135         if (inset_owner)
1136                 inset_owner->setUpdateStatus(bview, InsetText::CURSOR_PAR);
1137 }
1138
1139
1140 string LyXText::getStringToIndex(BufferView * bview)
1141 {
1142         string idxstring;
1143         
1144         // Try implicit word selection
1145         // If there is a change in the language the implicit word selection 
1146         // is disabled.
1147         LyXCursor resetCursor = cursor;
1148         bool implicitSelection = selectWordWhenUnderCursor(bview, PREVIOUS_WORD);
1149
1150         if (!selection.set()) {
1151                 bview->owner()->message(_("Nothing to index!"));
1152                 return string();
1153         }
1154         if (selection.start.par() != selection.end.par()) {
1155                 bview->owner()->message(_("Cannot index more than one paragraph!"));
1156                 return string();
1157         }
1158
1159         idxstring = selectionAsString(bview->buffer(), false);
1160         
1161         // Implicit selections are cleared afterwards
1162         //and cursor is set to the original position.
1163         if (implicitSelection) {
1164                 clearSelection();
1165                 cursor = resetCursor;
1166                 setCursor(bview, cursor.par(), cursor.pos());
1167                 selection.cursor = cursor;
1168         }
1169         return idxstring;
1170 }
1171
1172
1173 Paragraph::size_type LyXText::beginningOfMainBody(Buffer const * buf,
1174                              Paragraph const * par) const
1175 {
1176         if (textclasslist.Style(buf->params.textclass,
1177                                 par->getLayout()).labeltype != LABEL_MANUAL)
1178                 return 0;
1179         else
1180                 return par->beginningOfMainBody();
1181 }
1182
1183
1184 /* the DTP switches for paragraphs. LyX will store them in the 
1185 * first physicla paragraph. When a paragraph is broken, the top settings 
1186 * rest, the bottom settings are given to the new one. So I can make shure, 
1187 * they do not duplicate themself and you cannnot make dirty things with 
1188 * them!  */ 
1189
1190 void LyXText::setParagraph(BufferView * bview,
1191                            bool line_top, bool line_bottom,
1192                            bool pagebreak_top, bool pagebreak_bottom,
1193                            VSpace const & space_top,
1194                            VSpace const & space_bottom,
1195                            Spacing const & spacing,
1196                            LyXAlignment align, 
1197                            string labelwidthstring,
1198                            bool noindent) 
1199 {
1200         LyXCursor tmpcursor = cursor;
1201         if (!selection.set()) {
1202                 selection.start = cursor;
1203                 selection.end = cursor;
1204         }
1205
1206         // make sure that the depth behind the selection are restored, too
1207         Paragraph * endpar = selection.end.par()->next();
1208         Paragraph * undoendpar = endpar;
1209
1210         if (endpar && endpar->getDepth()) {
1211                 while (endpar && endpar->getDepth()) {
1212                         endpar = endpar->next();
1213                         undoendpar = endpar;
1214                 }
1215         }
1216         else if (endpar) {
1217                 // because of parindents etc.
1218                 endpar = endpar->next();
1219         }
1220    
1221         setUndo(bview, Undo::EDIT, selection.start.par(), undoendpar);
1222
1223         
1224         Paragraph * tmppar = selection.end.par();
1225         while (tmppar != selection.start.par()->previous()) {
1226                 setCursor(bview, tmppar, 0);
1227                 status(bview, LyXText::NEED_MORE_REFRESH);
1228                 refresh_row = cursor.row();
1229                 refresh_y = cursor.y() - cursor.row()->baseline();
1230                 cursor.par()->params().lineTop(line_top);
1231                 cursor.par()->params().lineBottom(line_bottom);
1232                 cursor.par()->params().pagebreakTop(pagebreak_top);
1233                 cursor.par()->params().pagebreakBottom(pagebreak_bottom);
1234                 cursor.par()->params().spaceTop(space_top);
1235                 cursor.par()->params().spaceBottom(space_bottom);
1236                 cursor.par()->params().spacing(spacing);
1237                 // does the layout allow the new alignment?
1238                 if (align == LYX_ALIGN_LAYOUT)
1239                         align = textclasslist
1240                                 .Style(bview->buffer()->params.textclass,
1241                                        cursor.par()->getLayout()).align;
1242                 if (align & textclasslist
1243                     .Style(bview->buffer()->params.textclass,
1244                            cursor.par()->getLayout()).alignpossible) {
1245                         if (align == textclasslist
1246                             .Style(bview->buffer()->params.textclass,
1247                                    cursor.par()->getLayout()).align)
1248                                 cursor.par()->params().align(LYX_ALIGN_LAYOUT);
1249                         else
1250                                 cursor.par()->params().align(align);
1251                 }
1252                 cursor.par()->setLabelWidthString(labelwidthstring);
1253                 cursor.par()->params().noindent(noindent);
1254                 tmppar = cursor.par()->previous();
1255         }
1256         
1257         redoParagraphs(bview, selection.start, endpar);
1258         
1259         clearSelection();
1260         setCursor(bview, selection.start.par(), selection.start.pos());
1261         selection.cursor = cursor;
1262         setCursor(bview, selection.end.par(), selection.end.pos());
1263         setSelection(bview);
1264         setCursor(bview, tmpcursor.par(), tmpcursor.pos());
1265         if (inset_owner)
1266                 bview->updateInset(inset_owner, true);
1267 }
1268
1269
1270 char loweralphaCounter(int n)
1271 {
1272         if (n < 1 || n > 26)
1273                 return '?';
1274         else
1275                 return 'a' + n - 1;
1276 }
1277
1278
1279 namespace {
1280
1281 inline
1282 char alphaCounter(int n)
1283 {
1284         if (n < 1 || n > 26)
1285                 return '?';
1286         else
1287                 return 'A' + n - 1;
1288 }
1289
1290
1291 inline
1292 char hebrewCounter(int n)
1293 {
1294         static const char hebrew[22] = {
1295                 'à', 'á', 'â', 'ã', 'ä', 'Ã¥', 'æ', 'ç', 'è',
1296                 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö', 
1297                 '÷', 'ø', 'ù', 'ú'
1298         };
1299         if (n < 1 || n > 22)
1300                 return '?';
1301         else
1302                 return hebrew[n-1];
1303 }
1304
1305
1306 inline
1307 string const romanCounter(int n)
1308 {
1309         static char const * roman[20] = {
1310                 "i",   "ii",  "iii", "iv", "v",
1311                 "vi",  "vii", "viii", "ix", "x",
1312                 "xi",  "xii", "xiii", "xiv", "xv",
1313                 "xvi", "xvii", "xviii", "xix", "xx"
1314         };
1315         if (n < 1 || n > 20)
1316                 return "??";
1317         else
1318                 return roman[n-1];
1319 }
1320
1321 } // namespace anon
1322
1323
1324 // set the counter of a paragraph. This includes the labels
1325 void LyXText::setCounter(Buffer const * buf, Paragraph * par) const
1326 {
1327         LyXLayout const & layout =
1328                 textclasslist.Style(buf->params.textclass, 
1329                                     par->getLayout());
1330
1331         LyXTextClass const & textclass =
1332                 textclasslist.TextClass(buf->params.textclass);
1333
1334         // copy the prev-counters to this one,
1335         // unless this is the first paragraph
1336         if (par->previous()) {
1337                 for (int i = 0; i < 10; ++i) {
1338                         par->setCounter(i, par->previous()->getFirstCounter(i));
1339                 }
1340                 par->params().appendix(par->previous()->params().appendix());
1341                 if (!par->params().appendix() && par->params().startOfAppendix()) {
1342                         par->params().appendix(true);
1343                         for (int i = 0; i < 10; ++i) {
1344                                 par->setCounter(i, 0);
1345                         }  
1346                 }
1347                 par->enumdepth = par->previous()->enumdepth;
1348                 par->itemdepth = par->previous()->itemdepth;
1349         } else {
1350                 for (int i = 0; i < 10; ++i) {
1351                         par->setCounter(i, 0);
1352                 }  
1353                 par->params().appendix(par->params().startOfAppendix());
1354                 par->enumdepth = 0;
1355                 par->itemdepth = 0;
1356         }
1357
1358         /* Maybe we have to increment the enumeration depth.
1359          * BUT, enumeration in a footnote is considered in isolation from its
1360          *      surrounding paragraph so don't increment if this is the
1361          *      first line of the footnote
1362          * AND, bibliographies can't have their depth changed ie. they
1363          *      are always of depth 0
1364          */
1365         if (par->previous()
1366             && par->previous()->getDepth() < par->getDepth()
1367             && textclasslist.Style(buf->params.textclass,
1368                                    par->previous()->getLayout()
1369                     ).labeltype == LABEL_COUNTER_ENUMI
1370             && par->enumdepth < 3
1371             && layout.labeltype != LABEL_BIBLIO) {
1372                 par->enumdepth++;
1373         }
1374
1375         // Maybe we have to decrement the enumeration depth, see note above
1376         if (par->previous()
1377             && par->previous()->getDepth() > par->getDepth()
1378             && layout.labeltype != LABEL_BIBLIO) {
1379                 par->enumdepth = par->depthHook(par->getDepth())->enumdepth;
1380                 par->setCounter(6 + par->enumdepth,
1381                                 par->depthHook(par->getDepth())->getCounter(6 + par->enumdepth));
1382                 /* reset the counters.
1383                  * A depth change is like a breaking layout
1384                  */
1385                 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1386                         par->setCounter(i, 0);
1387         }
1388    
1389         if (!par->params().labelString().empty()) {
1390                 par->params().labelString(string());
1391         }
1392    
1393         if (layout.margintype == MARGIN_MANUAL) {
1394                 if (par->params().labelWidthString().empty()) {
1395                         par->setLabelWidthString(layout.labelstring());
1396                 }
1397         } else {
1398                 par->setLabelWidthString(string());
1399         }
1400    
1401         // is it a layout that has an automatic label?
1402         if (layout.labeltype >=  LABEL_COUNTER_CHAPTER) {
1403       
1404                 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1405                 if (i >= 0 && i<= buf->params.secnumdepth) {
1406                         par->incCounter(i);     // increment the counter  
1407          
1408                         // Is there a label? Useful for Chapter layout
1409                         if (!par->params().appendix()) {
1410                                 if (!layout.labelstring().empty())
1411                                         par->params().labelString(layout.labelstring());
1412                                 else
1413                                         par->params().labelString(string());
1414                         } else {
1415                                 if (!layout.labelstring_appendix().empty())
1416                                         par->params().labelString(layout.labelstring_appendix());
1417                                 else
1418                                         par->params().labelString(string());
1419                         }
1420
1421                         ostringstream s;
1422
1423                         if (!par->params().appendix()) {
1424                                 switch (2 * LABEL_COUNTER_CHAPTER -
1425                                         textclass.maxcounter() + i) {
1426                                 case LABEL_COUNTER_CHAPTER:
1427                                         s << par->getCounter(i);
1428                                         break;
1429                                 case LABEL_COUNTER_SECTION:
1430                                         s << par->getCounter(i - 1) << '.'
1431                                           << par->getCounter(i);
1432                                         break;
1433                                 case LABEL_COUNTER_SUBSECTION:
1434                                         s << par->getCounter(i - 2) << '.'
1435                                           << par->getCounter(i - 1) << '.'
1436                                           << par->getCounter(i);
1437                                         break;
1438                                 case LABEL_COUNTER_SUBSUBSECTION:
1439                                         s << par->getCounter(i - 3) << '.'
1440                                           << par->getCounter(i - 2) << '.'
1441                                           << par->getCounter(i - 1) << '.'
1442                                           << par->getCounter(i);
1443                                         
1444                                         break;
1445                                 case LABEL_COUNTER_PARAGRAPH:
1446                                         s << par->getCounter(i - 4) << '.'
1447                                           << par->getCounter(i - 3) << '.'
1448                                           << par->getCounter(i - 2) << '.'
1449                                           << par->getCounter(i - 1) << '.'
1450                                           << par->getCounter(i);
1451                                         break;
1452                                 case LABEL_COUNTER_SUBPARAGRAPH:
1453                                         s << par->getCounter(i - 5) << '.'
1454                                           << par->getCounter(i - 4) << '.'
1455                                           << par->getCounter(i - 3) << '.'
1456                                           << par->getCounter(i - 2) << '.'
1457                                           << par->getCounter(i - 1) << '.'
1458                                           << par->getCounter(i);
1459
1460                                         break;
1461                                 default:
1462                                         // Can this ever be reached? And in the
1463                                         // case it is, how can this be correct?
1464                                         // (Lgb)
1465                                         s << par->getCounter(i) << '.';
1466                                         break;
1467                                 }
1468                         } else { // appendix
1469                                 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1470                                 case LABEL_COUNTER_CHAPTER:
1471                                         if (par->isRightToLeftPar(buf->params))
1472                                                 s << hebrewCounter(par->getCounter(i));
1473                                         else
1474                                                 s << alphaCounter(par->getCounter(i));
1475                                         break;
1476                                 case LABEL_COUNTER_SECTION:
1477                                         if (par->isRightToLeftPar(buf->params))
1478                                                 s << hebrewCounter(par->getCounter(i - 1));
1479                                         else
1480                                                 s << alphaCounter(par->getCounter(i - 1));
1481
1482                                         s << '.'
1483                                           << par->getCounter(i);
1484
1485                                         break;
1486                                 case LABEL_COUNTER_SUBSECTION:
1487                                         if (par->isRightToLeftPar(buf->params))
1488                                                 s << hebrewCounter(par->getCounter(i - 2));
1489                                         else
1490                                                 s << alphaCounter(par->getCounter(i - 2));
1491
1492                                         s << '.'
1493                                           << par->getCounter(i-1) << '.'
1494                                           << par->getCounter(i);
1495
1496                                         break;
1497                                 case LABEL_COUNTER_SUBSUBSECTION:
1498                                         if (par->isRightToLeftPar(buf->params))
1499                                                 s << hebrewCounter(par->getCounter(i-3));
1500                                         else
1501                                                 s << alphaCounter(par->getCounter(i-3));
1502
1503                                         s << '.'
1504                                           << par->getCounter(i-2) << '.'
1505                                           << par->getCounter(i-1) << '.'
1506                                           << par->getCounter(i);
1507
1508                                         break;
1509                                 case LABEL_COUNTER_PARAGRAPH:
1510                                         if (par->isRightToLeftPar(buf->params))
1511                                                 s << hebrewCounter(par->getCounter(i-4));
1512                                         else
1513                                                 s << alphaCounter(par->getCounter(i-4));
1514
1515                                         s << '.'
1516                                           << par->getCounter(i-3) << '.'
1517                                           << par->getCounter(i-2) << '.'
1518                                           << par->getCounter(i-1) << '.'
1519                                           << par->getCounter(i);
1520
1521                                         break;
1522                                 case LABEL_COUNTER_SUBPARAGRAPH:
1523                                         if (par->isRightToLeftPar(buf->params))
1524                                                 s << hebrewCounter(par->getCounter(i-5));
1525                                         else
1526                                                 s << alphaCounter(par->getCounter(i-5));
1527
1528                                         s << '.'
1529                                           << par->getCounter(i-4) << '.'
1530                                           << par->getCounter(i-3) << '.'
1531                                           << par->getCounter(i-2) << '.'
1532                                           << par->getCounter(i-1) << '.'
1533                                           << par->getCounter(i);
1534
1535                                         break;
1536                                 default:
1537                                         // Can this ever be reached? And in the
1538                                         // case it is, how can this be correct?
1539                                         // (Lgb)
1540                                         s << par->getCounter(i) << '.';
1541                                         
1542                                         break;
1543                                 }
1544                         }
1545
1546                         par->params().labelString(par->params().labelString() +s.str().c_str());
1547                         // We really want to remove the c_str as soon as
1548                         // possible...
1549                         
1550                         for (i++; i < 10; ++i) {
1551                                 // reset the following counters
1552                                 par->setCounter(i, 0);
1553                         }
1554                 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1555                         for (i++; i < 10; ++i) {
1556                                 // reset the following counters
1557                                 par->setCounter(i, 0);
1558                         }
1559                 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1560                         par->incCounter(i + par->enumdepth);
1561                         int number = par->getCounter(i + par->enumdepth);
1562
1563                         ostringstream s;
1564
1565                         switch (par->enumdepth) {
1566                         case 1:
1567                                 if (par->isRightToLeftPar(buf->params))
1568                                         s << '('
1569                                           << hebrewCounter(number)
1570                                           << ')';
1571                                 else
1572                                         s << '('
1573                                           << loweralphaCounter(number)
1574                                           << ')';
1575                                 break;
1576                         case 2:
1577                                 if (par->isRightToLeftPar(buf->params))
1578                                         s << '.' << romanCounter(number);
1579                                 else
1580                                         s << romanCounter(number) << '.';
1581                                 break;
1582                         case 3:
1583                                 if (par->isRightToLeftPar(buf->params))
1584                                         s << '.'
1585                                           << alphaCounter(number);
1586                                 else
1587                                         s << alphaCounter(number)
1588                                           << '.';
1589                                 break;
1590                         default:
1591                                 if (par->isRightToLeftPar(buf->params))
1592                                         s << '.' << number;
1593                                 else
1594                                         s << number << '.';
1595                                 break;
1596                         }
1597
1598                         par->params().labelString(s.str().c_str());
1599
1600                         for (i += par->enumdepth + 1; i < 10; ++i) {
1601                                 // reset the following counters
1602                                 par->setCounter(i, 0);
1603                         }
1604                         
1605                 } 
1606         } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1607                 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1608                 par->incCounter(i);
1609                 int number = par->getCounter(i);
1610                 if (!par->bibkey) {
1611                         InsetCommandParams p( "bibitem" );
1612                         par->bibkey = new InsetBibKey(p);
1613                 }
1614                 par->bibkey->setCounter(number);
1615                 par->params().labelString(layout.labelstring());
1616                 
1617                 // In biblio should't be following counters but...
1618         } else {
1619                 string s = layout.labelstring();
1620                 
1621                 // the caption hack:
1622                 if (layout.labeltype == LABEL_SENSITIVE) {
1623                         bool isOK (par->inInset() && par->inInset()->owner() &&
1624                                    (par->inInset()->owner()->lyxCode() == Inset::FLOAT_CODE));
1625                         
1626                         if (isOK) {
1627                                 InsetFloat * tmp = static_cast<InsetFloat*>(par->inInset()->owner());
1628                                 Floating const & fl
1629                                         = floatList.getType(tmp->type());
1630                                 // We should get the correct number here too.
1631                                 s = fl.name() + " #:";
1632                         } else {
1633                                 /* par->SetLayout(0); 
1634                                    s = layout->labelstring;  */
1635                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1636                                         ? " :úåòîùî Ã¸Ã±Ã§" : "Senseless: ";
1637                         }
1638                 }
1639                 par->params().labelString(s);
1640                 
1641                 /* reset the enumeration counter. They are always resetted
1642                  * when there is any other layout between */ 
1643                 for (int i = 6 + par->enumdepth; i < 10; ++i)
1644                         par->setCounter(i, 0);
1645         }
1646 }
1647
1648
1649 // Updates all counters BEHIND the row. Changed paragraphs
1650 // with a dynamic left margin will be rebroken.
1651 void LyXText::updateCounters(BufferView * bview, Row * row) const
1652 {
1653         Paragraph * par;
1654
1655         if (!row) {
1656                 row = firstrow;
1657                 par = row->par();
1658         } else {
1659                 par = row->par()->next();
1660         }
1661
1662         while (par) {
1663                 while (row->par() != par)
1664                         row = row->next();
1665                 
1666                 setCounter(bview->buffer(), par);
1667                 
1668                 // now check for the headline layouts. remember that they
1669                 // have a dynamic left margin
1670                 if ((textclasslist.Style(bview->buffer()->params.textclass,
1671                                          par->layout).margintype == MARGIN_DYNAMIC
1672                      || textclasslist.Style(bview->buffer()->params.textclass,
1673                                             par->layout).labeltype == LABEL_SENSITIVE)) {
1674                         
1675                         // Rebreak the paragraph
1676                         removeParagraph(row);
1677                         appendParagraph(bview, row);
1678                 }
1679                 par = par->next();
1680         }
1681 }
1682
1683
1684 void LyXText::insertInset(BufferView * bview, Inset * inset)
1685 {
1686         if (!cursor.par()->insetAllowed(inset->lyxCode()))
1687                 return;
1688         setUndo(bview, Undo::INSERT,
1689                 cursor.par(), cursor.par()->next());
1690         cursor.par()->insertInset(cursor.pos(), inset);
1691         // Just to rebreak and refresh correctly.
1692         // The character will not be inserted a second time
1693         insertChar(bview, Paragraph::META_INSET);
1694 #if 1
1695         // If we enter a highly editable inset the cursor should be to before
1696         // the inset. This couldn't happen before as Undo was not handled inside
1697         // inset now after the Undo LyX tries to call inset->Edit(...) again
1698         // and cannot do this as the cursor is behind the inset and GetInset
1699         // does not return the inset!
1700         if (inset->editable() == Inset::HIGHLY_EDITABLE) {
1701                 cursorLeft(bview, true);
1702         }
1703 #endif
1704 }
1705
1706
1707 void LyXText::copyEnvironmentType()
1708 {
1709         copylayouttype = cursor.par()->getLayout();
1710 }
1711
1712
1713 void LyXText::pasteEnvironmentType(BufferView * bview)
1714 {
1715         setLayout(bview, copylayouttype);
1716 }
1717
1718
1719 void LyXText::cutSelection(BufferView * bview, bool doclear, bool realcut)
1720 {
1721         // Stuff what we got on the clipboard. Even if there is no selection.
1722
1723         // There is a problem with having the stuffing here in that the
1724         // larger the selection the slower LyX will get. This can be
1725         // solved by running the line below only when the selection has
1726         // finished. The solution used currently just works, to make it
1727         // faster we need to be more clever and probably also have more
1728         // calls to stuffClipboard. (Lgb)
1729         bview->stuffClipboard(selectionAsString(bview->buffer(), true));
1730
1731         // This doesn't make sense, if there is no selection
1732         if (!selection.set())
1733                 return;
1734    
1735         // OK, we have a selection. This is always between selection.start
1736         // and selection.end
1737
1738         // make sure that the depth behind the selection are restored, too
1739         Paragraph * endpar = selection.end.par()->next();
1740         Paragraph * undoendpar = endpar;
1741     
1742         if (endpar && endpar->getDepth()) {
1743                 while (endpar && endpar->getDepth()) {
1744                         endpar = endpar->next();
1745                         undoendpar = endpar;
1746                 }
1747         } else if (endpar) {
1748                 endpar = endpar->next(); // because of parindents etc.
1749         }
1750     
1751         setUndo(bview, Undo::DELETE,
1752                 selection.start.par(), undoendpar);
1753     
1754         // there are two cases: cut only within one paragraph or
1755         // more than one paragraph
1756         if (selection.start.par() == selection.end.par()) {
1757                 // only within one paragraph
1758                 endpar = selection.end.par();
1759                 int pos = selection.end.pos();
1760                 CutAndPaste::cutSelection(selection.start.par(), &endpar,
1761                                           selection.start.pos(), pos,
1762                                           bview->buffer()->params.textclass,
1763                                           doclear, realcut);
1764                 selection.end.pos(pos);
1765         } else {
1766                 endpar = selection.end.par();
1767                 int pos = selection.end.pos();
1768                 CutAndPaste::cutSelection(selection.start.par(), &endpar,
1769                                           selection.start.pos(), pos,
1770                                           bview->buffer()->params.textclass,
1771                                           doclear, realcut);
1772                 cursor.par(endpar);
1773                 selection.end.par(endpar);
1774                 selection.end.pos(pos);
1775                 cursor.pos(selection.end.pos());
1776         }
1777         endpar = endpar->next();
1778
1779         // sometimes necessary
1780         if (doclear)
1781                 selection.start.par()->stripLeadingSpaces(bview->buffer()->params.textclass);
1782
1783         redoParagraphs(bview, selection.start, endpar);
1784
1785         // cutSelection can invalidate the cursor so we need to set
1786         // it anew. (Lgb)
1787         cursor = selection.start;
1788
1789         // need a valid cursor. (Lgb)
1790         clearSelection();
1791
1792         setCursor(bview, cursor.par(), cursor.pos());
1793         selection.cursor = cursor;
1794         updateCounters(bview, cursor.row());
1795 }
1796
1797
1798 void LyXText::copySelection(BufferView * bview)
1799 {
1800         // Stuff what we got on the clipboard. Even if there is no selection.
1801
1802         // There is a problem with having the stuffing here in that the
1803         // larger the selection the slower LyX will get. This can be
1804         // solved by running the line below only when the selection has
1805         // finished. The solution used currently just works, to make it
1806         // faster we need to be more clever and probably also have more
1807         // calls to stuffClipboard. (Lgb)
1808         bview->stuffClipboard(selectionAsString(bview->buffer(), true));
1809
1810         // this doesnt make sense, if there is no selection
1811         if (!selection.set())
1812                 return;
1813
1814         // ok we have a selection. This is always between selection.start
1815         // and sel_end cursor
1816
1817         // copy behind a space if there is one
1818         while (selection.start.par()->size() > selection.start.pos()
1819                && selection.start.par()->isLineSeparator(selection.start.pos())
1820                && (selection.start.par() != selection.end.par()
1821                    || selection.start.pos() < selection.end.pos()))
1822                 selection.start.pos(selection.start.pos() + 1); 
1823
1824         CutAndPaste::copySelection(selection.start.par(), selection.end.par(),
1825                                    selection.start.pos(), selection.end.pos(),
1826                                    bview->buffer()->params.textclass);
1827 }
1828
1829
1830 void LyXText::pasteSelection(BufferView * bview)
1831 {
1832         // this does not make sense, if there is nothing to paste
1833         if (!CutAndPaste::checkPastePossible(cursor.par()))
1834                 return;
1835
1836         setUndo(bview, Undo::INSERT,
1837                 cursor.par(), cursor.par()->next()); 
1838
1839         Paragraph * endpar;
1840         Paragraph * actpar = cursor.par();
1841         int pos = cursor.pos();
1842
1843         CutAndPaste::pasteSelection(&actpar, &endpar, pos,
1844                                     bview->buffer()->params.textclass);
1845     
1846         redoParagraphs(bview, cursor, endpar);
1847         
1848         setCursor(bview, cursor.par(), cursor.pos());
1849         clearSelection();
1850    
1851         setCursor(bview, actpar, pos);
1852         updateCounters(bview, cursor.row());
1853 }
1854
1855
1856 // returns a pointer to the very first Paragraph
1857 Paragraph * LyXText::firstParagraph() const
1858 {
1859         return ownerParagraph();
1860 }
1861
1862
1863 // sets the selection over the number of characters of string, no check!!
1864 void LyXText::setSelectionOverString(BufferView * bview, string const & str)
1865 {
1866         if (str.empty())
1867                 return;
1868         
1869         selection.cursor = cursor;
1870         for (string::size_type i = 0; i < str.length(); ++i)
1871                 cursorRight(bview);
1872         setSelection(bview);
1873 }
1874
1875
1876 // simple replacing. The font of the first selected character is used
1877 void LyXText::replaceSelectionWithString(BufferView * bview,
1878                                          string const & str)
1879 {
1880         setCursorParUndo(bview);
1881         freezeUndo();
1882
1883         if (!selection.set()) { // create a dummy selection
1884                 selection.end = cursor;
1885                 selection.start = cursor;
1886         }
1887
1888         // Get font setting before we cut
1889         Paragraph::size_type pos = selection.end.pos();
1890         LyXFont const font = selection.start.par()
1891                 ->getFontSettings(bview->buffer()->params,
1892                                   selection.start.pos());
1893
1894         // Insert the new string
1895         for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
1896                 selection.end.par()->insertChar(pos, (*cit), font);
1897                 ++pos;
1898         }
1899         
1900         // Cut the selection
1901         cutSelection(bview, true, false);
1902
1903         unFreezeUndo();
1904 }
1905
1906
1907 // needed to insert the selection
1908 void LyXText::insertStringAsLines(BufferView * bview, string const & str)
1909 {
1910         Paragraph * par = cursor.par();
1911         Paragraph::size_type pos = cursor.pos();
1912         Paragraph * endpar = cursor.par()->next();
1913         
1914         setCursorParUndo(bview);
1915         
1916         // only to be sure, should not be neccessary
1917         clearSelection();
1918         
1919         bview->buffer()->insertStringAsLines(par, pos, current_font, str);
1920
1921         redoParagraphs(bview, cursor, endpar);
1922         setCursor(bview, cursor.par(), cursor.pos());
1923         selection.cursor = cursor;
1924         setCursor(bview, par, pos);
1925         setSelection(bview);
1926 }
1927
1928
1929 // turns double-CR to single CR, others where converted into one
1930 // blank. Then InsertStringAsLines is called
1931 void LyXText::insertStringAsParagraphs(BufferView * bview, string const & str)
1932 {
1933         string linestr(str);
1934         bool newline_inserted = false;
1935         for (string::size_type i = 0; i < linestr.length(); ++i) {
1936                 if (linestr[i] == '\n') {
1937                         if (newline_inserted) {
1938                                 // we know that \r will be ignored by
1939                                 // InsertStringA. Of course, it is a dirty
1940                                 // trick, but it works...
1941                                 linestr[i - 1] = '\r';
1942                                 linestr[i] = '\n';
1943                         } else {
1944                                 linestr[i] = ' ';
1945                                 newline_inserted = true;
1946                         } 
1947                 } else if (IsPrintable(linestr[i])) {
1948                         newline_inserted = false;
1949                 }
1950         }
1951         insertStringAsLines(bview, linestr);
1952 }
1953
1954
1955 bool LyXText::gotoNextInset(BufferView * bview,
1956                             std::vector<Inset::Code> const & codes,
1957                             string const & contents) const
1958 {
1959         LyXCursor res = cursor;
1960         Inset * inset;
1961         do {
1962                 if (res.pos() < res.par()->size() - 1) {
1963                         res.pos(res.pos() + 1);
1964                 } else  {
1965                         res.par(res.par()->next());
1966                         res.pos(0);
1967                 }
1968       
1969         } while (res.par() && 
1970                  !(res.par()->getChar(res.pos()) == Paragraph::META_INSET
1971                    && (inset = res.par()->getInset(res.pos())) != 0
1972                    && find(codes.begin(), codes.end(), inset->lyxCode())
1973                    != codes.end()
1974                    && (contents.empty() ||
1975                        static_cast<InsetCommand *>(res.par()->getInset(res.pos()))->getContents()
1976                        == contents)));
1977
1978         if (res.par()) {
1979                 setCursor(bview, res.par(), res.pos());
1980                 return true;
1981         }
1982         return false;
1983 }
1984
1985
1986 void LyXText::checkParagraph(BufferView * bview, Paragraph * par,
1987                              Paragraph::size_type pos)
1988 {
1989         LyXCursor tmpcursor;                    
1990
1991         int y = 0;
1992         Paragraph::size_type z;
1993         Row * row = getRow(par, pos, y);
1994         
1995         // is there a break one row above
1996         if (row->previous() && row->previous()->par() == row->par()) {
1997                 z = nextBreakPoint(bview, row->previous(), workWidth(bview));
1998                 if (z >= row->pos()) {
1999                         // set the dimensions of the row above
2000                         y -= row->previous()->height();
2001                         refresh_y = y;
2002                         refresh_row = row->previous();
2003                         status(bview, LyXText::NEED_MORE_REFRESH);
2004                         
2005                         breakAgain(bview, row->previous());
2006                         
2007                         // set the cursor again. Otherwise
2008                         // dangling pointers are possible
2009                         setCursor(bview, cursor.par(), cursor.pos(),
2010                                   false, cursor.boundary());
2011                         selection.cursor = cursor;
2012                         return;
2013                 }
2014         }
2015
2016         int const tmpheight = row->height();
2017         Paragraph::size_type const tmplast = rowLast(row);
2018         refresh_y = y;
2019         refresh_row = row;
2020         
2021         breakAgain(bview, row);
2022         if (row->height() == tmpheight && rowLast(row) == tmplast)
2023                 status(bview, LyXText::NEED_VERY_LITTLE_REFRESH);
2024         else
2025                 status(bview, LyXText::NEED_MORE_REFRESH); 
2026         
2027         // check the special right address boxes
2028         if (textclasslist.Style(bview->buffer()->params.textclass,
2029                                 par->getLayout()).margintype
2030             == MARGIN_RIGHT_ADDRESS_BOX)
2031         {
2032                 tmpcursor.par(par);
2033                 tmpcursor.row(row);
2034                 tmpcursor.y(y);
2035                 tmpcursor.x(0);
2036                 tmpcursor.x_fix(0);
2037                 tmpcursor.pos(pos);
2038                 redoDrawingOfParagraph(bview, tmpcursor); 
2039         }
2040
2041         // set the cursor again. Otherwise dangling pointers are possible
2042         // also set the selection
2043    
2044         if (selection.set()) {
2045                 tmpcursor = cursor;
2046                 setCursorIntern(bview, selection.cursor.par(), selection.cursor.pos(),
2047                                 false, selection.cursor.boundary());
2048                 selection.cursor = cursor; 
2049                 setCursorIntern(bview, selection.start.par(),
2050                                 selection.start.pos(),
2051                                 false, selection.start.boundary());
2052                 selection.start = cursor; 
2053                 setCursorIntern(bview, selection.end.par(),
2054                                 selection.end.pos(),
2055                                 false, selection.end.boundary());
2056                 selection.end = cursor; 
2057                 setCursorIntern(bview, last_sel_cursor.par(),
2058                                 last_sel_cursor.pos(),
2059                                 false, last_sel_cursor.boundary());
2060                 last_sel_cursor = cursor; 
2061                 cursor = tmpcursor;
2062         }
2063         setCursorIntern(bview, cursor.par(), cursor.pos(),
2064                         false, cursor.boundary());
2065 }
2066
2067
2068 // returns false if inset wasn't found
2069 bool LyXText::updateInset(BufferView * bview, Inset * inset)
2070 {
2071         // first check the current paragraph
2072         int pos = cursor.par()->getPositionOfInset(inset);
2073         if (pos != -1) {
2074                 checkParagraph(bview, cursor.par(), pos);
2075                 return true;
2076         }
2077   
2078         // check every paragraph
2079   
2080         Paragraph * par = firstParagraph();
2081         do {
2082                 pos = par->getPositionOfInset(inset);
2083                 if (pos != -1) {
2084                         checkParagraph(bview, par, pos);
2085                         return true;
2086                 }
2087                 par = par->next();
2088         } while (par);
2089   
2090         return false;
2091 }
2092
2093
2094 void LyXText::setCursor(BufferView * bview, Paragraph * par,
2095                         Paragraph::size_type pos, 
2096                         bool setfont, bool boundary) const
2097 {
2098         LyXCursor old_cursor = cursor;
2099         setCursorIntern(bview, par, pos, setfont, boundary);
2100         deleteEmptyParagraphMechanism(bview, old_cursor);
2101 }
2102
2103
2104 void LyXText::setCursor(BufferView *bview, LyXCursor & cur, Paragraph * par,
2105                         Paragraph::size_type pos, bool boundary) const
2106 {
2107         cur.par(par);
2108         cur.pos(pos);
2109         cur.boundary(boundary);
2110
2111         // get the cursor y position in text
2112         int y = 0;
2113         Row * row = getRow(par, pos, y);
2114         // y is now the beginning of the cursor row
2115         y += row->baseline();
2116         // y is now the cursor baseline 
2117         cur.y(y);
2118    
2119         // now get the cursors x position
2120         float x;
2121         float fill_separator;
2122         float fill_hfill;
2123         float fill_label_hfill;
2124         prepareToPrint(bview, row, x, fill_separator, fill_hfill,
2125                        fill_label_hfill);
2126         Paragraph::size_type cursor_vpos = 0;
2127         Paragraph::size_type last = rowLastPrintable(row);
2128
2129         if (pos > last + 1)   // This shouldn't happen.
2130                 pos = last + 1;
2131         else if (pos < row->pos())
2132                 pos = row->pos();
2133
2134         if (last < row->pos())
2135                 cursor_vpos = row->pos();
2136         else if (pos > last && !boundary)
2137                 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2138                         ? row->pos() : last + 1; 
2139         else if (pos > row->pos() &&
2140                  (pos > last || boundary))
2141                 /// Place cursor after char at (logical) position pos - 1
2142                 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2143                         ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2144         else
2145                 /// Place cursor before char at (logical) position pos
2146                 cursor_vpos = (bidi_level(pos) % 2 == 0)
2147                         ? log2vis(pos) : log2vis(pos) + 1;
2148         
2149         Paragraph::size_type main_body =
2150                 beginningOfMainBody(bview->buffer(), row->par());
2151         if ((main_body > 0) &&
2152             ((main_body-1 > last) || 
2153              !row->par()->isLineSeparator(main_body-1)))
2154                 main_body = 0;
2155         
2156         for (Paragraph::size_type vpos = row->pos();
2157              vpos < cursor_vpos; ++vpos) {
2158                 pos = vis2log(vpos);
2159                 if (main_body > 0 && pos == main_body - 1) {
2160                         x += fill_label_hfill +
2161                                 lyxfont::width(textclasslist.Style(
2162                                         bview->buffer()->params.textclass,
2163                                         row->par()->getLayout())
2164                                                .labelsep,
2165                                                getLabelFont(bview->buffer(), row->par()));
2166                         if (row->par()->isLineSeparator(main_body-1))
2167                                 x -= singleWidth(bview, row->par(),main_body-1);
2168                 }
2169                 if (hfillExpansion(bview->buffer(), row, pos)) {
2170                         x += singleWidth(bview, row->par(), pos);
2171                         if (pos >= main_body)
2172                                 x += fill_hfill;
2173                         else 
2174                                 x += fill_label_hfill;
2175                 } else if (row->par()->isSeparator(pos)) {
2176                         x += singleWidth(bview, row->par(), pos);
2177                         if (pos >= main_body)
2178                                 x += fill_separator;
2179                 } else
2180                         x += singleWidth(bview, row->par(), pos);
2181         }
2182         
2183         cur.x(int(x));
2184         cur.x_fix(cur.x());
2185         cur.row(row);
2186 }
2187
2188
2189 void LyXText::setCursorIntern(BufferView * bview, Paragraph * par,
2190                               Paragraph::size_type pos,
2191                               bool setfont, bool boundary) const
2192 {
2193         InsetText * it = static_cast<InsetText *>(par->inInset());
2194         if (it) {
2195                 if (it != inset_owner) {
2196                         lyxerr << "InsetText   is " << it << endl;
2197                         lyxerr << "inset_owner is " << inset_owner << endl;
2198 #warning I believe this code is wrong. (Lgb)
2199 #warning Jürgen, have a look at this. (Lgb)
2200 #warning Hmmm, I guess you are right but we
2201 #warning should verify when this is needed
2202                         // Jürgen, would you like to have a look?
2203                         // I guess we need to move the outer cursor
2204                         // and open and lock the inset (bla bla bla)
2205                         // stuff I don't know... so can you have a look?
2206                         // (Lgb)
2207                         // I moved the lyxerr stuff in here so we can see if
2208                         // this is actually really needed and where!
2209                         // (Jug)
2210                         it->getLyXText(bview)->setCursorIntern(bview, par, pos, setfont,
2211                                                                boundary);
2212                         return;
2213                 }
2214         }
2215         
2216         setCursor(bview, cursor, par, pos, boundary);
2217         if (setfont)
2218                 setCurrentFont(bview);
2219 }
2220
2221
2222 void LyXText::setCurrentFont(BufferView * bview) const
2223 {
2224         Paragraph::size_type pos = cursor.pos();
2225         if (cursor.boundary() && pos > 0)
2226                 --pos;
2227
2228         if (pos > 0) {
2229                 if (pos == cursor.par()->size())
2230                         --pos;
2231                 else // potentional bug... BUG (Lgb)
2232                         if (cursor.par()->isSeparator(pos)) {
2233                                 if (pos > cursor.row()->pos() &&
2234                                     bidi_level(pos) % 2 == 
2235                                     bidi_level(pos - 1) % 2)
2236                                         --pos;
2237                                 else if (pos + 1 < cursor.par()->size())
2238                                         ++pos;
2239                         }
2240         }
2241
2242         current_font =
2243                 cursor.par()->getFontSettings(bview->buffer()->params, pos);
2244         real_current_font = getFont(bview->buffer(), cursor.par(), pos);
2245
2246         if (cursor.pos() == cursor.par()->size() &&
2247             isBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2248             !cursor.boundary()) {
2249                 Language const * lang =
2250                         cursor.par()->getParLanguage(bview->buffer()->params);
2251                 current_font.setLanguage(lang);
2252                 current_font.setNumber(LyXFont::OFF);
2253                 real_current_font.setLanguage(lang);
2254                 real_current_font.setNumber(LyXFont::OFF);
2255         }
2256 }
2257
2258
2259 void LyXText::setCursorFromCoordinates(BufferView * bview, int x, int y) const
2260 {
2261         LyXCursor old_cursor = cursor;
2262
2263         setCursorFromCoordinates(bview, cursor, x, y);
2264         setCurrentFont(bview);
2265         deleteEmptyParagraphMechanism(bview, old_cursor);
2266 }
2267
2268
2269 void LyXText::setCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2270                                        int x, int y) const
2271 {
2272         // Get the row first.
2273    
2274         Row * row = getRowNearY(y);
2275         bool bound = false;
2276         Paragraph::size_type const column = getColumnNearX(bview, row, x,
2277                                                            bound);
2278    
2279         cur.par(row->par());
2280         cur.pos(row->pos() + column);
2281         cur.x(x);
2282         cur.y(y + row->baseline());
2283         cur.row(row);
2284         cur.boundary(bound);
2285 }
2286
2287
2288 void LyXText::cursorLeft(BufferView * bview, bool internal) const
2289 {
2290         if (cursor.pos() > 0) {
2291                 bool boundary = cursor.boundary();
2292                 setCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2293                 if (!internal && !boundary &&
2294                     isBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2295                         setCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2296         } else if (cursor.par()->previous()) { // steps into the above paragraph.
2297                 Paragraph * par = cursor.par()->previous();
2298                 setCursor(bview, par, par->size());
2299         }
2300 }
2301
2302
2303 void LyXText::cursorRight(BufferView * bview, bool internal) const
2304 {
2305         if (!internal && cursor.boundary() &&
2306             !cursor.par()->isNewline(cursor.pos()))
2307                 setCursor(bview, cursor.par(), cursor.pos(), true, false);
2308         else if (cursor.pos() < cursor.par()->size()) {
2309                 setCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2310                 if (!internal &&
2311                     isBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2312                         setCursor(bview, cursor.par(), cursor.pos(), true, true);
2313         } else if (cursor.par()->next())
2314                 setCursor(bview, cursor.par()->next(), 0);
2315 }
2316
2317
2318 void LyXText::cursorUp(BufferView * bview) const
2319 {
2320         setCursorFromCoordinates(bview, cursor.x_fix(), 
2321                                  cursor.y() - cursor.row()->baseline() - 1);
2322 }
2323
2324
2325 void LyXText::cursorDown(BufferView * bview) const
2326 {
2327         setCursorFromCoordinates(bview, cursor.x_fix(), 
2328                                  cursor.y() - cursor.row()->baseline()
2329                                  + cursor.row()->height() + 1);
2330 }
2331
2332
2333 void LyXText::cursorUpParagraph(BufferView * bview) const
2334 {
2335         if (cursor.pos() > 0) {
2336                 setCursor(bview, cursor.par(), 0);
2337         }
2338         else if (cursor.par()->previous()) {
2339                 setCursor(bview, cursor.par()->previous(), 0);
2340         }
2341 }
2342
2343
2344 void LyXText::cursorDownParagraph(BufferView * bview) const
2345 {
2346         if (cursor.par()->next()) {
2347                 setCursor(bview, cursor.par()->next(), 0);
2348         } else {
2349                 setCursor(bview, cursor.par(), cursor.par()->size());
2350         }
2351 }
2352
2353 // fix the cursor `cur' after a characters has been deleted at `where'
2354 // position. Called by deleteEmptyParagraphMechanism
2355 void LyXText::fixCursorAfterDelete(BufferView * bview,
2356                                    LyXCursor & cur,
2357                                    LyXCursor const & where) const
2358 {
2359         // if cursor is not in the paragraph where the delete occured,
2360         // do nothing
2361         if (cur.par() != where.par())
2362                 return;
2363
2364         // if cursor position is after the place where the delete occured,
2365         // update it
2366         if (cur.pos() > where.pos())
2367                 cur.pos(cur.pos()-1);
2368
2369         // recompute row et al. for this cursor
2370         setCursor(bview, cur, cur.par(), cur.pos(), cur.boundary());
2371 }
2372
2373
2374 void LyXText::deleteEmptyParagraphMechanism(BufferView * bview,
2375                                             LyXCursor const & old_cursor) const
2376 {
2377         // Would be wrong to delete anything if we have a selection.
2378         if (selection.set()) return;
2379
2380         // We allow all kinds of "mumbo-jumbo" when freespacing.
2381         if (textclasslist.Style(bview->buffer()->params.textclass,
2382                                 old_cursor.par()->getLayout()).free_spacing)
2383                 return;
2384
2385         bool deleted = false;
2386         
2387         /* Ok I'll put some comments here about what is missing.
2388            I have fixed BackSpace (and thus Delete) to not delete
2389            double-spaces automagically. I have also changed Cut,
2390            Copy and Paste to hopefully do some sensible things.
2391            There are still some small problems that can lead to
2392            double spaces stored in the document file or space at
2393            the beginning of paragraphs. This happens if you have
2394            the cursor betwenn to spaces and then save. Or if you
2395            cut and paste and the selection have a space at the
2396            beginning and then save right after the paste. I am
2397            sure none of these are very hard to fix, but I will
2398            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2399            that I can get some feedback. (Lgb)
2400         */
2401
2402         // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2403         // delete the LineSeparator.
2404         // MISSING
2405
2406         // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2407         // delete the LineSeparator.
2408         // MISSING
2409
2410         // If the pos around the old_cursor were spaces, delete one of them.
2411         if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) { 
2412                 // Only if the cursor has really moved
2413                 
2414                 if (old_cursor.pos() > 0
2415                     && old_cursor.pos() < old_cursor.par()->size()
2416                     && old_cursor.par()->isLineSeparator(old_cursor.pos())
2417                     && old_cursor.par()->isLineSeparator(old_cursor.pos() - 1)) {
2418                         old_cursor.par()->erase(old_cursor.pos() - 1);
2419                         redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2420
2421 #ifdef WITH_WARNINGS
2422 #warning This will not work anymore when we have multiple views of the same buffer
2423 // In this case, we will have to correct also the cursors held by
2424 // other bufferviews. It will probably be easier to do that in a more
2425 // automated way in LyXCursor code. (JMarc 26/09/2001)
2426 #endif
2427                         // correct all cursors held by the LyXText
2428                         fixCursorAfterDelete(bview, cursor, old_cursor);
2429                         fixCursorAfterDelete(bview, selection.cursor,
2430                                              old_cursor);
2431                         fixCursorAfterDelete(bview, selection.start,
2432                                              old_cursor);
2433                         fixCursorAfterDelete(bview, selection.end, old_cursor);
2434                         fixCursorAfterDelete(bview, last_sel_cursor,
2435                                              old_cursor);
2436                         fixCursorAfterDelete(bview, toggle_cursor, old_cursor);
2437                         fixCursorAfterDelete(bview, toggle_end_cursor,
2438                                              old_cursor);
2439                         return;
2440                 }
2441         }
2442
2443         // Do not delete empty paragraphs with keepempty set.
2444         if ((textclasslist.Style(bview->buffer()->params.textclass,
2445                                  old_cursor.par()->getLayout())).keepempty)
2446                 return;
2447
2448         // only do our magic if we changed paragraph
2449         if (old_cursor.par() == cursor.par()) 
2450                 return;
2451         
2452         if ((old_cursor.par()->size() == 0
2453              || (old_cursor.par()->size() == 1
2454                  && old_cursor.par()->isLineSeparator(0)))) {
2455                 // ok, we will delete anything
2456                 LyXCursor tmpcursor;
2457                 
2458                 // make sure that you do not delete any environments
2459                 status(bview, LyXText::NEED_MORE_REFRESH);
2460                 deleted = true;
2461                                 
2462                 if (old_cursor.row()->previous()) {
2463                         refresh_row = old_cursor.row()->previous();
2464                         refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2465                         tmpcursor = cursor;
2466                         cursor = old_cursor; // that undo can restore the right cursor position
2467                         Paragraph * endpar = old_cursor.par()->next();
2468                         if (endpar && endpar->getDepth()) {
2469                                 while (endpar && endpar->getDepth()) {
2470                                         endpar = endpar->next();
2471                                 }
2472                         }
2473                         setUndo(bview, Undo::DELETE, old_cursor.par(), endpar);
2474                         cursor = tmpcursor;
2475
2476                                 // delete old row
2477                         removeRow(old_cursor.row());
2478                         if (ownerParagraph() == old_cursor.par()) {
2479                                 ownerParagraph(ownerParagraph()->next());
2480                         }
2481                                 // delete old par
2482                         delete old_cursor.par();
2483                                         
2484                         /* Breakagain the next par. Needed because of
2485                          * the parindent that can occur or dissappear.
2486                          * The next row can change its height, if
2487                          * there is another layout before */
2488                         if (refresh_row->next()) {
2489                                 breakAgain(bview, refresh_row->next());
2490                                 updateCounters(bview, refresh_row);
2491                         }
2492                         setHeightOfRow(bview, refresh_row);
2493                 } else {
2494                         refresh_row = old_cursor.row()->next();
2495                         refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2496                                         
2497                         tmpcursor = cursor;
2498                         cursor = old_cursor; // that undo can restore the right cursor position
2499                         Paragraph * endpar = old_cursor.par()->next();
2500                         if (endpar && endpar->getDepth()) {
2501                                 while (endpar && endpar->getDepth()) {
2502                                         endpar = endpar->next();
2503                                 }
2504                         }
2505                         setUndo(bview, Undo::DELETE, old_cursor.par(), endpar);
2506                         cursor = tmpcursor;
2507
2508                         // delete old row
2509                         removeRow(old_cursor.row());
2510                         // delete old par
2511                         if (ownerParagraph() == old_cursor.par()) {
2512                                 ownerParagraph(ownerParagraph()->next());
2513                         }
2514
2515                         delete old_cursor.par();
2516                                         
2517                         /* Breakagain the next par. Needed because of
2518                            the parindent that can occur or dissappear.
2519                            The next row can change its height, if
2520                            there is another layout before */
2521                         if (refresh_row) {
2522                                 breakAgain(bview, refresh_row);
2523                                 updateCounters(bview, refresh_row->previous());
2524                         }
2525                 }
2526                                 
2527                 // correct cursor y
2528                 setCursorIntern(bview, cursor.par(), cursor.pos());
2529
2530                 if (selection.cursor.par()  == old_cursor.par()
2531                     && selection.cursor.pos() == selection.cursor.pos()) {
2532                         // correct selection
2533                         selection.cursor = cursor;
2534                 }
2535         }
2536         if (!deleted) {
2537                 if (old_cursor.par()->stripLeadingSpaces(bview->buffer()->params.textclass)) {
2538                         redoParagraphs(bview, old_cursor,
2539                                        old_cursor.par()->next());
2540                         // correct cursor y
2541                         setCursorIntern(bview, cursor.par(), cursor.pos());
2542                         selection.cursor = cursor;
2543                 }
2544         }
2545 }
2546
2547
2548 void LyXText::toggleAppendix(BufferView * bview)
2549 {
2550         Paragraph * par = cursor.par();
2551         bool start = !par->params().startOfAppendix();
2552
2553         // ensure that we have only one start_of_appendix in this document
2554         Paragraph * tmp = firstParagraph();
2555         for (; tmp; tmp = tmp->next()) {
2556                 tmp->params().startOfAppendix(false);
2557         }
2558         
2559         par->params().startOfAppendix(start);
2560
2561         // we can set the refreshing parameters now
2562         status(bview, LyXText::NEED_MORE_REFRESH);
2563         refresh_y = 0;
2564         refresh_row = 0; // not needed for full update
2565         updateCounters(bview, 0);
2566         setCursor(bview, cursor.par(), cursor.pos());
2567 }
2568
2569
2570 Paragraph * LyXText::ownerParagraph() const
2571 {
2572         if (inset_owner) {
2573                 return inset_owner->paragraph();
2574         }
2575         return bv_owner->buffer()->paragraph;
2576 }
2577
2578
2579 void LyXText::ownerParagraph(Paragraph * p) const
2580 {
2581         if (inset_owner) {
2582                 inset_owner->paragraph(p);
2583         } else {
2584                 bv_owner->buffer()->paragraph = p;
2585         }
2586 }
2587
2588
2589 void LyXText::ownerParagraph(int id, Paragraph * p) const
2590 {
2591         Paragraph * op = bv_owner->buffer()->getParFromID(id);
2592         if (op && op->inInset()) {
2593                 static_cast<InsetText *>(op->inInset())->paragraph(p);
2594         } else {
2595                 if (inset_owner) {
2596                         inset_owner->paragraph(p);
2597                 } else {
2598                         bv_owner->buffer()->paragraph = p;
2599                 }
2600         }
2601 }
2602
2603
2604 LyXText::text_status LyXText::status() const
2605 {
2606         return status_;
2607 }
2608
2609
2610 void LyXText::status(BufferView * bview, LyXText::text_status st) const
2611 {
2612         // well as much as I know && binds more then || so the above and the
2613         // below are identical (this for your known use of parentesis!)
2614         // Now some explanation:
2615         // We should only go up with refreshing code so this means that if
2616         // we have a MORE refresh we should never set it to LITTLE if we still
2617         // didn't handle it (and then it will be UNCHANGED. Now as long as
2618         // we stay inside one LyXText this may work but we need to tell the
2619         // outermost LyXText that it should REALLY draw us if there is some
2620         // change in a Inset::LyXText. So you see that when we are inside a
2621         // inset's LyXText we give the LITTLE to the outermost LyXText to
2622         // tell'em that it should redraw the actual row (where the inset
2623         // resides! Capito?!
2624
2625         if ((status_ != NEED_MORE_REFRESH)
2626             || (status_ == NEED_MORE_REFRESH
2627                 && st != NEED_VERY_LITTLE_REFRESH))
2628         {
2629                 status_ = st;
2630                 if (inset_owner && st != UNCHANGED) {
2631                         bview->text->status(bview, NEED_VERY_LITTLE_REFRESH);
2632                         if (!bview->text->refresh_row) {
2633                                 bview->text->refresh_row = bview->text->cursor.row();
2634                                 bview->text->refresh_y = bview->text->cursor.y() -
2635                                         bview->text->cursor.row()->baseline();
2636                         }
2637                 }
2638         }
2639 }