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