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