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