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