]> git.lyx.org Git - lyx.git/blob - src/text2.C
various 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::HIGHLY_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, tmpfont;
427         for (Paragraph::size_type pos = 0;
428              pos < par->size(); ++pos) {
429                 if (pos < beginningOfMainBody(buf, par))
430                         layoutfont = layout.labelfont;
431                 else
432                         layoutfont = layout.font;
433       
434                 tmpfont = par->getFontSettings(buf->params, pos);
435                 tmpfont.reduce(layoutfont);
436                 par->setFont(pos, tmpfont);
437         }
438 }
439
440
441 Paragraph * LyXText::setLayout(BufferView * bview,
442                                LyXCursor & cur, LyXCursor & sstart_cur,
443                                LyXCursor & send_cur,
444                                LyXTextClass::size_type layout)
445 {
446         Paragraph * endpar = send_cur.par()->next();
447         Paragraph * undoendpar = endpar;
448         
449         if (endpar && endpar->getDepth()) {
450                 while (endpar && endpar->getDepth()) {
451                         endpar = endpar->next();
452                         undoendpar = endpar;
453                 }
454         } else if (endpar) {
455                 endpar = endpar->next(); // because of parindents etc.
456         }
457         
458         setUndo(bview, Undo::EDIT,
459                 sstart_cur.par(), undoendpar);
460         
461         // ok we have a selection. This is always between sstart_cur
462         // and sel_end cursor
463         cur = sstart_cur;
464         
465         LyXLayout const & lyxlayout =
466                 textclasslist.Style(bview->buffer()->params.textclass, layout);
467         
468         while (cur.par() != send_cur.par()) {
469                 cur.par()->setLayout(layout);
470                 makeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
471                 Paragraph * fppar = cur.par();
472                 fppar->params().spaceTop(lyxlayout.fill_top ?
473                                          VSpace(VSpace::VFILL)
474                                          : VSpace(VSpace::NONE));
475                 fppar->params().spaceBottom(lyxlayout.fill_bottom ? 
476                                             VSpace(VSpace::VFILL)
477                                             : VSpace(VSpace::NONE));
478                 if (lyxlayout.margintype == MARGIN_MANUAL)
479                         cur.par()->setLabelWidthString(lyxlayout.labelstring());
480                 if (lyxlayout.labeltype != LABEL_BIBLIO
481                     && fppar->bibkey) {
482                         delete fppar->bibkey;
483                         fppar->bibkey = 0;
484                 }
485                 cur.par(cur.par()->next());
486         }
487         cur.par()->setLayout(layout);
488         makeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
489         Paragraph * fppar = cur.par();
490         fppar->params().spaceTop(lyxlayout.fill_top ?
491                                  VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
492         fppar->params().spaceBottom(lyxlayout.fill_bottom ? 
493                                     VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
494         if (lyxlayout.margintype == MARGIN_MANUAL)
495                 cur.par()->setLabelWidthString(lyxlayout.labelstring());
496         if (lyxlayout.labeltype != LABEL_BIBLIO
497             && fppar->bibkey) {
498                 delete fppar->bibkey;
499                 fppar->bibkey = 0;
500         }
501         return endpar;
502 }
503
504
505 // set layout over selection and make a total rebreak of those paragraphs
506 void LyXText::setLayout(BufferView * bview, LyXTextClass::size_type layout)
507 {
508         LyXCursor tmpcursor = cursor;  /* store the current cursor  */
509
510         // if there is no selection just set the layout
511         // of the current paragraph  */
512         if (!selection.set()) {
513                 selection.start = cursor;  // dummy selection
514                 selection.end = cursor;
515         }
516         Paragraph * endpar = setLayout(bview, cursor, selection.start,
517                                        selection.end, layout);
518         redoParagraphs(bview, selection.start, endpar);
519    
520         // we have to reset the selection, because the
521         // geometry could have changed
522         setCursor(bview, selection.start.par(),
523                   selection.start.pos(), false);
524         selection.cursor = cursor;
525         setCursor(bview, selection.end.par(), selection.end.pos(), false);
526         updateCounters(bview, cursor.row());
527         clearSelection(bview);
528         setSelection(bview);
529         setCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
530 }
531
532
533 // increment depth over selection and
534 // make a total rebreak of those paragraphs
535 void  LyXText::incDepth(BufferView * bview)
536 {
537         // If there is no selection, just use the current paragraph
538         if (!selection.set()) {
539                 selection.start = cursor; // dummy selection
540                 selection.end = cursor;
541         }
542
543         // We end at the next paragraph with depth 0
544         Paragraph * endpar = selection.end.par()->next();
545
546         Paragraph * undoendpar = endpar;
547
548         if (endpar && endpar->getDepth()) {
549                 while (endpar && endpar->getDepth()) {
550                         endpar = endpar->next();
551                         undoendpar = endpar;
552                 }
553         } else if (endpar) {
554                 endpar = endpar->next(); // because of parindents etc.
555         }
556         
557         setUndo(bview, Undo::EDIT,
558                 selection.start.par(), undoendpar);
559
560         LyXCursor tmpcursor = cursor; // store the current cursor
561
562         // ok we have a selection. This is always between sel_start_cursor
563         // and sel_end cursor
564         cursor = selection.start;
565    
566         bool anything_changed = false;
567    
568         while (true) {
569                 // NOTE: you can't change the depth of a bibliography entry
570                 if (
571                         textclasslist.Style(bview->buffer()->params.textclass,
572                                             cursor.par()->getLayout()
573                                 ).labeltype != LABEL_BIBLIO) {
574                         Paragraph * prev = cursor.par()->previous();
575
576                         if (prev 
577                             && (prev->getDepth() - cursor.par()->getDepth() > 0
578                                 || (prev->getDepth() == cursor.par()->getDepth()
579                                     && textclasslist.Style(bview->buffer()->params.textclass,
580                                                            prev->getLayout()).isEnvironment()))) {
581                                 cursor.par()->params().depth(cursor.par()->params().depth() + 1);
582                                 anything_changed = true;
583                         }
584                 }
585                 if (cursor.par() == selection.end.par())
586                         break;
587                 cursor.par(cursor.par()->next());
588         }
589    
590         // if nothing changed set all depth to 0
591         if (!anything_changed) {
592                 cursor = selection.start;
593                 while (cursor.par() != selection.end.par()) {
594                         cursor.par()->params().depth(0);
595                         cursor.par(cursor.par()->next());
596                 }
597                 cursor.par()->params().depth(0);
598         }
599    
600         redoParagraphs(bview, selection.start, endpar);
601    
602         // we have to reset the selection, because the
603         // geometry could have changed
604         setCursor(bview, selection.start.par(), selection.start.pos());
605         selection.cursor = cursor;
606         setCursor(bview, selection.end.par(), selection.end.pos());
607         updateCounters(bview, cursor.row());
608         clearSelection(bview);
609         setSelection(bview);
610         setCursor(bview, tmpcursor.par(), tmpcursor.pos());
611 }
612
613
614 // decrement depth over selection and
615 // make a total rebreak of those paragraphs
616 void  LyXText::decDepth(BufferView * bview)
617 {
618         // if there is no selection just set the layout
619         // of the current paragraph
620         if (!selection.set()) {
621                 selection.start = cursor; // dummy selection
622                 selection.end = cursor;
623         }
624         Paragraph * endpar = selection.end.par()->next();
625         Paragraph * undoendpar = endpar;
626
627         if (endpar && endpar->getDepth()) {
628                 while (endpar && endpar->getDepth()) {
629                         endpar = endpar->next();
630                         undoendpar = endpar;
631                 }
632         } else if (endpar) {
633                 endpar = endpar->next(); // because of parindents etc.
634         }
635    
636         setUndo(bview, Undo::EDIT,
637                 selection.start.par(), undoendpar);
638
639         LyXCursor tmpcursor = cursor; // store the current cursor
640
641         // ok we have a selection. This is always between sel_start_cursor
642         // and sel_end cursor
643         cursor = selection.start;
644
645         while (true) {
646                 if (cursor.par()->params().depth()) {
647                         cursor.par()->params()
648                                 .depth(cursor.par()->params().depth() - 1);
649                 }
650                 if (cursor.par() == selection.end.par()) {
651                         break;
652                 }
653                 cursor.par(cursor.par()->next());
654         }
655
656         redoParagraphs(bview, selection.start, endpar);
657    
658         // we have to reset the selection, because the
659         // geometry could have changed
660         setCursor(bview, selection.start.par(),
661                   selection.start.pos());
662         selection.cursor = cursor;
663         setCursor(bview, selection.end.par(), selection.end.pos());
664         updateCounters(bview, cursor.row());
665         clearSelection(bview);
666         setSelection(bview);
667         setCursor(bview, tmpcursor.par(), tmpcursor.pos());
668 }
669
670
671 // set font over selection and make a total rebreak of those paragraphs
672 void LyXText::setFont(BufferView * bview, LyXFont const & font, bool toggleall)
673 {
674         // if there is no selection just set the current_font
675         if (!selection.set()) {
676                 // Determine basis font
677                 LyXFont layoutfont;
678                 if (cursor.pos() < beginningOfMainBody(bview->buffer(),
679                                                        cursor.par()))
680                         layoutfont = getFont(bview->buffer(), cursor.par(),-2);
681                 else
682                         layoutfont = getFont(bview->buffer(), cursor.par(),-1);
683                 // Update current font
684                 real_current_font.update(font, toggleall);
685
686                 // Reduce to implicit settings
687                 current_font = real_current_font;
688                 current_font.reduce(layoutfont);
689                 // And resolve it completely
690                 real_current_font.realize(layoutfont,
691                                           bview->buffer()->params.language);
692                 return;
693         }
694
695         LyXCursor tmpcursor = cursor; // store the current cursor
696    
697         // ok we have a selection. This is always between sel_start_cursor
698         // and sel_end cursor
699    
700         setUndo(bview, Undo::EDIT,
701                 selection.start.par(),
702                 selection.end.par()->next()); 
703         freezeUndo();
704         cursor = selection.start;
705         while (cursor.par() != selection.end.par() ||
706                (cursor.pos() < selection.end.pos())) {
707                 if (cursor.pos() < cursor.par()->size()) {
708                         // an open footnote should behave
709                         // like a closed one
710                         setCharFont(bview, cursor.par(), cursor.pos(),
711                                     font, toggleall);
712                         cursor.pos(cursor.pos() + 1);
713                 } else {
714                         cursor.pos(0);
715                         cursor.par(cursor.par()->next());
716                 }
717         }
718         unFreezeUndo();
719    
720         redoParagraphs(bview, selection.start, selection.end.par()->next());
721    
722         // we have to reset the selection, because the
723         // geometry could have changed
724         setCursor(bview, selection.start.par(), selection.start.pos());
725         selection.cursor = cursor;
726         setCursor(bview, selection.end.par(), selection.end.pos());
727         clearSelection(bview);
728         setSelection(bview);
729         setCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
730                   tmpcursor.boundary());
731 }
732
733
734 void LyXText::redoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
735 {
736         Row * tmprow = cur.row();
737         int y = cur.y() - tmprow->baseline();
738
739         setHeightOfRow(bview, tmprow);
740         
741         while (tmprow->previous()
742                && tmprow->previous()->par() == tmprow->par()) {
743                 tmprow = tmprow->previous();
744                 y -= tmprow->height();
745                 setHeightOfRow(bview, tmprow);
746         }
747         
748         // we can set the refreshing parameters now
749         status(bview, LyXText::NEED_MORE_REFRESH);
750         refresh_y = y;
751         refresh_row = tmprow;
752         setCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
753 }
754
755
756 void LyXText::redoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
757 {
758         Row * tmprow = cur.row();
759    
760         int y = cur.y() - tmprow->baseline();
761         setHeightOfRow(bview, tmprow);
762
763         while (tmprow->previous()
764                && tmprow->previous()->par() == tmprow->par())  {
765                 tmprow = tmprow->previous();
766                 y -= tmprow->height();
767         }
768
769         // we can set the refreshing parameters now
770         if (status_ == LyXText::UNCHANGED || y < refresh_y) {
771                 refresh_y = y;
772                 refresh_row = tmprow;
773         }
774         status(bview, LyXText::NEED_MORE_REFRESH);
775         setCursor(bview, cur.par(), cur.pos());
776 }
777
778
779 // deletes and inserts again all paragaphs between the cursor
780 // and the specified par 
781 // This function is needed after SetLayout and SetFont etc.
782 void LyXText::redoParagraphs(BufferView * bview, LyXCursor const & cur,
783                              Paragraph const * endpar) const
784 {
785         Row * tmprow2;
786         Paragraph * tmppar = 0;
787         Paragraph * first_phys_par = 0;
788    
789         Row * tmprow = cur.row();
790    
791         int y = cur.y() - tmprow->baseline();
792
793         if (!tmprow->previous()) {
794                 // a trick/hack for UNDO
795                 // Can somebody please tell me _why_ this solves
796                 // anything. (Lgb)
797                 first_phys_par = firstParagraph();
798         } else {
799                 first_phys_par = tmprow->par();
800                 while (tmprow->previous()
801                        && tmprow->previous()->par() == first_phys_par) {
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(BufferView * /*bview*/) 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(bview);
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(bview);
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(bview);
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(bview);
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(bview);
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(bview);
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         // Get the row first. 
2167    
2168         Row * row = getRowNearY(y);
2169         cursor.par(row->par());
2170
2171         bool bound = false;
2172         int column = getColumnNearX(bview, row, x, bound);
2173         cursor.pos(row->pos() + column);
2174         cursor.x(x);
2175         cursor.y(y + row->baseline());
2176         cursor.row(row);
2177         cursor.boundary(bound);
2178         setCurrentFont(bview);
2179         deleteEmptyParagraphMechanism(bview, old_cursor);
2180 }
2181
2182
2183 void LyXText::setCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2184                                        int x, int y) const
2185 {
2186         // Get the row first.
2187    
2188         Row * row = getRowNearY(y);
2189         bool bound = false;
2190         int column = getColumnNearX(bview, row, x, bound);
2191    
2192         cur.par(row->par());
2193         cur.pos(row->pos() + column);
2194         cur.x(x);
2195         cur.y(y + row->baseline());
2196         cur.row(row);
2197         cur.boundary(bound);
2198 }
2199
2200
2201 void LyXText::cursorLeft(BufferView * bview, bool internal) const
2202 {
2203         if (cursor.pos() > 0) {
2204                 bool boundary = cursor.boundary();
2205                 setCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2206                 if (!internal && !boundary &&
2207                     isBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2208                         setCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2209         } else if (cursor.par()->previous()) { // steps into the above paragraph.
2210                 Paragraph * par = cursor.par()->previous();
2211                 setCursor(bview, par, par->size());
2212         }
2213 }
2214
2215
2216 void LyXText::cursorRight(BufferView * bview, bool internal) const
2217 {
2218         if (!internal && cursor.boundary() &&
2219             !cursor.par()->isNewline(cursor.pos()))
2220                 setCursor(bview, cursor.par(), cursor.pos(), true, false);
2221         else if (cursor.pos() < cursor.par()->size()) {
2222                 setCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2223                 if (!internal &&
2224                     isBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2225                         setCursor(bview, cursor.par(), cursor.pos(), true, true);
2226         } else if (cursor.par()->next())
2227                 setCursor(bview, cursor.par()->next(), 0);
2228 }
2229
2230
2231 void LyXText::cursorUp(BufferView * bview) const
2232 {
2233         setCursorFromCoordinates(bview, cursor.x_fix(), 
2234                                  cursor.y() - cursor.row()->baseline() - 1);
2235 }
2236
2237
2238 void LyXText::cursorDown(BufferView * bview) const
2239 {
2240         setCursorFromCoordinates(bview, cursor.x_fix(), 
2241                                  cursor.y() - cursor.row()->baseline()
2242                                  + cursor.row()->height() + 1);
2243 }
2244
2245
2246 void LyXText::cursorUpParagraph(BufferView * bview) const
2247 {
2248         if (cursor.pos() > 0) {
2249                 setCursor(bview, cursor.par(), 0);
2250         }
2251         else if (cursor.par()->previous()) {
2252                 setCursor(bview, cursor.par()->previous(), 0);
2253         }
2254 }
2255
2256
2257 void LyXText::cursorDownParagraph(BufferView * bview) const
2258 {
2259         if (cursor.par()->next()) {
2260                 setCursor(bview, cursor.par()->next(), 0);
2261         } else {
2262                 setCursor(bview, cursor.par(), cursor.par()->size());
2263         }
2264 }
2265
2266
2267 void LyXText::deleteEmptyParagraphMechanism(BufferView * bview,
2268                                             LyXCursor const & old_cursor) const
2269 {
2270         // Would be wrong to delete anything if we have a selection.
2271         if (selection.set()) return;
2272
2273         // We allow all kinds of "mumbo-jumbo" when freespacing.
2274         if (textclasslist.Style(bview->buffer()->params.textclass,
2275                                 old_cursor.par()->getLayout()).free_spacing)
2276                 return;
2277
2278         bool deleted = false;
2279         
2280         /* Ok I'll put some comments here about what is missing.
2281            I have fixed BackSpace (and thus Delete) to not delete
2282            double-spaces automagically. I have also changed Cut,
2283            Copy and Paste to hopefully do some sensible things.
2284            There are still some small problems that can lead to
2285            double spaces stored in the document file or space at
2286            the beginning of paragraphs. This happens if you have
2287            the cursor betwenn to spaces and then save. Or if you
2288            cut and paste and the selection have a space at the
2289            beginning and then save right after the paste. I am
2290            sure none of these are very hard to fix, but I will
2291            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2292            that I can get some feedback. (Lgb)
2293         */
2294
2295         // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2296         // delete the LineSeparator.
2297         // MISSING
2298
2299         // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2300         // delete the LineSeparator.
2301         // MISSING
2302
2303         // If the pos around the old_cursor were spaces, delete one of them.
2304         if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) { 
2305                 // Only if the cursor has really moved
2306                 
2307                 if (old_cursor.pos() > 0
2308                     && old_cursor.pos() < old_cursor.par()->size()
2309                     && old_cursor.par()->isLineSeparator(old_cursor.pos())
2310                     && old_cursor.par()->isLineSeparator(old_cursor.pos() - 1)) {
2311                         old_cursor.par()->erase(old_cursor.pos() - 1);
2312                         redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2313                         // correct cursor
2314                         if (old_cursor.par() == cursor.par() &&
2315                             cursor.pos() > old_cursor.pos()) {
2316                                 setCursorIntern(bview, cursor.par(),
2317                                                 cursor.pos() - 1);
2318                         } else
2319                                 setCursorIntern(bview, cursor.par(),
2320                                                 cursor.pos());
2321                         return;
2322                 }
2323         }
2324
2325         // Do not delete empty paragraphs with keepempty set.
2326         if ((textclasslist.Style(bview->buffer()->params.textclass,
2327                                  old_cursor.par()->getLayout())).keepempty)
2328                 return;
2329
2330         LyXCursor tmpcursor;
2331
2332         if (old_cursor.par() != cursor.par()) {
2333                 if ((old_cursor.par()->size() == 0
2334                      || (old_cursor.par()->size() == 1
2335                          && old_cursor.par()->isLineSeparator(0)))) {
2336                         // ok, we will delete anything
2337                         
2338                         // make sure that you do not delete any environments
2339                         status(bview, LyXText::NEED_MORE_REFRESH);
2340                         deleted = true;
2341                                 
2342                         if (old_cursor.row()->previous()) {
2343                                 refresh_row = old_cursor.row()->previous();
2344                                 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2345                                 tmpcursor = cursor;
2346                                 cursor = old_cursor; // that undo can restore the right cursor position
2347                                 Paragraph * endpar = old_cursor.par()->next();
2348                                 if (endpar && endpar->getDepth()) {
2349                                         while (endpar && endpar->getDepth()) {
2350                                                 endpar = endpar->next();
2351                                         }
2352                                 }
2353                                 setUndo(bview, Undo::DELETE,
2354                                         old_cursor.par(),
2355                                         endpar);
2356                                 cursor = tmpcursor;
2357
2358                                 // delete old row
2359                                 removeRow(old_cursor.row());
2360                                 if (ownerParagraph() == old_cursor.par()) {
2361                                         ownerParagraph(ownerParagraph()->next());
2362                                 }
2363                                 // delete old par
2364                                 delete old_cursor.par();
2365                                         
2366                                 /* Breakagain the next par. Needed
2367                                  * because of the parindent that
2368                                  * can occur or dissappear. The
2369                                  * next row can change its height,
2370                                  * if there is another layout before */
2371                                 if (refresh_row->next()) {
2372                                         breakAgain(bview, refresh_row->next());
2373                                         updateCounters(bview, refresh_row);
2374                                 }
2375                                 setHeightOfRow(bview, refresh_row);
2376                         } else {
2377                                 refresh_row = old_cursor.row()->next();
2378                                 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2379                                         
2380                                 tmpcursor = cursor;
2381                                 cursor = old_cursor; // that undo can restore the right cursor position
2382                                 Paragraph * endpar = old_cursor.par()->next();
2383                                 if (endpar && endpar->getDepth()) {
2384                                         while (endpar && endpar->getDepth()) {
2385                                                 endpar = endpar->next();
2386                                         }
2387                                 }
2388                                 setUndo(bview, Undo::DELETE,
2389                                         old_cursor.par(),
2390                                         endpar);
2391                                 cursor = tmpcursor;
2392
2393                                 // delete old row
2394                                 removeRow(old_cursor.row());
2395                                 // delete old par
2396                                 if (ownerParagraph() == old_cursor.par()) {
2397                                         ownerParagraph(ownerParagraph()->next());
2398                                 }
2399
2400                                 delete old_cursor.par();
2401                                         
2402                                 /* Breakagain the next par. Needed
2403                                    because of the parindent that can
2404                                    occur or dissappear.
2405                                    The next row can change its height,
2406                                    if there is another layout before
2407                                 */ 
2408                                 if (refresh_row) {
2409                                         breakAgain(bview, refresh_row);
2410                                         updateCounters(bview, refresh_row->previous());
2411                                 }
2412                         }
2413                                 
2414                                 // correct cursor y
2415
2416                         setCursorIntern(bview, cursor.par(), cursor.pos());
2417
2418                         if (selection.cursor.par()  == old_cursor.par()
2419                             && selection.cursor.pos() == selection.cursor.pos()) {
2420                                 // correct selection
2421                                 selection.cursor = cursor;
2422                         }
2423                 }
2424                 if (!deleted) {
2425                         if (old_cursor.par()->stripLeadingSpaces(bview->buffer()->params.textclass)) {
2426                                 redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2427                                 // correct cursor y
2428                                 setCursorIntern(bview, cursor.par(), cursor.pos());
2429                                 selection.cursor = cursor;
2430                         }
2431                 }
2432         }
2433 }
2434
2435
2436 void LyXText::toggleAppendix(BufferView * bview)
2437 {
2438         Paragraph * par = cursor.par();
2439         bool start = !par->params().startOfAppendix();
2440
2441         // ensure that we have only one start_of_appendix in this document
2442         Paragraph * tmp = firstParagraph();
2443         for (; tmp; tmp = tmp->next()) {
2444                 tmp->params().startOfAppendix(false);
2445         }
2446         
2447         par->params().startOfAppendix(start);
2448
2449         // we can set the refreshing parameters now
2450         status(bview, LyXText::NEED_MORE_REFRESH);
2451         refresh_y = 0;
2452         refresh_row = 0; // not needed for full update
2453         updateCounters(bview, 0);
2454         setCursor(bview, cursor.par(), cursor.pos());
2455 }
2456
2457
2458 Paragraph * LyXText::ownerParagraph() const
2459 {
2460         if (inset_owner) {
2461                 return inset_owner->paragraph();
2462         }
2463         return bv_owner->buffer()->paragraph;
2464 }
2465
2466
2467 Paragraph * LyXText::ownerParagraph(Paragraph * p) const
2468 {
2469         if (inset_owner) {
2470                 inset_owner->paragraph(p);
2471         } else {
2472                 bv_owner->buffer()->paragraph = p;
2473         }
2474         return 0;
2475 }
2476
2477 Paragraph * LyXText::ownerParagraph(int id, Paragraph * p) const
2478 {
2479         Paragraph * op = bv_owner->buffer()->getParFromID(id);
2480         if (op && op->inInset()) {
2481                 static_cast<InsetText *>(op->inInset())->paragraph(p);
2482         } else {
2483                 if (inset_owner) {
2484                         inset_owner->paragraph(p);
2485                 } else {
2486                         bv_owner->buffer()->paragraph = p;
2487                 }
2488         }
2489         return 0;
2490 }
2491
2492
2493 LyXText::text_status LyXText::status() const
2494 {
2495         return status_;
2496 }
2497
2498
2499 void LyXText::status(BufferView * bview, LyXText::text_status st) const
2500 {
2501 #if 0
2502         if ((status_ != NEED_MORE_REFRESH)
2503             || (status_ == NEED_MORE_REFRESH)
2504             && (st != NEED_VERY_LITTLE_REFRESH)) {
2505                 status_ = st;
2506                 if (inset_owner && st != UNCHANGED) {
2507                         bview->text->status(bview, NEED_VERY_LITTLE_REFRESH);
2508                 }
2509         }
2510 #else
2511 #warning Please tell what the intention is here. (Lgb)
2512         // The above does not make any sense, I changed it to what is here,
2513         // but it still does not make much sense. (Lgb)
2514 #warning Sure have a look now! (Jug)
2515         // well as much as I know && binds more then || so the above and the
2516         // below are identical (this for your known use of parentesis!)
2517         // Now some explanation:
2518         // We should only go up with refreshing code so this means that if
2519         // we have a MORE refresh we should never set it to LITTLE if we still
2520         // didn't handle it (and then it will be UNCHANGED. Now as long as
2521         // we stay inside one LyXText this may work but we need to tell the
2522         // outermost LyXText that it should REALLY draw us if there is some
2523         // change in a Inset::LyXText. So you see that when we are inside a
2524         // inset's LyXText we give the LITTLE to the outermost LyXText to
2525         // tell'em that it should redraw the actual row (where the inset
2526         // resides! Capito?!
2527
2528         if ((status_ != NEED_MORE_REFRESH)
2529             || (status_ == NEED_MORE_REFRESH
2530                 && st != NEED_VERY_LITTLE_REFRESH))
2531         {
2532                 status_ = st;
2533                 if (inset_owner && st != UNCHANGED) {
2534                         bview->text->status(bview, NEED_VERY_LITTLE_REFRESH);
2535                 }
2536         }
2537 #endif
2538 }