]> git.lyx.org Git - lyx.git/blob - src/text2.C
8898e4cae0d1b33aec344a1556bf0e7cd67e2029
[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 Paragraph::size_type
1063 LyXText::beginningOfMainBody(Buffer const * buf,
1064                              Paragraph const * par) const
1065 {
1066         if (textclasslist.Style(buf->params.textclass,
1067                                 par->getLayout()).labeltype != LABEL_MANUAL)
1068                 return 0;
1069         else
1070                 return par->beginningOfMainBody();
1071 }
1072
1073
1074 /* the DTP switches for paragraphs. LyX will store them in the 
1075 * first physicla paragraph. When a paragraph is broken, the top settings 
1076 * rest, the bottom settings are given to the new one. So I can make shure, 
1077 * they do not duplicate themself and you cannnot make dirty things with 
1078 * them!  */ 
1079
1080 void LyXText::setParagraph(BufferView * bview,
1081                            bool line_top, bool line_bottom,
1082                            bool pagebreak_top, bool pagebreak_bottom,
1083                            VSpace const & space_top,
1084                            VSpace const & space_bottom,
1085                            LyXAlignment align, 
1086                            string labelwidthstring,
1087                            bool noindent) 
1088 {
1089         LyXCursor tmpcursor = cursor;
1090         if (!selection.set()) {
1091                 selection.start = cursor;
1092                 selection.end = cursor;
1093         }
1094
1095         // make sure that the depth behind the selection are restored, too
1096         Paragraph * endpar = selection.end.par()->next();
1097         Paragraph * undoendpar = endpar;
1098
1099         if (endpar && endpar->getDepth()) {
1100                 while (endpar && endpar->getDepth()) {
1101                         endpar = endpar->next();
1102                         undoendpar = endpar;
1103                 }
1104         }
1105         else if (endpar) {
1106                 // because of parindents etc.
1107                 endpar = endpar->next();
1108         }
1109    
1110         setUndo(bview, Undo::EDIT, selection.start.par(), undoendpar);
1111
1112         
1113         Paragraph * tmppar = selection.end.par();
1114         while (tmppar != selection.start.par()->previous()) {
1115                 setCursor(bview, tmppar, 0);
1116                 status(bview, LyXText::NEED_MORE_REFRESH);
1117                 refresh_row = cursor.row();
1118                 refresh_y = cursor.y() - cursor.row()->baseline();
1119                 cursor.par()->params().lineTop(line_top);
1120                 cursor.par()->params().lineBottom(line_bottom);
1121                 cursor.par()->params().pagebreakTop(pagebreak_top);
1122                 cursor.par()->params().pagebreakBottom(pagebreak_bottom);
1123                 cursor.par()->params().spaceTop(space_top);
1124                 cursor.par()->params().spaceBottom(space_bottom);
1125                 // does the layout allow the new alignment?
1126                 if (align == LYX_ALIGN_LAYOUT)
1127                         align = textclasslist
1128                                 .Style(bview->buffer()->params.textclass,
1129                                        cursor.par()->getLayout()).align;
1130                 if (align & textclasslist
1131                     .Style(bview->buffer()->params.textclass,
1132                            cursor.par()->getLayout()).alignpossible) {
1133                         if (align == textclasslist
1134                             .Style(bview->buffer()->params.textclass,
1135                                    cursor.par()->getLayout()).align)
1136                                 cursor.par()->params().align(LYX_ALIGN_LAYOUT);
1137                         else
1138                                 cursor.par()->params().align(align);
1139                 }
1140                 cursor.par()->setLabelWidthString(labelwidthstring);
1141                 cursor.par()->params().noindent(noindent);
1142                 tmppar = cursor.par()->previous();
1143         }
1144         
1145         redoParagraphs(bview, selection.start, endpar);
1146         
1147         clearSelection(bview);
1148         setCursor(bview, selection.start.par(), selection.start.pos());
1149         selection.cursor = cursor;
1150         setCursor(bview, selection.end.par(), selection.end.pos());
1151         setSelection(bview);
1152         setCursor(bview, tmpcursor.par(), tmpcursor.pos());
1153         if (inset_owner)
1154                 bview->updateInset(inset_owner, true);
1155 }
1156
1157
1158 char loweralphaCounter(int n)
1159 {
1160         if (n < 1 || n > 26)
1161                 return '?';
1162         else
1163                 return 'a' + n - 1;
1164 }
1165
1166
1167 namespace {
1168
1169 inline
1170 char alphaCounter(int n)
1171 {
1172         if (n < 1 || n > 26)
1173                 return '?';
1174         else
1175                 return 'A' + n - 1;
1176 }
1177
1178
1179 inline
1180 char hebrewCounter(int n)
1181 {
1182         static const char hebrew[22] = {
1183                 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1184                 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö', 
1185                 '÷', 'ø', 'ù', 'ú'
1186         };
1187         if (n < 1 || n > 22)
1188                 return '?';
1189         else
1190                 return hebrew[n-1];
1191 }
1192
1193
1194 inline
1195 string const romanCounter(int n)
1196 {
1197         static char const * roman[20] = {
1198                 "i",   "ii",  "iii", "iv", "v",
1199                 "vi",  "vii", "viii", "ix", "x",
1200                 "xi",  "xii", "xiii", "xiv", "xv",
1201                 "xvi", "xvii", "xviii", "xix", "xx"
1202         };
1203         if (n < 1 || n > 20)
1204                 return "??";
1205         else
1206                 return roman[n-1];
1207 }
1208
1209 } // namespace anon
1210
1211
1212 // set the counter of a paragraph. This includes the labels
1213 void LyXText::setCounter(Buffer const * buf, Paragraph * par) const
1214 {
1215         LyXLayout const & layout =
1216                 textclasslist.Style(buf->params.textclass, 
1217                                     par->getLayout());
1218
1219         LyXTextClass const & textclass =
1220                 textclasslist.TextClass(buf->params.textclass);
1221
1222         // copy the prev-counters to this one,
1223         // unless this is the first paragraph
1224         if (par->previous()) {
1225                 for (int i = 0; i < 10; ++i) {
1226                         par->setCounter(i, par->previous()->getFirstCounter(i));
1227                 }
1228                 par->params().appendix(par->previous()->params().appendix());
1229                 if (!par->params().appendix() && par->params().startOfAppendix()) {
1230                         par->params().appendix(true);
1231                         for (int i = 0; i < 10; ++i) {
1232                                 par->setCounter(i, 0);
1233                         }  
1234                 }
1235                 par->enumdepth = par->previous()->enumdepth;
1236                 par->itemdepth = par->previous()->itemdepth;
1237         } else {
1238                 for (int i = 0; i < 10; ++i) {
1239                         par->setCounter(i, 0);
1240                 }  
1241                 par->params().appendix(par->params().startOfAppendix());
1242                 par->enumdepth = 0;
1243                 par->itemdepth = 0;
1244         }
1245
1246         /* Maybe we have to increment the enumeration depth.
1247          * BUT, enumeration in a footnote is considered in isolation from its
1248          *      surrounding paragraph so don't increment if this is the
1249          *      first line of the footnote
1250          * AND, bibliographies can't have their depth changed ie. they
1251          *      are always of depth 0
1252          */
1253         if (par->previous()
1254             && par->previous()->getDepth() < par->getDepth()
1255             && textclasslist.Style(buf->params.textclass,
1256                                    par->previous()->getLayout()
1257                     ).labeltype == LABEL_COUNTER_ENUMI
1258             && par->enumdepth < 3
1259             && layout.labeltype != LABEL_BIBLIO) {
1260                 par->enumdepth++;
1261         }
1262
1263         // Maybe we have to decrement the enumeration depth, see note above
1264         if (par->previous()
1265             && par->previous()->getDepth() > par->getDepth()
1266             && layout.labeltype != LABEL_BIBLIO) {
1267                 par->enumdepth = par->depthHook(par->getDepth())->enumdepth;
1268                 par->setCounter(6 + par->enumdepth,
1269                                 par->depthHook(par->getDepth())->getCounter(6 + par->enumdepth));
1270                 /* reset the counters.
1271                  * A depth change is like a breaking layout
1272                  */
1273                 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1274                         par->setCounter(i, 0);
1275         }
1276    
1277         if (!par->params().labelString().empty()) {
1278                 par->params().labelString(string());
1279         }
1280    
1281         if (layout.margintype == MARGIN_MANUAL) {
1282                 if (par->params().labelWidthString().empty()) {
1283                         par->setLabelWidthString(layout.labelstring());
1284                 }
1285         } else {
1286                 par->setLabelWidthString(string());
1287         }
1288    
1289         // is it a layout that has an automatic label?
1290         if (layout.labeltype >=  LABEL_COUNTER_CHAPTER) {
1291       
1292                 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1293                 if (i >= 0 && i<= buf->params.secnumdepth) {
1294                         par->incCounter(i);     // increment the counter  
1295          
1296                         // Is there a label? Useful for Chapter layout
1297                         if (!par->params().appendix()) {
1298                                 if (!layout.labelstring().empty())
1299                                         par->params().labelString(layout.labelstring());
1300                                 else
1301                                         par->params().labelString(string());
1302                         } else {
1303                                 if (!layout.labelstring_appendix().empty())
1304                                         par->params().labelString(layout.labelstring_appendix());
1305                                 else
1306                                         par->params().labelString(string());
1307                         }
1308
1309                         ostringstream s;
1310
1311                         if (!par->params().appendix()) {
1312                                 switch (2 * LABEL_COUNTER_CHAPTER -
1313                                         textclass.maxcounter() + i) {
1314                                 case LABEL_COUNTER_CHAPTER:
1315                                         s << par->getCounter(i);
1316                                         break;
1317                                 case LABEL_COUNTER_SECTION:
1318                                         s << par->getCounter(i - 1) << '.'
1319                                           << par->getCounter(i);
1320                                         break;
1321                                 case LABEL_COUNTER_SUBSECTION:
1322                                         s << par->getCounter(i - 2) << '.'
1323                                           << par->getCounter(i - 1) << '.'
1324                                           << par->getCounter(i);
1325                                         break;
1326                                 case LABEL_COUNTER_SUBSUBSECTION:
1327                                         s << par->getCounter(i - 3) << '.'
1328                                           << par->getCounter(i - 2) << '.'
1329                                           << par->getCounter(i - 1) << '.'
1330                                           << par->getCounter(i);
1331                                         
1332                                         break;
1333                                 case LABEL_COUNTER_PARAGRAPH:
1334                                         s << par->getCounter(i - 4) << '.'
1335                                           << par->getCounter(i - 3) << '.'
1336                                           << par->getCounter(i - 2) << '.'
1337                                           << par->getCounter(i - 1) << '.'
1338                                           << par->getCounter(i);
1339                                         break;
1340                                 case LABEL_COUNTER_SUBPARAGRAPH:
1341                                         s << par->getCounter(i - 5) << '.'
1342                                           << par->getCounter(i - 4) << '.'
1343                                           << par->getCounter(i - 3) << '.'
1344                                           << par->getCounter(i - 2) << '.'
1345                                           << par->getCounter(i - 1) << '.'
1346                                           << par->getCounter(i);
1347
1348                                         break;
1349                                 default:
1350                                         // Can this ever be reached? And in the
1351                                         // case it is, how can this be correct?
1352                                         // (Lgb)
1353                                         s << par->getCounter(i) << '.';
1354                                         break;
1355                                 }
1356                         } else { // appendix
1357                                 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1358                                 case LABEL_COUNTER_CHAPTER:
1359                                         if (par->isRightToLeftPar(buf->params))
1360                                                 s << hebrewCounter(par->getCounter(i));
1361                                         else
1362                                                 s << alphaCounter(par->getCounter(i));
1363                                         break;
1364                                 case LABEL_COUNTER_SECTION:
1365                                         if (par->isRightToLeftPar(buf->params))
1366                                                 s << hebrewCounter(par->getCounter(i - 1));
1367                                         else
1368                                                 s << alphaCounter(par->getCounter(i - 1));
1369
1370                                         s << '.'
1371                                           << par->getCounter(i);
1372
1373                                         break;
1374                                 case LABEL_COUNTER_SUBSECTION:
1375                                         if (par->isRightToLeftPar(buf->params))
1376                                                 s << hebrewCounter(par->getCounter(i - 2));
1377                                         else
1378                                                 s << alphaCounter(par->getCounter(i - 2));
1379
1380                                         s << '.'
1381                                           << par->getCounter(i-1) << '.'
1382                                           << par->getCounter(i);
1383
1384                                         break;
1385                                 case LABEL_COUNTER_SUBSUBSECTION:
1386                                         if (par->isRightToLeftPar(buf->params))
1387                                                 s << hebrewCounter(par->getCounter(i-3));
1388                                         else
1389                                                 s << alphaCounter(par->getCounter(i-3));
1390
1391                                         s << '.'
1392                                           << par->getCounter(i-2) << '.'
1393                                           << par->getCounter(i-1) << '.'
1394                                           << par->getCounter(i);
1395
1396                                         break;
1397                                 case LABEL_COUNTER_PARAGRAPH:
1398                                         if (par->isRightToLeftPar(buf->params))
1399                                                 s << hebrewCounter(par->getCounter(i-4));
1400                                         else
1401                                                 s << alphaCounter(par->getCounter(i-4));
1402
1403                                         s << '.'
1404                                           << par->getCounter(i-3) << '.'
1405                                           << par->getCounter(i-2) << '.'
1406                                           << par->getCounter(i-1) << '.'
1407                                           << par->getCounter(i);
1408
1409                                         break;
1410                                 case LABEL_COUNTER_SUBPARAGRAPH:
1411                                         if (par->isRightToLeftPar(buf->params))
1412                                                 s << hebrewCounter(par->getCounter(i-5));
1413                                         else
1414                                                 s << alphaCounter(par->getCounter(i-5));
1415
1416                                         s << '.'
1417                                           << par->getCounter(i-4) << '.'
1418                                           << par->getCounter(i-3) << '.'
1419                                           << par->getCounter(i-2) << '.'
1420                                           << par->getCounter(i-1) << '.'
1421                                           << par->getCounter(i);
1422
1423                                         break;
1424                                 default:
1425                                         // Can this ever be reached? And in the
1426                                         // case it is, how can this be correct?
1427                                         // (Lgb)
1428                                         s << par->getCounter(i) << '.';
1429                                         
1430                                         break;
1431                                 }
1432                         }
1433
1434                         par->params().labelString(par->params().labelString() +s.str().c_str());
1435                         // We really want to remove the c_str as soon as
1436                         // possible...
1437                         
1438                         for (i++; i < 10; ++i) {
1439                                 // reset the following counters
1440                                 par->setCounter(i, 0);
1441                         }
1442                 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1443                         for (i++; i < 10; ++i) {
1444                                 // reset the following counters
1445                                 par->setCounter(i, 0);
1446                         }
1447                 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1448                         par->incCounter(i + par->enumdepth);
1449                         int number = par->getCounter(i + par->enumdepth);
1450
1451                         ostringstream s;
1452
1453                         switch (par->enumdepth) {
1454                         case 1:
1455                                 if (par->isRightToLeftPar(buf->params))
1456                                         s << '('
1457                                           << hebrewCounter(number)
1458                                           << ')';
1459                                 else
1460                                         s << '('
1461                                           << loweralphaCounter(number)
1462                                           << ')';
1463                                 break;
1464                         case 2:
1465                                 if (par->isRightToLeftPar(buf->params))
1466                                         s << '.' << romanCounter(number);
1467                                 else
1468                                         s << romanCounter(number) << '.';
1469                                 break;
1470                         case 3:
1471                                 if (par->isRightToLeftPar(buf->params))
1472                                         s << '.'
1473                                           << alphaCounter(number);
1474                                 else
1475                                         s << alphaCounter(number)
1476                                           << '.';
1477                                 break;
1478                         default:
1479                                 if (par->isRightToLeftPar(buf->params))
1480                                         s << '.' << number;
1481                                 else
1482                                         s << number << '.';
1483                                 break;
1484                         }
1485
1486                         par->params().labelString(s.str().c_str());
1487
1488                         for (i += par->enumdepth + 1; i < 10; ++i) {
1489                                 // reset the following counters
1490                                 par->setCounter(i, 0);
1491                         }
1492                         
1493                 } 
1494         } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1495                 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1496                 par->incCounter(i);
1497                 int number = par->getCounter(i);
1498                 if (!par->bibkey) {
1499                         InsetCommandParams p( "bibitem" );
1500                         par->bibkey = new InsetBibKey(p);
1501                 }
1502                 par->bibkey->setCounter(number);
1503                 par->params().labelString(layout.labelstring());
1504                 
1505                 // In biblio should't be following counters but...
1506         } else {
1507                 string s = layout.labelstring();
1508                 
1509                 // the caption hack:
1510                 if (layout.labeltype == LABEL_SENSITIVE) {
1511                         bool isOK (par->inInset() && par->inInset()->owner() &&
1512                                    (par->inInset()->owner()->lyxCode() == Inset::FLOAT_CODE));
1513                         
1514                         if (isOK) {
1515                                 InsetFloat * tmp = static_cast<InsetFloat*>(par->inInset()->owner());
1516                                 Floating const & fl
1517                                         = floatList.getType(tmp->type());
1518                                 // We should get the correct number here too.
1519                                 s = fl.name() + " #:";
1520                         } else {
1521                                 /* par->SetLayout(0); 
1522                                    s = layout->labelstring;  */
1523                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1524                                         ? " :úåòîùî øñç" : "Senseless: ";
1525                         }
1526                 }
1527                 par->params().labelString(s);
1528                 
1529                 /* reset the enumeration counter. They are always resetted
1530                  * when there is any other layout between */ 
1531                 for (int i = 6 + par->enumdepth; i < 10; ++i)
1532                         par->setCounter(i, 0);
1533         }
1534 }
1535
1536
1537 // Updates all counters BEHIND the row. Changed paragraphs
1538 // with a dynamic left margin will be rebroken.
1539 void LyXText::updateCounters(BufferView * bview, Row * row) const
1540 {
1541         Paragraph * par;
1542
1543         if (!row) {
1544                 row = firstrow;
1545                 par = row->par();
1546         } else {
1547                 par = row->par()->next();
1548         }
1549
1550         while (par) {
1551                 while (row->par() != par)
1552                         row = row->next();
1553                 
1554                 setCounter(bview->buffer(), par);
1555                 
1556                 // now check for the headline layouts. remember that they
1557                 // have a dynamic left margin
1558                 if ((textclasslist.Style(bview->buffer()->params.textclass,
1559                                          par->layout).margintype == MARGIN_DYNAMIC
1560                      || textclasslist.Style(bview->buffer()->params.textclass,
1561                                             par->layout).labeltype == LABEL_SENSITIVE)) {
1562                         
1563                         // Rebreak the paragraph
1564                         removeParagraph(row);
1565                         appendParagraph(bview, row);
1566                 }
1567                 par = par->next();
1568         }
1569 }
1570
1571
1572 void LyXText::insertInset(BufferView * bview, Inset * inset)
1573 {
1574         if (!cursor.par()->insetAllowed(inset->lyxCode()))
1575                 return;
1576         setUndo(bview, Undo::INSERT,
1577                 cursor.par(), cursor.par()->next());
1578         cursor.par()->insertInset(cursor.pos(), inset);
1579         // Just to rebreak and refresh correctly.
1580         // The character will not be inserted a second time
1581         insertChar(bview, Paragraph::META_INSET);
1582 #if 1
1583         // If we enter a highly editable inset the cursor should be to before
1584         // the inset. This couldn't happen before as Undo was not handled inside
1585         // inset now after the Undo LyX tries to call inset->Edit(...) again
1586         // and cannot do this as the cursor is behind the inset and GetInset
1587         // does not return the inset!
1588         if (inset->editable() == Inset::HIGHLY_EDITABLE) {
1589                 cursorLeft(bview, true);
1590         }
1591 #endif
1592 }
1593
1594
1595 void LyXText::copyEnvironmentType()
1596 {
1597         copylayouttype = cursor.par()->getLayout();
1598 }
1599
1600
1601 void LyXText::pasteEnvironmentType(BufferView * bview)
1602 {
1603         setLayout(bview, copylayouttype);
1604 }
1605
1606
1607 void LyXText::cutSelection(BufferView * bview, bool doclear)
1608 {
1609         // Stuff what we got on the clipboard. Even if there is no selection.
1610
1611         // There is a problem with having the stuffing here in that the
1612         // larger the selection the slower LyX will get. This can be
1613         // solved by running the line below only when the selection has
1614         // finished. The solution used currently just works, to make it
1615         // faster we need to be more clever and probably also have more
1616         // calls to stuffClipboard. (Lgb)
1617         bview->stuffClipboard(selectionAsString(bview->buffer()));
1618
1619         // This doesn't make sense, if there is no selection
1620         if (!selection.set())
1621                 return;
1622    
1623         // OK, we have a selection. This is always between selection.start
1624         // and selection.end
1625
1626         // make sure that the depth behind the selection are restored, too
1627         Paragraph * endpar = selection.end.par()->next();
1628         Paragraph * undoendpar = endpar;
1629     
1630         if (endpar && endpar->getDepth()) {
1631                 while (endpar && endpar->getDepth()) {
1632                         endpar = endpar->next();
1633                         undoendpar = endpar;
1634                 }
1635         } else if (endpar) {
1636                 endpar = endpar->next(); // because of parindents etc.
1637         }
1638     
1639         setUndo(bview, Undo::DELETE,
1640                 selection.start.par(), undoendpar);
1641     
1642         // there are two cases: cut only within one paragraph or
1643         // more than one paragraph
1644         if (selection.start.par() == selection.end.par()) {
1645                 // only within one paragraph
1646                 endpar = selection.end.par();
1647                 int pos = selection.end.pos();
1648                 CutAndPaste::cutSelection(selection.start.par(), &endpar,
1649                                           selection.start.pos(), pos,
1650                                           bview->buffer()->params.textclass, doclear);
1651                 selection.end.pos(pos);
1652         } else {
1653                 endpar = selection.end.par();
1654                 int pos = selection.end.pos();
1655                 CutAndPaste::cutSelection(selection.start.par(), &endpar,
1656                                           selection.start.pos(), pos,
1657                                           bview->buffer()->params.textclass, doclear);
1658                 cursor.par(endpar);
1659                 selection.end.par(endpar);
1660                 selection.end.pos(pos);
1661                 cursor.pos(selection.end.pos());
1662         }
1663         endpar = endpar->next();
1664
1665         // sometimes necessary
1666         if (doclear)
1667                 selection.start.par()->stripLeadingSpaces(bview->buffer()->params.textclass);
1668
1669         redoParagraphs(bview, selection.start, endpar);
1670
1671         // cutSelection can invalidate the cursor so we need to set
1672         // it anew. (Lgb)
1673         cursor = selection.start;
1674
1675         // need a valid cursor. (Lgb)
1676         clearSelection(bview);
1677
1678         setCursor(bview, cursor.par(), cursor.pos());
1679         selection.cursor = cursor;
1680         updateCounters(bview, cursor.row());
1681 }
1682
1683
1684 void LyXText::copySelection(BufferView * bview)
1685 {
1686         // Stuff what we got on the clipboard. Even if there is no selection.
1687
1688         // There is a problem with having the stuffing here in that the
1689         // larger the selection the slower LyX will get. This can be
1690         // solved by running the line below only when the selection has
1691         // finished. The solution used currently just works, to make it
1692         // faster we need to be more clever and probably also have more
1693         // calls to stuffClipboard. (Lgb)
1694         bview->stuffClipboard(selectionAsString(bview->buffer()));
1695
1696         // this doesnt make sense, if there is no selection
1697         if (!selection.set())
1698                 return;
1699
1700         // ok we have a selection. This is always between selection.start
1701         // and sel_end cursor
1702
1703         // copy behind a space if there is one
1704         while (selection.start.par()->size() > selection.start.pos()
1705                && selection.start.par()->isLineSeparator(selection.start.pos())
1706                && (selection.start.par() != selection.end.par()
1707                    || selection.start.pos() < selection.end.pos()))
1708                 selection.start.pos(selection.start.pos() + 1); 
1709
1710         CutAndPaste::copySelection(selection.start.par(), selection.end.par(),
1711                                    selection.start.pos(), selection.end.pos(),
1712                                    bview->buffer()->params.textclass);
1713 }
1714
1715
1716 void LyXText::pasteSelection(BufferView * bview)
1717 {
1718         // this does not make sense, if there is nothing to paste
1719         if (!CutAndPaste::checkPastePossible(cursor.par()))
1720                 return;
1721
1722         setUndo(bview, Undo::INSERT,
1723                 cursor.par(), cursor.par()->next()); 
1724
1725         Paragraph * endpar;
1726         Paragraph * actpar = cursor.par();
1727
1728         int pos = cursor.pos();
1729         CutAndPaste::pasteSelection(&actpar, &endpar, pos,
1730                                     bview->buffer()->params.textclass);
1731     
1732         redoParagraphs(bview, cursor, endpar);
1733         
1734         setCursor(bview, cursor.par(), cursor.pos());
1735         clearSelection(bview);
1736    
1737         selection.cursor = cursor;
1738         setCursor(bview, actpar, pos);
1739         setSelection(bview);
1740         updateCounters(bview, cursor.row());
1741 }
1742
1743
1744 // returns a pointer to the very first Paragraph
1745 Paragraph * LyXText::firstParagraph() const
1746 {
1747         return ownerParagraph();
1748 }
1749
1750
1751 // sets the selection over the number of characters of string, no check!!
1752 void LyXText::setSelectionOverString(BufferView * bview, string const & str)
1753 {
1754         if (str.empty())
1755                 return;
1756         
1757         selection.cursor = cursor;
1758         for (string::size_type i = 0; i < str.length(); ++i)
1759                 cursorRight(bview);
1760         setSelection(bview);
1761 }
1762
1763
1764 // simple replacing. The font of the first selected character is used
1765 void LyXText::replaceSelectionWithString(BufferView * bview,
1766                                          string const & str)
1767 {
1768         setCursorParUndo(bview);
1769         freezeUndo();
1770
1771         if (!selection.set()) { // create a dummy selection
1772                 selection.end = cursor;
1773                 selection.start = cursor;
1774         }
1775
1776         // Get font setting before we cut
1777         Paragraph::size_type pos = selection.end.pos();
1778         LyXFont const font = selection.start.par()
1779                 ->getFontSettings(bview->buffer()->params,
1780                                   selection.start.pos());
1781
1782         // Insert the new string
1783         for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
1784                 selection.end.par()->insertChar(pos, (*cit), font);
1785                 ++pos;
1786         }
1787         
1788         // Cut the selection
1789         cutSelection(bview);
1790
1791         unFreezeUndo();
1792 }
1793
1794
1795 // needed to insert the selection
1796 void LyXText::insertStringAsLines(BufferView * bview, string const & str)
1797 {
1798         Paragraph * par = cursor.par();
1799         Paragraph::size_type pos = cursor.pos();
1800         Paragraph * endpar = cursor.par()->next();
1801         
1802         setCursorParUndo(bview);
1803         
1804         // only to be sure, should not be neccessary
1805         clearSelection(bview);
1806         
1807         bview->buffer()->insertStringAsLines(par, pos, current_font, str);
1808
1809         redoParagraphs(bview, cursor, endpar);
1810         setCursor(bview, cursor.par(), cursor.pos());
1811         selection.cursor = cursor;
1812         setCursor(bview, par, pos);
1813         setSelection(bview);
1814 }
1815
1816
1817 // turns double-CR to single CR, others where converted into one
1818 // blank. Then InsertStringAsLines is called
1819 void LyXText::insertStringAsParagraphs(BufferView * bview, string const & str)
1820 {
1821         string linestr(str);
1822         bool newline_inserted = false;
1823         for (string::size_type i = 0; i < linestr.length(); ++i) {
1824                 if (linestr[i] == '\n') {
1825                         if (newline_inserted) {
1826                                 // we know that \r will be ignored by
1827                                 // InsertStringA. Of course, it is a dirty
1828                                 // trick, but it works...
1829                                 linestr[i - 1] = '\r';
1830                                 linestr[i] = '\n';
1831                         } else {
1832                                 linestr[i] = ' ';
1833                                 newline_inserted = true;
1834                         } 
1835                 } else if (IsPrintable(linestr[i])) {
1836                         newline_inserted = false;
1837                 }
1838         }
1839         insertStringAsLines(bview, linestr);
1840 }
1841
1842
1843 bool LyXText::gotoNextInset(BufferView * bview,
1844                             std::vector<Inset::Code> const & codes,
1845                             string const & contents) const
1846 {
1847         LyXCursor res = cursor;
1848         Inset * inset;
1849         do {
1850                 if (res.pos() < res.par()->size() - 1) {
1851                         res.pos(res.pos() + 1);
1852                 } else  {
1853                         res.par(res.par()->next());
1854                         res.pos(0);
1855                 }
1856       
1857         } while (res.par() && 
1858                  !(res.par()->getChar(res.pos()) == Paragraph::META_INSET
1859                    && (inset = res.par()->getInset(res.pos())) != 0
1860                    && find(codes.begin(), codes.end(), inset->lyxCode())
1861                    != codes.end()
1862                    && (contents.empty() ||
1863                        static_cast<InsetCommand *>(res.par()->getInset(res.pos()))->getContents()
1864                        == contents)));
1865
1866         if (res.par()) {
1867                 setCursor(bview, res.par(), res.pos());
1868                 return true;
1869         }
1870         return false;
1871 }
1872
1873
1874 void LyXText::checkParagraph(BufferView * bview, Paragraph * par,
1875                              Paragraph::size_type pos)
1876 {
1877         LyXCursor tmpcursor;                    
1878
1879         int y = 0;
1880         Paragraph::size_type z;
1881         Row * row = getRow(par, pos, y);
1882         
1883         // is there a break one row above
1884         if (row->previous() && row->previous()->par() == row->par()) {
1885                 z = nextBreakPoint(bview, row->previous(), workWidth(bview));
1886                 if (z >= row->pos()) {
1887                         // set the dimensions of the row above
1888                         y -= row->previous()->height();
1889                         refresh_y = y;
1890                         refresh_row = row->previous();
1891                         status(bview, LyXText::NEED_MORE_REFRESH);
1892                         
1893                         breakAgain(bview, row->previous());
1894                         
1895                         // set the cursor again. Otherwise
1896                         // dangling pointers are possible
1897                         setCursor(bview, cursor.par(), cursor.pos(),
1898                                   false, cursor.boundary());
1899                         selection.cursor = cursor;
1900                         return;
1901                 }
1902         }
1903
1904         int const tmpheight = row->height();
1905         Paragraph::size_type const tmplast = rowLast(row);
1906         refresh_y = y;
1907         refresh_row = row;
1908         
1909         breakAgain(bview, row);
1910         if (row->height() == tmpheight && rowLast(row) == tmplast)
1911                 status(bview, LyXText::NEED_VERY_LITTLE_REFRESH);
1912         else
1913                 status(bview, LyXText::NEED_MORE_REFRESH); 
1914         
1915         // check the special right address boxes
1916         if (textclasslist.Style(bview->buffer()->params.textclass,
1917                                 par->getLayout()).margintype
1918             == MARGIN_RIGHT_ADDRESS_BOX) {
1919                 tmpcursor.par(par);
1920                 tmpcursor.row(row);
1921                 tmpcursor.y(y);
1922                 tmpcursor.x(0);
1923                 tmpcursor.x_fix(0);
1924                 tmpcursor.pos(pos);
1925                 redoDrawingOfParagraph(bview, tmpcursor); 
1926         }
1927
1928         // set the cursor again. Otherwise dangling pointers are possible
1929         // also set the selection
1930    
1931         if (selection.set()) {
1932                 tmpcursor = cursor;
1933                 setCursorIntern(bview, selection.cursor.par(), selection.cursor.pos(),
1934                                 false, selection.cursor.boundary());
1935                 selection.cursor = cursor; 
1936                 setCursorIntern(bview, selection.start.par(),
1937                                 selection.start.pos(),
1938                                 false, selection.start.boundary());
1939                 selection.start = cursor; 
1940                 setCursorIntern(bview, selection.end.par(),
1941                                 selection.end.pos(),
1942                                 false, selection.end.boundary());
1943                 selection.end = cursor; 
1944                 setCursorIntern(bview, last_sel_cursor.par(),
1945                                 last_sel_cursor.pos(),
1946                                 false, last_sel_cursor.boundary());
1947                 last_sel_cursor = cursor; 
1948                 cursor = tmpcursor;
1949         }
1950         setCursorIntern(bview, cursor.par(), cursor.pos(),
1951                         false, cursor.boundary());
1952 }
1953
1954
1955 // returns false if inset wasn't found
1956 bool LyXText::updateInset(BufferView * bview, Inset * inset)
1957 {
1958         // first check the current paragraph
1959         int pos = cursor.par()->getPositionOfInset(inset);
1960         if (pos != -1){
1961                 checkParagraph(bview, cursor.par(), pos);
1962                 return true;
1963         }
1964   
1965         // check every paragraph
1966   
1967         Paragraph * par = firstParagraph();
1968         do {
1969                 pos = par->getPositionOfInset(inset);
1970                 if (pos != -1){
1971                         checkParagraph(bview, par, pos);
1972                         return true;
1973                 }
1974                 par = par->next();
1975         } while (par);
1976   
1977         return false;
1978 }
1979
1980
1981 void LyXText::setCursor(BufferView * bview, Paragraph * par,
1982                         Paragraph::size_type pos, 
1983                         bool setfont, bool boundary) const
1984 {
1985         LyXCursor old_cursor = cursor;
1986         setCursorIntern(bview, par, pos, setfont, boundary);
1987         deleteEmptyParagraphMechanism(bview, old_cursor);
1988 }
1989
1990
1991 void LyXText::setCursor(BufferView *bview, LyXCursor & cur, Paragraph * par,
1992                         Paragraph::size_type pos, bool boundary) const
1993 {
1994         cur.par(par);
1995         cur.pos(pos);
1996         cur.boundary(boundary);
1997
1998         // get the cursor y position in text
1999         int y = 0;
2000         Row * row = getRow(par, pos, y);
2001         // y is now the beginning of the cursor row
2002         y += row->baseline();
2003         // y is now the cursor baseline 
2004         cur.y(y);
2005    
2006         // now get the cursors x position
2007         float x;
2008         float fill_separator;
2009         float fill_hfill;
2010         float fill_label_hfill;
2011         prepareToPrint(bview, row, x, fill_separator, fill_hfill,
2012                        fill_label_hfill);
2013         Paragraph::size_type cursor_vpos = 0;
2014         Paragraph::size_type last = rowLastPrintable(row);
2015
2016         if (pos > last + 1)   // This shouldn't happen.
2017                 pos = last + 1;
2018         else if (pos < row->pos())
2019                 pos = row->pos();
2020
2021         if (last < row->pos())
2022                 cursor_vpos = row->pos();
2023         else if (pos > last && !boundary)
2024                 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2025                         ? row->pos() : last + 1; 
2026         else if (pos > row->pos() &&
2027                  (pos > last || boundary))
2028                 /// Place cursor after char at (logical) position pos - 1
2029                 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2030                         ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2031         else
2032                 /// Place cursor before char at (logical) position pos
2033                 cursor_vpos = (bidi_level(pos) % 2 == 0)
2034                         ? log2vis(pos) : log2vis(pos) + 1;
2035         
2036         Paragraph::size_type main_body =
2037                 beginningOfMainBody(bview->buffer(), row->par());
2038         if ((main_body > 0) &&
2039             ((main_body-1 > last) || 
2040              !row->par()->isLineSeparator(main_body-1)))
2041                 main_body = 0;
2042         
2043         for (Paragraph::size_type vpos = row->pos();
2044              vpos < cursor_vpos; ++vpos) {
2045                 pos = vis2log(vpos);
2046                 if (main_body > 0 && pos == main_body - 1) {
2047                         x += fill_label_hfill +
2048                                 lyxfont::width(textclasslist.Style(
2049                                         bview->buffer()->params.textclass,
2050                                         row->par()->getLayout())
2051                                                .labelsep,
2052                                                getFont(bview->buffer(), row->par(), -2));
2053                         if (row->par()->isLineSeparator(main_body-1))
2054                                 x -= singleWidth(bview, row->par(),main_body-1);
2055                 }
2056                 if (hfillExpansion(bview->buffer(), row, pos)) {
2057                         x += singleWidth(bview, row->par(), pos);
2058                         if (pos >= main_body)
2059                                 x += fill_hfill;
2060                         else 
2061                                 x += fill_label_hfill;
2062                 } else if (row->par()->isSeparator(pos)) {
2063                         x += singleWidth(bview, row->par(), pos);
2064                         if (pos >= main_body)
2065                                 x += fill_separator;
2066                 } else
2067                         x += singleWidth(bview, row->par(), pos);
2068         }
2069         
2070         cur.x(int(x));
2071         cur.x_fix(cur.x());
2072         cur.row(row);
2073 }
2074
2075
2076 void LyXText::setCursorIntern(BufferView * bview, Paragraph * par,
2077                               Paragraph::size_type pos,
2078                               bool setfont, bool boundary) const
2079 {
2080         InsetText * it = static_cast<InsetText *>(par->inInset());
2081         if (it && (it != inset_owner)) {
2082                 it->getLyXText(bview)->setCursorIntern(bview, par, pos, setfont,
2083                                                        boundary);
2084         } else {
2085                 setCursor(bview, cursor, par, pos, boundary);
2086                 if (setfont)
2087                         setCurrentFont(bview);
2088         }
2089 }
2090
2091
2092 void LyXText::setCurrentFont(BufferView * bview) const
2093 {
2094         Paragraph::size_type pos = cursor.pos();
2095         if (cursor.boundary() && pos > 0)
2096                 --pos;
2097
2098         if (pos > 0) {
2099                 if (pos == cursor.par()->size())
2100                         --pos;
2101                 else // potentional bug... BUG (Lgb)
2102                         if (cursor.par()->isSeparator(pos)) {
2103                                 if (pos > cursor.row()->pos() &&
2104                                     bidi_level(pos) % 2 == 
2105                                     bidi_level(pos - 1) % 2)
2106                                         --pos;
2107                                 else if (pos + 1 < cursor.par()->size())
2108                                         ++pos;
2109                         }
2110         }
2111
2112         current_font =
2113                 cursor.par()->getFontSettings(bview->buffer()->params, pos);
2114         real_current_font = getFont(bview->buffer(), cursor.par(), pos);
2115
2116         if (cursor.pos() == cursor.par()->size() &&
2117             isBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2118             !cursor.boundary()) {
2119                 Language const * lang =
2120                         cursor.par()->getParLanguage(bview->buffer()->params);
2121                 current_font.setLanguage(lang);
2122                 current_font.setNumber(LyXFont::OFF);
2123                 real_current_font.setLanguage(lang);
2124                 real_current_font.setNumber(LyXFont::OFF);
2125         }
2126 }
2127
2128
2129 void LyXText::setCursorFromCoordinates(BufferView * bview, int x, int y) const
2130 {
2131         LyXCursor old_cursor = cursor;
2132    
2133         // Get the row first. 
2134    
2135         Row * row = getRowNearY(y);
2136         cursor.par(row->par());
2137
2138         bool bound = false;
2139         int column = getColumnNearX(bview, row, x, bound);
2140         cursor.pos(row->pos() + column);
2141         cursor.x(x);
2142         cursor.y(y + row->baseline());
2143         cursor.row(row);
2144         cursor.boundary(bound);
2145         setCurrentFont(bview);
2146         deleteEmptyParagraphMechanism(bview, old_cursor);
2147 }
2148
2149
2150 void LyXText::setCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2151                                        int x, int y) const
2152 {
2153         // Get the row first.
2154    
2155         Row * row = getRowNearY(y);
2156         bool bound = false;
2157         int column = getColumnNearX(bview, row, x, bound);
2158    
2159         cur.par(row->par());
2160         cur.pos(row->pos() + column);
2161         cur.x(x);
2162         cur.y(y + row->baseline());
2163         cur.row(row);
2164         cur.boundary(bound);
2165 }
2166
2167
2168 void LyXText::cursorLeft(BufferView * bview, bool internal) const
2169 {
2170         if (cursor.pos() > 0) {
2171                 bool boundary = cursor.boundary();
2172                 setCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2173                 if (!internal && !boundary &&
2174                     isBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2175                         setCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2176         } else if (cursor.par()->previous()) { // steps into the above paragraph.
2177                 Paragraph * par = cursor.par()->previous();
2178                 setCursor(bview, par, par->size());
2179         }
2180 }
2181
2182
2183 void LyXText::cursorRight(BufferView * bview, bool internal) const
2184 {
2185         if (!internal && cursor.boundary() &&
2186             !cursor.par()->isNewline(cursor.pos()))
2187                 setCursor(bview, cursor.par(), cursor.pos(), true, false);
2188         else if (cursor.pos() < cursor.par()->size()) {
2189                 setCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2190                 if (!internal &&
2191                     isBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2192                         setCursor(bview, cursor.par(), cursor.pos(), true, true);
2193         } else if (cursor.par()->next())
2194                 setCursor(bview, cursor.par()->next(), 0);
2195 }
2196
2197
2198 void LyXText::cursorUp(BufferView * bview) const
2199 {
2200         setCursorFromCoordinates(bview, cursor.x_fix(), 
2201                                  cursor.y() - cursor.row()->baseline() - 1);
2202 }
2203
2204
2205 void LyXText::cursorDown(BufferView * bview) const
2206 {
2207         setCursorFromCoordinates(bview, cursor.x_fix(), 
2208                                  cursor.y() - cursor.row()->baseline()
2209                                  + cursor.row()->height() + 1);
2210 }
2211
2212
2213 void LyXText::cursorUpParagraph(BufferView * bview) const
2214 {
2215         if (cursor.pos() > 0) {
2216                 setCursor(bview, cursor.par(), 0);
2217         }
2218         else if (cursor.par()->previous()) {
2219                 setCursor(bview, cursor.par()->previous(), 0);
2220         }
2221 }
2222
2223
2224 void LyXText::cursorDownParagraph(BufferView * bview) const
2225 {
2226         if (cursor.par()->next()) {
2227                 setCursor(bview, cursor.par()->next(), 0);
2228         } else {
2229                 setCursor(bview, cursor.par(), cursor.par()->size());
2230         }
2231 }
2232
2233
2234 void LyXText::deleteEmptyParagraphMechanism(BufferView * bview,
2235                                             LyXCursor const & old_cursor) const
2236 {
2237         // Would be wrong to delete anything if we have a selection.
2238         if (selection.set()) return;
2239
2240         // We allow all kinds of "mumbo-jumbo" when freespacing.
2241         if (textclasslist.Style(bview->buffer()->params.textclass,
2242                                 old_cursor.par()->getLayout()).free_spacing)
2243                 return;
2244
2245         bool deleted = false;
2246         
2247         /* Ok I'll put some comments here about what is missing.
2248            I have fixed BackSpace (and thus Delete) to not delete
2249            double-spaces automagically. I have also changed Cut,
2250            Copy and Paste to hopefully do some sensible things.
2251            There are still some small problems that can lead to
2252            double spaces stored in the document file or space at
2253            the beginning of paragraphs. This happens if you have
2254            the cursor betwenn to spaces and then save. Or if you
2255            cut and paste and the selection have a space at the
2256            beginning and then save right after the paste. I am
2257            sure none of these are very hard to fix, but I will
2258            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2259            that I can get some feedback. (Lgb)
2260         */
2261
2262         // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2263         // delete the LineSeparator.
2264         // MISSING
2265
2266         // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2267         // delete the LineSeparator.
2268         // MISSING
2269
2270         // If the pos around the old_cursor were spaces, delete one of them.
2271         if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) { 
2272                 // Only if the cursor has really moved
2273                 
2274                 if (old_cursor.pos() > 0
2275                     && old_cursor.pos() < old_cursor.par()->size()
2276                     && old_cursor.par()->isLineSeparator(old_cursor.pos())
2277                     && old_cursor.par()->isLineSeparator(old_cursor.pos() - 1)) {
2278                         old_cursor.par()->erase(old_cursor.pos() - 1);
2279                         redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2280                         // correct cursor
2281                         if (old_cursor.par() == cursor.par() &&
2282                             cursor.pos() > old_cursor.pos()) {
2283                                 setCursorIntern(bview, cursor.par(),
2284                                                 cursor.pos() - 1);
2285                         } else
2286                                 setCursorIntern(bview, cursor.par(),
2287                                                 cursor.pos());
2288                         return;
2289                 }
2290         }
2291
2292         // Do not delete empty paragraphs with keepempty set.
2293         if ((textclasslist.Style(bview->buffer()->params.textclass,
2294                                  old_cursor.par()->getLayout())).keepempty)
2295                 return;
2296
2297         LyXCursor tmpcursor;
2298
2299         if (old_cursor.par() != cursor.par()) {
2300                 if ((old_cursor.par()->size() == 0
2301                      || (old_cursor.par()->size() == 1
2302                          && old_cursor.par()->isLineSeparator(0)))) {
2303                         // ok, we will delete anything
2304                         
2305                         // make sure that you do not delete any environments
2306                         status(bview, LyXText::NEED_MORE_REFRESH);
2307                         deleted = true;
2308                                 
2309                         if (old_cursor.row()->previous()) {
2310                                 refresh_row = old_cursor.row()->previous();
2311                                 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2312                                 tmpcursor = cursor;
2313                                 cursor = old_cursor; // that undo can restore the right cursor position
2314                                 Paragraph * endpar = old_cursor.par()->next();
2315                                 if (endpar && endpar->getDepth()) {
2316                                         while (endpar && endpar->getDepth()) {
2317                                                 endpar = endpar->next();
2318                                         }
2319                                 }
2320                                 setUndo(bview, Undo::DELETE,
2321                                         old_cursor.par(),
2322                                         endpar);
2323                                 cursor = tmpcursor;
2324
2325                                 // delete old row
2326                                 removeRow(old_cursor.row());
2327                                 if (ownerParagraph() == old_cursor.par()) {
2328                                         ownerParagraph(ownerParagraph()->next());
2329                                 }
2330                                 // delete old par
2331                                 delete old_cursor.par();
2332                                         
2333                                 /* Breakagain the next par. Needed
2334                                  * because of the parindent that
2335                                  * can occur or dissappear. The
2336                                  * next row can change its height,
2337                                  * if there is another layout before */
2338                                 if (refresh_row->next()) {
2339                                         breakAgain(bview, refresh_row->next());
2340                                         updateCounters(bview, refresh_row);
2341                                 }
2342                                 setHeightOfRow(bview, refresh_row);
2343                         } else {
2344                                 refresh_row = old_cursor.row()->next();
2345                                 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2346                                         
2347                                 tmpcursor = cursor;
2348                                 cursor = old_cursor; // that undo can restore the right cursor position
2349                                 Paragraph * endpar = old_cursor.par()->next();
2350                                 if (endpar && endpar->getDepth()) {
2351                                         while (endpar && endpar->getDepth()) {
2352                                                 endpar = endpar->next();
2353                                         }
2354                                 }
2355                                 setUndo(bview, Undo::DELETE,
2356                                         old_cursor.par(),
2357                                         endpar);
2358                                 cursor = tmpcursor;
2359
2360                                 // delete old row
2361                                 removeRow(old_cursor.row());
2362                                 // delete old par
2363                                 if (ownerParagraph() == old_cursor.par()) {
2364                                         ownerParagraph(ownerParagraph()->next());
2365                                 }
2366
2367                                 delete old_cursor.par();
2368                                         
2369                                 /* Breakagain the next par. Needed
2370                                    because of the parindent that can
2371                                    occur or dissappear.
2372                                    The next row can change its height,
2373                                    if there is another layout before
2374                                 */ 
2375                                 if (refresh_row) {
2376                                         breakAgain(bview, refresh_row);
2377                                         updateCounters(bview, refresh_row->previous());
2378                                 }
2379                         }
2380                                 
2381                                 // correct cursor y
2382
2383                         setCursorIntern(bview, cursor.par(), cursor.pos());
2384
2385                         if (selection.cursor.par()  == old_cursor.par()
2386                             && selection.cursor.pos() == selection.cursor.pos()) {
2387                                 // correct selection
2388                                 selection.cursor = cursor;
2389                         }
2390                 }
2391                 if (!deleted) {
2392                         if (old_cursor.par()->stripLeadingSpaces(bview->buffer()->params.textclass)) {
2393                                 redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2394                                 // correct cursor y
2395                                 setCursorIntern(bview, cursor.par(), cursor.pos());
2396                                 selection.cursor = cursor;
2397                         }
2398                 }
2399         }
2400 }
2401
2402
2403 void LyXText::toggleAppendix(BufferView * bview)
2404 {
2405         Paragraph * par = cursor.par();
2406         bool start = !par->params().startOfAppendix();
2407
2408         // ensure that we have only one start_of_appendix in this document
2409         Paragraph * tmp = firstParagraph();
2410         for (; tmp; tmp = tmp->next()) {
2411                 tmp->params().startOfAppendix(false);
2412         }
2413         
2414         par->params().startOfAppendix(start);
2415
2416         // we can set the refreshing parameters now
2417         status(bview, LyXText::NEED_MORE_REFRESH);
2418         refresh_y = 0;
2419         refresh_row = 0; // not needed for full update
2420         updateCounters(bview, 0);
2421         setCursor(bview, cursor.par(), cursor.pos());
2422 }
2423
2424
2425 Paragraph * LyXText::ownerParagraph() const
2426 {
2427         if (inset_owner) {
2428                 return inset_owner->paragraph();
2429         }
2430         return bv_owner->buffer()->paragraph;
2431 }
2432
2433
2434 Paragraph * LyXText::ownerParagraph(Paragraph * p) const
2435 {
2436         if (inset_owner) {
2437                 inset_owner->paragraph(p);
2438         } else {
2439                 bv_owner->buffer()->paragraph = p;
2440         }
2441         return 0;
2442 }
2443
2444 Paragraph * LyXText::ownerParagraph(int id, Paragraph * p) const
2445 {
2446         Paragraph * op = bv_owner->buffer()->getParFromID(id);
2447         if (op && op->inInset()) {
2448                 static_cast<InsetText *>(op->inInset())->paragraph(p);
2449         } else {
2450                 if (inset_owner) {
2451                         inset_owner->paragraph(p);
2452                 } else {
2453                         bv_owner->buffer()->paragraph = p;
2454                 }
2455         }
2456         return 0;
2457 }
2458
2459
2460 LyXText::text_status LyXText::status() const
2461 {
2462         return status_;
2463 }
2464
2465
2466 void LyXText::status(BufferView * bview, LyXText::text_status st) const
2467 {
2468 #if 0
2469         if ((status_ != NEED_MORE_REFRESH)
2470             || (status_ == NEED_MORE_REFRESH)
2471             && (st != NEED_VERY_LITTLE_REFRESH)) {
2472                 status_ = st;
2473                 if (inset_owner && st != UNCHANGED) {
2474                         bview->text->status(bview, NEED_VERY_LITTLE_REFRESH);
2475                 }
2476         }
2477 #else
2478 #warning Please tell what the intention is here. (Lgb)
2479         // The above does not make any sense, I changed it to what is here,
2480         // but it still does not make much sense. (Lgb)
2481 #warning Sure have a look now! (Jug)
2482         // well as much as I know && binds more then || so the above and the
2483         // below are identical (this for your known use of parentesis!)
2484         // Now some explanation:
2485         // We should only go up with refreshing code so this means that if
2486         // we have a MORE refresh we should never set it to LITTLE if we still
2487         // didn't handle it (and then it will be UNCHANGED. Now as long as
2488         // we stay inside one LyXText this may work but we need to tell the
2489         // outermost LyXText that it should REALLY draw us if there is some
2490         // change in a Inset::LyXText. So you see that when we are inside a
2491         // inset's LyXText we give the LITTLE to the outermost LyXText to
2492         // tell'em that it should redraw the actual row (where the inset
2493         // resides! Capito?!
2494
2495         if ((status_ != NEED_MORE_REFRESH)
2496             || (status_ == NEED_MORE_REFRESH
2497                 && st != NEED_VERY_LITTLE_REFRESH))
2498         {
2499                 status_ = st;
2500                 if (inset_owner && st != UNCHANGED) {
2501                         bview->text->status(bview, NEED_VERY_LITTLE_REFRESH);
2502                 }
2503         }
2504 #endif
2505 }