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