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