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