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