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