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