]> git.lyx.org Git - lyx.git/blob - src/text2.C
get rid of NO_LATEX, split some methods, small cleanup
[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)
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                 selection.end.pos(pos);
1711         } else {
1712                 endpar = selection.end.par();
1713                 int pos = selection.end.pos();
1714                 CutAndPaste::cutSelection(selection.start.par(), &endpar,
1715                                           selection.start.pos(), pos,
1716                                           bview->buffer()->params.textclass, doclear);
1717                 cursor.par(endpar);
1718                 selection.end.par(endpar);
1719                 selection.end.pos(pos);
1720                 cursor.pos(selection.end.pos());
1721         }
1722         endpar = endpar->next();
1723
1724         // sometimes necessary
1725         if (doclear)
1726                 selection.start.par()->stripLeadingSpaces(bview->buffer()->params.textclass);
1727
1728         redoParagraphs(bview, selection.start, endpar);
1729
1730         // cutSelection can invalidate the cursor so we need to set
1731         // it anew. (Lgb)
1732         cursor = selection.start;
1733
1734         // need a valid cursor. (Lgb)
1735         clearSelection();
1736
1737         setCursor(bview, cursor.par(), cursor.pos());
1738         selection.cursor = cursor;
1739         updateCounters(bview, cursor.row());
1740 }
1741
1742
1743 void LyXText::copySelection(BufferView * bview)
1744 {
1745         // Stuff what we got on the clipboard. Even if there is no selection.
1746
1747         // There is a problem with having the stuffing here in that the
1748         // larger the selection the slower LyX will get. This can be
1749         // solved by running the line below only when the selection has
1750         // finished. The solution used currently just works, to make it
1751         // faster we need to be more clever and probably also have more
1752         // calls to stuffClipboard. (Lgb)
1753         bview->stuffClipboard(selectionAsString(bview->buffer()));
1754
1755         // this doesnt make sense, if there is no selection
1756         if (!selection.set())
1757                 return;
1758
1759         // ok we have a selection. This is always between selection.start
1760         // and sel_end cursor
1761
1762         // copy behind a space if there is one
1763         while (selection.start.par()->size() > selection.start.pos()
1764                && selection.start.par()->isLineSeparator(selection.start.pos())
1765                && (selection.start.par() != selection.end.par()
1766                    || selection.start.pos() < selection.end.pos()))
1767                 selection.start.pos(selection.start.pos() + 1); 
1768
1769         CutAndPaste::copySelection(selection.start.par(), selection.end.par(),
1770                                    selection.start.pos(), selection.end.pos(),
1771                                    bview->buffer()->params.textclass);
1772 }
1773
1774
1775 void LyXText::pasteSelection(BufferView * bview)
1776 {
1777         // this does not make sense, if there is nothing to paste
1778         if (!CutAndPaste::checkPastePossible(cursor.par()))
1779                 return;
1780
1781         setUndo(bview, Undo::INSERT,
1782                 cursor.par(), cursor.par()->next()); 
1783
1784         Paragraph * endpar;
1785         Paragraph * actpar = cursor.par();
1786
1787         int pos = cursor.pos();
1788         CutAndPaste::pasteSelection(&actpar, &endpar, pos,
1789                                     bview->buffer()->params.textclass);
1790     
1791         redoParagraphs(bview, cursor, endpar);
1792         
1793         setCursor(bview, cursor.par(), cursor.pos());
1794         clearSelection();
1795    
1796         selection.cursor = cursor;
1797         setCursor(bview, actpar, pos);
1798         setSelection(bview);
1799         updateCounters(bview, cursor.row());
1800 }
1801
1802
1803 // returns a pointer to the very first Paragraph
1804 Paragraph * LyXText::firstParagraph() const
1805 {
1806         return ownerParagraph();
1807 }
1808
1809
1810 // sets the selection over the number of characters of string, no check!!
1811 void LyXText::setSelectionOverString(BufferView * bview, string const & str)
1812 {
1813         if (str.empty())
1814                 return;
1815         
1816         selection.cursor = cursor;
1817         for (string::size_type i = 0; i < str.length(); ++i)
1818                 cursorRight(bview);
1819         setSelection(bview);
1820 }
1821
1822
1823 // simple replacing. The font of the first selected character is used
1824 void LyXText::replaceSelectionWithString(BufferView * bview,
1825                                          string const & str)
1826 {
1827         setCursorParUndo(bview);
1828         freezeUndo();
1829
1830         if (!selection.set()) { // create a dummy selection
1831                 selection.end = cursor;
1832                 selection.start = cursor;
1833         }
1834
1835         // Get font setting before we cut
1836         Paragraph::size_type pos = selection.end.pos();
1837         LyXFont const font = selection.start.par()
1838                 ->getFontSettings(bview->buffer()->params,
1839                                   selection.start.pos());
1840
1841         // Insert the new string
1842         for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
1843                 selection.end.par()->insertChar(pos, (*cit), font);
1844                 ++pos;
1845         }
1846         
1847         // Cut the selection
1848         cutSelection(bview);
1849
1850         unFreezeUndo();
1851 }
1852
1853
1854 // needed to insert the selection
1855 void LyXText::insertStringAsLines(BufferView * bview, string const & str)
1856 {
1857         Paragraph * par = cursor.par();
1858         Paragraph::size_type pos = cursor.pos();
1859         Paragraph * endpar = cursor.par()->next();
1860         
1861         setCursorParUndo(bview);
1862         
1863         // only to be sure, should not be neccessary
1864         clearSelection();
1865         
1866         bview->buffer()->insertStringAsLines(par, pos, current_font, str);
1867
1868         redoParagraphs(bview, cursor, endpar);
1869         setCursor(bview, cursor.par(), cursor.pos());
1870         selection.cursor = cursor;
1871         setCursor(bview, par, pos);
1872         setSelection(bview);
1873 }
1874
1875
1876 // turns double-CR to single CR, others where converted into one
1877 // blank. Then InsertStringAsLines is called
1878 void LyXText::insertStringAsParagraphs(BufferView * bview, string const & str)
1879 {
1880         string linestr(str);
1881         bool newline_inserted = false;
1882         for (string::size_type i = 0; i < linestr.length(); ++i) {
1883                 if (linestr[i] == '\n') {
1884                         if (newline_inserted) {
1885                                 // we know that \r will be ignored by
1886                                 // InsertStringA. Of course, it is a dirty
1887                                 // trick, but it works...
1888                                 linestr[i - 1] = '\r';
1889                                 linestr[i] = '\n';
1890                         } else {
1891                                 linestr[i] = ' ';
1892                                 newline_inserted = true;
1893                         } 
1894                 } else if (IsPrintable(linestr[i])) {
1895                         newline_inserted = false;
1896                 }
1897         }
1898         insertStringAsLines(bview, linestr);
1899 }
1900
1901
1902 bool LyXText::gotoNextInset(BufferView * bview,
1903                             std::vector<Inset::Code> const & codes,
1904                             string const & contents) const
1905 {
1906         LyXCursor res = cursor;
1907         Inset * inset;
1908         do {
1909                 if (res.pos() < res.par()->size() - 1) {
1910                         res.pos(res.pos() + 1);
1911                 } else  {
1912                         res.par(res.par()->next());
1913                         res.pos(0);
1914                 }
1915       
1916         } while (res.par() && 
1917                  !(res.par()->getChar(res.pos()) == Paragraph::META_INSET
1918                    && (inset = res.par()->getInset(res.pos())) != 0
1919                    && find(codes.begin(), codes.end(), inset->lyxCode())
1920                    != codes.end()
1921                    && (contents.empty() ||
1922                        static_cast<InsetCommand *>(res.par()->getInset(res.pos()))->getContents()
1923                        == contents)));
1924
1925         if (res.par()) {
1926                 setCursor(bview, res.par(), res.pos());
1927                 return true;
1928         }
1929         return false;
1930 }
1931
1932
1933 void LyXText::checkParagraph(BufferView * bview, Paragraph * par,
1934                              Paragraph::size_type pos)
1935 {
1936         LyXCursor tmpcursor;                    
1937
1938         int y = 0;
1939         Paragraph::size_type z;
1940         Row * row = getRow(par, pos, y);
1941         
1942         // is there a break one row above
1943         if (row->previous() && row->previous()->par() == row->par()) {
1944                 z = nextBreakPoint(bview, row->previous(), workWidth(bview));
1945                 if (z >= row->pos()) {
1946                         // set the dimensions of the row above
1947                         y -= row->previous()->height();
1948                         refresh_y = y;
1949                         refresh_row = row->previous();
1950                         status(bview, LyXText::NEED_MORE_REFRESH);
1951                         
1952                         breakAgain(bview, row->previous());
1953                         
1954                         // set the cursor again. Otherwise
1955                         // dangling pointers are possible
1956                         setCursor(bview, cursor.par(), cursor.pos(),
1957                                   false, cursor.boundary());
1958                         selection.cursor = cursor;
1959                         return;
1960                 }
1961         }
1962
1963         int const tmpheight = row->height();
1964         Paragraph::size_type const tmplast = rowLast(row);
1965         refresh_y = y;
1966         refresh_row = row;
1967         
1968         breakAgain(bview, row);
1969         if (row->height() == tmpheight && rowLast(row) == tmplast)
1970                 status(bview, LyXText::NEED_VERY_LITTLE_REFRESH);
1971         else
1972                 status(bview, LyXText::NEED_MORE_REFRESH); 
1973         
1974         // check the special right address boxes
1975         if (textclasslist.Style(bview->buffer()->params.textclass,
1976                                 par->getLayout()).margintype
1977             == MARGIN_RIGHT_ADDRESS_BOX) {
1978                 tmpcursor.par(par);
1979                 tmpcursor.row(row);
1980                 tmpcursor.y(y);
1981                 tmpcursor.x(0);
1982                 tmpcursor.x_fix(0);
1983                 tmpcursor.pos(pos);
1984                 redoDrawingOfParagraph(bview, tmpcursor); 
1985         }
1986
1987         // set the cursor again. Otherwise dangling pointers are possible
1988         // also set the selection
1989    
1990         if (selection.set()) {
1991                 tmpcursor = cursor;
1992                 setCursorIntern(bview, selection.cursor.par(), selection.cursor.pos(),
1993                                 false, selection.cursor.boundary());
1994                 selection.cursor = cursor; 
1995                 setCursorIntern(bview, selection.start.par(),
1996                                 selection.start.pos(),
1997                                 false, selection.start.boundary());
1998                 selection.start = cursor; 
1999                 setCursorIntern(bview, selection.end.par(),
2000                                 selection.end.pos(),
2001                                 false, selection.end.boundary());
2002                 selection.end = cursor; 
2003                 setCursorIntern(bview, last_sel_cursor.par(),
2004                                 last_sel_cursor.pos(),
2005                                 false, last_sel_cursor.boundary());
2006                 last_sel_cursor = cursor; 
2007                 cursor = tmpcursor;
2008         }
2009         setCursorIntern(bview, cursor.par(), cursor.pos(),
2010                         false, cursor.boundary());
2011 }
2012
2013
2014 // returns false if inset wasn't found
2015 bool LyXText::updateInset(BufferView * bview, Inset * inset)
2016 {
2017         // first check the current paragraph
2018         int pos = cursor.par()->getPositionOfInset(inset);
2019         if (pos != -1){
2020                 checkParagraph(bview, cursor.par(), pos);
2021                 return true;
2022         }
2023   
2024         // check every paragraph
2025   
2026         Paragraph * par = firstParagraph();
2027         do {
2028                 pos = par->getPositionOfInset(inset);
2029                 if (pos != -1){
2030                         checkParagraph(bview, par, pos);
2031                         return true;
2032                 }
2033                 par = par->next();
2034         } while (par);
2035   
2036         return false;
2037 }
2038
2039
2040 void LyXText::setCursor(BufferView * bview, Paragraph * par,
2041                         Paragraph::size_type pos, 
2042                         bool setfont, bool boundary) const
2043 {
2044         LyXCursor old_cursor = cursor;
2045         setCursorIntern(bview, par, pos, setfont, boundary);
2046         deleteEmptyParagraphMechanism(bview, old_cursor);
2047 }
2048
2049
2050 void LyXText::setCursor(BufferView *bview, LyXCursor & cur, Paragraph * par,
2051                         Paragraph::size_type pos, bool boundary) const
2052 {
2053         cur.par(par);
2054         cur.pos(pos);
2055         cur.boundary(boundary);
2056
2057         // get the cursor y position in text
2058         int y = 0;
2059         Row * row = getRow(par, pos, y);
2060         // y is now the beginning of the cursor row
2061         y += row->baseline();
2062         // y is now the cursor baseline 
2063         cur.y(y);
2064    
2065         // now get the cursors x position
2066         float x;
2067         float fill_separator;
2068         float fill_hfill;
2069         float fill_label_hfill;
2070         prepareToPrint(bview, row, x, fill_separator, fill_hfill,
2071                        fill_label_hfill);
2072         Paragraph::size_type cursor_vpos = 0;
2073         Paragraph::size_type last = rowLastPrintable(row);
2074
2075         if (pos > last + 1)   // This shouldn't happen.
2076                 pos = last + 1;
2077         else if (pos < row->pos())
2078                 pos = row->pos();
2079
2080         if (last < row->pos())
2081                 cursor_vpos = row->pos();
2082         else if (pos > last && !boundary)
2083                 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2084                         ? row->pos() : last + 1; 
2085         else if (pos > row->pos() &&
2086                  (pos > last || boundary))
2087                 /// Place cursor after char at (logical) position pos - 1
2088                 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2089                         ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2090         else
2091                 /// Place cursor before char at (logical) position pos
2092                 cursor_vpos = (bidi_level(pos) % 2 == 0)
2093                         ? log2vis(pos) : log2vis(pos) + 1;
2094         
2095         Paragraph::size_type main_body =
2096                 beginningOfMainBody(bview->buffer(), row->par());
2097         if ((main_body > 0) &&
2098             ((main_body-1 > last) || 
2099              !row->par()->isLineSeparator(main_body-1)))
2100                 main_body = 0;
2101         
2102         for (Paragraph::size_type vpos = row->pos();
2103              vpos < cursor_vpos; ++vpos) {
2104                 pos = vis2log(vpos);
2105                 if (main_body > 0 && pos == main_body - 1) {
2106                         x += fill_label_hfill +
2107                                 lyxfont::width(textclasslist.Style(
2108                                         bview->buffer()->params.textclass,
2109                                         row->par()->getLayout())
2110                                                .labelsep,
2111                                                getLabelFont(bview->buffer(), row->par()));
2112                         if (row->par()->isLineSeparator(main_body-1))
2113                                 x -= singleWidth(bview, row->par(),main_body-1);
2114                 }
2115                 if (hfillExpansion(bview->buffer(), row, pos)) {
2116                         x += singleWidth(bview, row->par(), pos);
2117                         if (pos >= main_body)
2118                                 x += fill_hfill;
2119                         else 
2120                                 x += fill_label_hfill;
2121                 } else if (row->par()->isSeparator(pos)) {
2122                         x += singleWidth(bview, row->par(), pos);
2123                         if (pos >= main_body)
2124                                 x += fill_separator;
2125                 } else
2126                         x += singleWidth(bview, row->par(), pos);
2127         }
2128         
2129         cur.x(int(x));
2130         cur.x_fix(cur.x());
2131         cur.row(row);
2132 }
2133
2134
2135 void LyXText::setCursorIntern(BufferView * bview, Paragraph * par,
2136                               Paragraph::size_type pos,
2137                               bool setfont, bool boundary) const
2138 {
2139         InsetText * it = static_cast<InsetText *>(par->inInset());
2140         if (it && (it != inset_owner)) {
2141                 it->getLyXText(bview)->setCursorIntern(bview, par, pos, setfont,
2142                                                        boundary);
2143         } else {
2144                 setCursor(bview, cursor, par, pos, boundary);
2145                 if (setfont)
2146                         setCurrentFont(bview);
2147         }
2148 }
2149
2150
2151 void LyXText::setCurrentFont(BufferView * bview) const
2152 {
2153         Paragraph::size_type pos = cursor.pos();
2154         if (cursor.boundary() && pos > 0)
2155                 --pos;
2156
2157         if (pos > 0) {
2158                 if (pos == cursor.par()->size())
2159                         --pos;
2160                 else // potentional bug... BUG (Lgb)
2161                         if (cursor.par()->isSeparator(pos)) {
2162                                 if (pos > cursor.row()->pos() &&
2163                                     bidi_level(pos) % 2 == 
2164                                     bidi_level(pos - 1) % 2)
2165                                         --pos;
2166                                 else if (pos + 1 < cursor.par()->size())
2167                                         ++pos;
2168                         }
2169         }
2170
2171         current_font =
2172                 cursor.par()->getFontSettings(bview->buffer()->params, pos);
2173         real_current_font = getFont(bview->buffer(), cursor.par(), pos);
2174
2175         if (cursor.pos() == cursor.par()->size() &&
2176             isBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2177             !cursor.boundary()) {
2178                 Language const * lang =
2179                         cursor.par()->getParLanguage(bview->buffer()->params);
2180                 current_font.setLanguage(lang);
2181                 current_font.setNumber(LyXFont::OFF);
2182                 real_current_font.setLanguage(lang);
2183                 real_current_font.setNumber(LyXFont::OFF);
2184         }
2185 }
2186
2187
2188 void LyXText::setCursorFromCoordinates(BufferView * bview, int x, int y) const
2189 {
2190         LyXCursor old_cursor = cursor;
2191
2192         setCursorFromCoordinates(bview, cursor, x, y);
2193         setCurrentFont(bview);
2194         deleteEmptyParagraphMechanism(bview, old_cursor);
2195 }
2196
2197
2198 void LyXText::setCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2199                                        int x, int y) const
2200 {
2201         // Get the row first.
2202    
2203         Row * row = getRowNearY(y);
2204         bool bound = false;
2205         int const column = getColumnNearX(bview, row, x, bound);
2206    
2207         cur.par(row->par());
2208         cur.pos(row->pos() + column);
2209         cur.x(x);
2210         cur.y(y + row->baseline());
2211         cur.row(row);
2212         cur.boundary(bound);
2213 }
2214
2215
2216 void LyXText::cursorLeft(BufferView * bview, bool internal) const
2217 {
2218         if (cursor.pos() > 0) {
2219                 bool boundary = cursor.boundary();
2220                 setCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2221                 if (!internal && !boundary &&
2222                     isBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2223                         setCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2224         } else if (cursor.par()->previous()) { // steps into the above paragraph.
2225                 Paragraph * par = cursor.par()->previous();
2226                 setCursor(bview, par, par->size());
2227         }
2228 }
2229
2230
2231 void LyXText::cursorRight(BufferView * bview, bool internal) const
2232 {
2233         if (!internal && cursor.boundary() &&
2234             !cursor.par()->isNewline(cursor.pos()))
2235                 setCursor(bview, cursor.par(), cursor.pos(), true, false);
2236         else if (cursor.pos() < cursor.par()->size()) {
2237                 setCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2238                 if (!internal &&
2239                     isBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2240                         setCursor(bview, cursor.par(), cursor.pos(), true, true);
2241         } else if (cursor.par()->next())
2242                 setCursor(bview, cursor.par()->next(), 0);
2243 }
2244
2245
2246 void LyXText::cursorUp(BufferView * bview) const
2247 {
2248         setCursorFromCoordinates(bview, cursor.x_fix(), 
2249                                  cursor.y() - cursor.row()->baseline() - 1);
2250 }
2251
2252
2253 void LyXText::cursorDown(BufferView * bview) const
2254 {
2255         setCursorFromCoordinates(bview, cursor.x_fix(), 
2256                                  cursor.y() - cursor.row()->baseline()
2257                                  + cursor.row()->height() + 1);
2258 }
2259
2260
2261 void LyXText::cursorUpParagraph(BufferView * bview) const
2262 {
2263         if (cursor.pos() > 0) {
2264                 setCursor(bview, cursor.par(), 0);
2265         }
2266         else if (cursor.par()->previous()) {
2267                 setCursor(bview, cursor.par()->previous(), 0);
2268         }
2269 }
2270
2271
2272 void LyXText::cursorDownParagraph(BufferView * bview) const
2273 {
2274         if (cursor.par()->next()) {
2275                 setCursor(bview, cursor.par()->next(), 0);
2276         } else {
2277                 setCursor(bview, cursor.par(), cursor.par()->size());
2278         }
2279 }
2280
2281
2282 void LyXText::deleteEmptyParagraphMechanism(BufferView * bview,
2283                                             LyXCursor const & old_cursor) const
2284 {
2285         // Would be wrong to delete anything if we have a selection.
2286         if (selection.set()) return;
2287
2288         // We allow all kinds of "mumbo-jumbo" when freespacing.
2289         if (textclasslist.Style(bview->buffer()->params.textclass,
2290                                 old_cursor.par()->getLayout()).free_spacing)
2291                 return;
2292
2293         bool deleted = false;
2294         
2295         /* Ok I'll put some comments here about what is missing.
2296            I have fixed BackSpace (and thus Delete) to not delete
2297            double-spaces automagically. I have also changed Cut,
2298            Copy and Paste to hopefully do some sensible things.
2299            There are still some small problems that can lead to
2300            double spaces stored in the document file or space at
2301            the beginning of paragraphs. This happens if you have
2302            the cursor betwenn to spaces and then save. Or if you
2303            cut and paste and the selection have a space at the
2304            beginning and then save right after the paste. I am
2305            sure none of these are very hard to fix, but I will
2306            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2307            that I can get some feedback. (Lgb)
2308         */
2309
2310         // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2311         // delete the LineSeparator.
2312         // MISSING
2313
2314         // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2315         // delete the LineSeparator.
2316         // MISSING
2317
2318         // If the pos around the old_cursor were spaces, delete one of them.
2319         if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) { 
2320                 // Only if the cursor has really moved
2321                 
2322                 if (old_cursor.pos() > 0
2323                     && old_cursor.pos() < old_cursor.par()->size()
2324                     && old_cursor.par()->isLineSeparator(old_cursor.pos())
2325                     && old_cursor.par()->isLineSeparator(old_cursor.pos() - 1)) {
2326                         old_cursor.par()->erase(old_cursor.pos() - 1);
2327                         redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2328                         // correct cursor
2329                         if (old_cursor.par() == cursor.par() &&
2330                             cursor.pos() > old_cursor.pos()) {
2331                                 setCursorIntern(bview, cursor.par(),
2332                                                 cursor.pos() - 1);
2333                         } else
2334                                 setCursorIntern(bview, cursor.par(),
2335                                                 cursor.pos());
2336                         return;
2337                 }
2338         }
2339
2340         // Do not delete empty paragraphs with keepempty set.
2341         if ((textclasslist.Style(bview->buffer()->params.textclass,
2342                                  old_cursor.par()->getLayout())).keepempty)
2343                 return;
2344
2345         LyXCursor tmpcursor;
2346
2347         if (old_cursor.par() != cursor.par()) {
2348                 if ((old_cursor.par()->size() == 0
2349                      || (old_cursor.par()->size() == 1
2350                          && old_cursor.par()->isLineSeparator(0)))) {
2351                         // ok, we will delete anything
2352                         
2353                         // make sure that you do not delete any environments
2354                         status(bview, LyXText::NEED_MORE_REFRESH);
2355                         deleted = true;
2356                                 
2357                         if (old_cursor.row()->previous()) {
2358                                 refresh_row = old_cursor.row()->previous();
2359                                 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2360                                 tmpcursor = cursor;
2361                                 cursor = old_cursor; // that undo can restore the right cursor position
2362                                 Paragraph * endpar = old_cursor.par()->next();
2363                                 if (endpar && endpar->getDepth()) {
2364                                         while (endpar && endpar->getDepth()) {
2365                                                 endpar = endpar->next();
2366                                         }
2367                                 }
2368                                 setUndo(bview, Undo::DELETE,
2369                                         old_cursor.par(),
2370                                         endpar);
2371                                 cursor = tmpcursor;
2372
2373                                 // delete old row
2374                                 removeRow(old_cursor.row());
2375                                 if (ownerParagraph() == old_cursor.par()) {
2376                                         ownerParagraph(ownerParagraph()->next());
2377                                 }
2378                                 // delete old par
2379                                 delete old_cursor.par();
2380                                         
2381                                 /* Breakagain the next par. Needed
2382                                  * because of the parindent that
2383                                  * can occur or dissappear. The
2384                                  * next row can change its height,
2385                                  * if there is another layout before */
2386                                 if (refresh_row->next()) {
2387                                         breakAgain(bview, refresh_row->next());
2388                                         updateCounters(bview, refresh_row);
2389                                 }
2390                                 setHeightOfRow(bview, refresh_row);
2391                         } else {
2392                                 refresh_row = old_cursor.row()->next();
2393                                 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2394                                         
2395                                 tmpcursor = cursor;
2396                                 cursor = old_cursor; // that undo can restore the right cursor position
2397                                 Paragraph * endpar = old_cursor.par()->next();
2398                                 if (endpar && endpar->getDepth()) {
2399                                         while (endpar && endpar->getDepth()) {
2400                                                 endpar = endpar->next();
2401                                         }
2402                                 }
2403                                 setUndo(bview, Undo::DELETE,
2404                                         old_cursor.par(),
2405                                         endpar);
2406                                 cursor = tmpcursor;
2407
2408                                 // delete old row
2409                                 removeRow(old_cursor.row());
2410                                 // delete old par
2411                                 if (ownerParagraph() == old_cursor.par()) {
2412                                         ownerParagraph(ownerParagraph()->next());
2413                                 }
2414
2415                                 delete old_cursor.par();
2416                                         
2417                                 /* Breakagain the next par. Needed
2418                                    because of the parindent that can
2419                                    occur or dissappear.
2420                                    The next row can change its height,
2421                                    if there is another layout before
2422                                 */ 
2423                                 if (refresh_row) {
2424                                         breakAgain(bview, refresh_row);
2425                                         updateCounters(bview, refresh_row->previous());
2426                                 }
2427                         }
2428                                 
2429                                 // correct cursor y
2430
2431                         setCursorIntern(bview, cursor.par(), cursor.pos());
2432
2433                         if (selection.cursor.par()  == old_cursor.par()
2434                             && selection.cursor.pos() == selection.cursor.pos()) {
2435                                 // correct selection
2436                                 selection.cursor = cursor;
2437                         }
2438                 }
2439                 if (!deleted) {
2440                         if (old_cursor.par()->stripLeadingSpaces(bview->buffer()->params.textclass)) {
2441                                 redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2442                                 // correct cursor y
2443                                 setCursorIntern(bview, cursor.par(), cursor.pos());
2444                                 selection.cursor = cursor;
2445                         }
2446                 }
2447         }
2448 }
2449
2450
2451 void LyXText::toggleAppendix(BufferView * bview)
2452 {
2453         Paragraph * par = cursor.par();
2454         bool start = !par->params().startOfAppendix();
2455
2456         // ensure that we have only one start_of_appendix in this document
2457         Paragraph * tmp = firstParagraph();
2458         for (; tmp; tmp = tmp->next()) {
2459                 tmp->params().startOfAppendix(false);
2460         }
2461         
2462         par->params().startOfAppendix(start);
2463
2464         // we can set the refreshing parameters now
2465         status(bview, LyXText::NEED_MORE_REFRESH);
2466         refresh_y = 0;
2467         refresh_row = 0; // not needed for full update
2468         updateCounters(bview, 0);
2469         setCursor(bview, cursor.par(), cursor.pos());
2470 }
2471
2472
2473 Paragraph * LyXText::ownerParagraph() const
2474 {
2475         if (inset_owner) {
2476                 return inset_owner->paragraph();
2477         }
2478         return bv_owner->buffer()->paragraph;
2479 }
2480
2481
2482 Paragraph * LyXText::ownerParagraph(Paragraph * p) const
2483 {
2484         if (inset_owner) {
2485                 inset_owner->paragraph(p);
2486         } else {
2487                 bv_owner->buffer()->paragraph = p;
2488         }
2489         return 0;
2490 }
2491
2492 Paragraph * LyXText::ownerParagraph(int id, Paragraph * p) const
2493 {
2494         Paragraph * op = bv_owner->buffer()->getParFromID(id);
2495         if (op && op->inInset()) {
2496                 static_cast<InsetText *>(op->inInset())->paragraph(p);
2497         } else {
2498                 if (inset_owner) {
2499                         inset_owner->paragraph(p);
2500                 } else {
2501                         bv_owner->buffer()->paragraph = p;
2502                 }
2503         }
2504         return 0;
2505 }
2506
2507
2508 LyXText::text_status LyXText::status() const
2509 {
2510         return status_;
2511 }
2512
2513
2514 void LyXText::status(BufferView * bview, LyXText::text_status st) const
2515 {
2516 #if 0
2517         if ((status_ != NEED_MORE_REFRESH)
2518             || (status_ == NEED_MORE_REFRESH)
2519             && (st != NEED_VERY_LITTLE_REFRESH)) {
2520                 status_ = st;
2521                 if (inset_owner && st != UNCHANGED) {
2522                         bview->text->status(bview, NEED_VERY_LITTLE_REFRESH);
2523                 }
2524         }
2525 #else
2526 #warning Please tell what the intention is here. (Lgb)
2527         // The above does not make any sense, I changed it to what is here,
2528         // but it still does not make much sense. (Lgb)
2529 #warning Sure have a look now! (Jug)
2530         // well as much as I know && binds more then || so the above and the
2531         // below are identical (this for your known use of parentesis!)
2532         // Now some explanation:
2533         // We should only go up with refreshing code so this means that if
2534         // we have a MORE refresh we should never set it to LITTLE if we still
2535         // didn't handle it (and then it will be UNCHANGED. Now as long as
2536         // we stay inside one LyXText this may work but we need to tell the
2537         // outermost LyXText that it should REALLY draw us if there is some
2538         // change in a Inset::LyXText. So you see that when we are inside a
2539         // inset's LyXText we give the LITTLE to the outermost LyXText to
2540         // tell'em that it should redraw the actual row (where the inset
2541         // resides! Capito?!
2542
2543         if ((status_ != NEED_MORE_REFRESH)
2544             || (status_ == NEED_MORE_REFRESH
2545                 && st != NEED_VERY_LITTLE_REFRESH))
2546         {
2547                 status_ = st;
2548                 if (inset_owner && st != UNCHANGED) {
2549                         bview->text->status(bview, NEED_VERY_LITTLE_REFRESH);
2550                         if (!bview->text->refresh_row) {
2551                                 bview->text->refresh_row = bview->text->cursor.row();
2552                                 bview->text->refresh_y = bview->text->cursor.y() -
2553                                         bview->text->cursor.row()->baseline();
2554                         }
2555                 }
2556         }
2557 #endif
2558 }