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