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