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