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