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