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