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