]> git.lyx.org Git - lyx.git/blob - src/text.C
constify vars
[lyx.git] / src / text.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *       
6  *           Copyright 1995 Matthias Ettrich
7  *           Copyright 1995-2000 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12 #include <cstdlib>
13 #include <cctype>
14 #include <algorithm>
15
16 #include "layout.h"
17 #include "lyxparagraph.h"
18 #include "lyxtext.h"
19 #include "support/textutils.h"
20 #include "insets/insetbib.h"
21 #include "insets/insettext.h"
22 #include "lyx_gui_misc.h"
23 #include "gettext.h"
24 #include "bufferparams.h"
25 #include "buffer.h"
26 #include "minibuffer.h"
27 #include "debug.h"
28 #include "lyxrc.h"
29 #include "LyXView.h"
30 #include "lyxrow.h"
31 #include "Painter.h"
32 #include "tracer.h"
33 #include "font.h"
34 #include "encoding.h"
35 #include "lyxscreen.h"
36 #include "bufferview_funcs.h"
37
38 using std::max;
39 using std::min;
40 using std::endl;
41 using std::pair;
42
43 namespace {
44
45 int const LYX_PAPER_MARGIN = 20;
46
47 } // namespace anon
48
49 extern int bibitemMaxWidth(BufferView *, LyXFont const &);
50
51
52 int LyXText::workWidth(BufferView * bview) const
53 {
54         if (inset_owner) {
55                 return inset_owner->textWidth(bview);
56         }
57         return bview->workWidth();
58 }
59
60
61 int LyXText::GetRealCursorX(BufferView * bview) const
62 {
63         int x = cursor.x();
64         if (the_locking_inset && (the_locking_inset->getLyXText(bview)!=this))
65                 x = the_locking_inset->getLyXText(bview)->GetRealCursorX(bview);
66         return x;
67 }
68
69
70 unsigned char LyXText::TransformChar(unsigned char c, LyXParagraph * par,
71                         LyXParagraph::size_type pos) const
72 {
73         if (!Encodings::is_arabic(c))
74                 if (lyxrc.font_norm_type == LyXRC::ISO_8859_6_8 && isdigit(c))
75                         return c + (0xb0 - '0');
76                 else
77                         return c;
78
79         unsigned char const prev_char = pos > 0 ? par->GetChar(pos-1) : ' ';
80         unsigned char next_char = ' ';
81 #ifndef NEW_INSETS
82         for (LyXParagraph::size_type i = pos+1; i < par->Last(); ++i)
83 #else
84         for (LyXParagraph::size_type i = pos+1; i < par->size(); ++i)
85 #endif
86                 if (!Encodings::IsComposeChar_arabic(par->GetChar(i))) {
87                         next_char = par->GetChar(i);
88                         break;
89                 }
90
91         if (Encodings::is_arabic(next_char)) {
92                 if (Encodings::is_arabic(prev_char))
93                         return Encodings::TransformChar(c, Encodings::FORM_MEDIAL);
94                 else
95                         return Encodings::TransformChar(c, Encodings::FORM_INITIAL);
96         } else {
97                 if (Encodings::is_arabic(prev_char))
98                         return Encodings::TransformChar(c, Encodings::FORM_FINAL);
99                 else
100                         return Encodings::TransformChar(c, Encodings::FORM_ISOLATED);
101         }
102 }
103
104 // This is the comments that some of the warnings below refers to.
105 // There are some issues in this file and I don't think they are
106 // really related to the FIX_DOUBLE_SPACE patch. I'd rather think that
107 // this is a problem that has been here almost from day one and that a
108 // larger userbase with differenct access patters triggers the bad
109 // behaviour. (segfaults.) What I think happen is: In several places
110 // we store the paragraph in the current cursor and then moves the
111 // cursor. This movement of the cursor will delete paragraph at the
112 // old position if it is now empty. This will make the temporary
113 // pointer to the old cursor paragraph invalid and dangerous to use.
114 // And is some cases this will trigger a segfault. I have marked some
115 // of the cases where this happens with a warning, but I am sure there
116 // are others in this file and in text2.C. There is also a note in
117 // Delete() that you should read. In Delete I store the paragraph->id
118 // instead of a pointer to the paragraph. I am pretty sure this faulty
119 // use of temporary pointers to paragraphs that might have gotten
120 // invalidated (through a cursor movement) before they are used, are
121 // the cause of the strange crashes we get reported often.
122 //
123 // It is very tiresom to change this code, especially when it is as
124 // hard to read as it is. Help to fix all the cases where this is done
125 // would be greately appreciated.
126 //
127 // Lgb
128
129 int LyXText::SingleWidth(BufferView * bview, LyXParagraph * par,
130                          LyXParagraph::size_type pos) const
131 {
132         char const c = par->GetChar(pos);
133         return SingleWidth(bview, par, pos, c);
134 }
135
136
137 int LyXText::SingleWidth(BufferView * bview, LyXParagraph * par,
138                          LyXParagraph::size_type pos, char c) const
139 {
140         LyXFont const font = GetFont(bview->buffer(), par, pos);
141
142         // The most common case is handled first (Asger)
143         if (IsPrintable(c)) {
144                 if (font.language()->RightToLeft()) {
145                         if (font.language()->lang() == "arabic" &&
146                             (lyxrc.font_norm_type == LyXRC::ISO_8859_6_8 ||
147                              lyxrc.font_norm_type == LyXRC::ISO_10646_1))
148                                 if (Encodings::IsComposeChar_arabic(c))
149                                         return 0;
150                                 else
151                                         c = TransformChar(c, par, pos);
152                         else if (font.language()->lang() == "hebrew" &&
153                                  Encodings::IsComposeChar_hebrew(c))
154                                 return 0;
155                 }
156                 return lyxfont::width(c, font);
157
158         } else if (IsHfillChar(c)) {
159                 return 3;       /* Because of the representation
160                                  * as vertical lines */
161 #ifndef NEW_INSETS
162         } else if (c == LyXParagraph::META_FOOTNOTE ||
163                    c == LyXParagraph::META_MARGIN ||
164                    c == LyXParagraph::META_FIG ||
165                    c == LyXParagraph::META_TAB ||
166                    c == LyXParagraph::META_WIDE_FIG ||
167                    c == LyXParagraph::META_WIDE_TAB ||
168                    c == LyXParagraph::META_ALGORITHM) {
169                 string fs;
170                 switch (c) {
171                 case LyXParagraph::META_MARGIN:
172                         fs = "margin";
173                         break;
174                 case LyXParagraph::META_FIG:
175                         fs = "fig";
176                         break;
177                 case LyXParagraph::META_TAB:
178                         fs = "tab";
179                         break;
180                 case LyXParagraph::META_ALGORITHM:
181                         fs = "alg";
182                         break;
183                 case LyXParagraph::META_WIDE_FIG:
184                         fs = "wide-fig";
185                         break;
186                 case LyXParagraph::META_WIDE_TAB:
187                         fs = "wide-tab";
188                         break;
189                 case LyXParagraph::META_FOOTNOTE:
190                         fs = "foot";
191                         break;
192                 }
193                 font.decSize();
194                 font.decSize();
195                 return lyxfont::width(fs, font);
196 #endif
197         } else if (c == LyXParagraph::META_INSET) {
198                 Inset * tmpinset = par->GetInset(pos);
199                 if (tmpinset) {
200                         tmpinset->update(bview, font);
201                         return tmpinset->width(bview, font);
202                 } else
203                         return 0;
204
205         } else if (IsSeparatorChar(c))
206                 c = ' ';
207         else if (IsNewlineChar(c))
208                 c = 'n';
209         return lyxfont::width(c, font);
210 }
211
212
213 // Returns the paragraph position of the last character in the specified row
214 LyXParagraph::size_type LyXText::RowLast(Row const * row) const
215 {
216 #ifndef NEW_INSETS
217         if (row->next() == 0)
218                 return row->par()->Last() - 1;
219         else if (row->next()->par() != row->par()) 
220                 return row->par()->Last() - 1;
221         else 
222                 return row->next()->pos() - 1;
223 #else
224         if (row->next() == 0)
225                 return row->par()->size() - 1;
226         else if (row->next()->par() != row->par()) 
227                 return row->par()->size() - 1;
228         else 
229                 return row->next()->pos() - 1;
230 #endif
231 }
232
233
234 LyXParagraph::size_type LyXText::RowLastPrintable(Row const * row) const
235 {
236         LyXParagraph::size_type const last = RowLast(row);
237         if (last >= row->pos()
238             && row->next()
239             && row->next()->par() == row->par()
240             && row->par()->IsSeparator(last))
241                 return last - 1;
242         else
243                 return last;
244 }
245
246
247 void LyXText::ComputeBidiTables(Buffer const * buf, Row * row) const
248 {
249         bidi_same_direction = true;
250         if (!lyxrc.rtl_support) {
251                 bidi_start = -1;
252                 return;
253         }
254
255         bidi_start = row->pos();
256         bidi_end = RowLastPrintable(row);
257
258         if (bidi_start > bidi_end) {
259                 bidi_start = -1;
260                 return;
261         }
262
263         if (bidi_end + 2 - bidi_start >
264             static_cast<LyXParagraph::size_type>(log2vis_list.size())) {
265                 LyXParagraph::size_type new_size = 
266                         (bidi_end + 2 - bidi_start < 500) ?
267                         500 : 2 * (bidi_end + 2 - bidi_start);
268                 log2vis_list.resize(new_size);
269                 vis2log_list.resize(new_size);
270                 bidi_levels.resize(new_size);
271         }
272
273         vis2log_list[bidi_end + 1 - bidi_start] = -1;
274         log2vis_list[bidi_end + 1 - bidi_start] = -1;
275
276         LyXParagraph::size_type stack[2];
277         bool const rtl_par =
278                 row->par()->getParLanguage(buf->params)->RightToLeft();
279         int level = 0;
280         bool rtl = false;
281         bool rtl0 = false;
282         LyXParagraph::size_type const main_body =
283                 BeginningOfMainBody(buf, row->par());
284
285         for (LyXParagraph::size_type lpos = bidi_start;
286              lpos <= bidi_end; ++lpos) {
287                 bool is_space = row->par()->IsLineSeparator(lpos);
288                 LyXParagraph::size_type const pos =
289                         (is_space && lpos + 1 <= bidi_end &&
290                          !row->par()->IsLineSeparator(lpos + 1) &&
291                          !row->par()->IsNewline(lpos + 1))
292                         ? lpos + 1 : lpos;
293                 LyXFont font = row->par()->GetFontSettings(buf->params, pos);
294                 if (pos != lpos && 0 < lpos && rtl0 && font.isRightToLeft() &&
295                     font.number() == LyXFont::ON &&
296                     row->par()->GetFontSettings(buf->params, lpos-1).number()
297                     == LyXFont::ON) {
298                         font = row->par()->GetFontSettings(buf->params, lpos);
299                         is_space = false;
300                 }
301
302
303                 bool new_rtl = font.isVisibleRightToLeft();
304                 bool new_rtl0 = font.isRightToLeft();
305                 int new_level;
306
307                 if (lpos == main_body - 1
308                     && row->pos() < main_body - 1
309                     && is_space) {
310                         new_level = (rtl_par) ? 1 : 0;
311                         new_rtl = new_rtl0 = rtl_par;
312                 } else if (new_rtl0)
313                         new_level = (new_rtl) ? 1 : 2;
314                 else
315                         new_level = (rtl_par) ? 2 : 0;
316
317                 if (is_space && new_level >= level) {
318                         new_level = level;
319                         new_rtl = rtl;
320                         new_rtl0 = rtl0;
321                 }
322
323                 int new_level2 = new_level;
324
325                 if (level == new_level && rtl0 != new_rtl0) {
326                         --new_level2;
327                         log2vis_list[lpos - bidi_start] = (rtl) ? 1 : -1;
328                 } else if (level < new_level) {
329                         log2vis_list[lpos - bidi_start] =  (rtl) ? -1 : 1;
330                         if (new_level > rtl_par)
331                                 bidi_same_direction = false;
332                 } else
333                         log2vis_list[lpos - bidi_start] = (new_rtl) ? -1 : 1;
334                 rtl = new_rtl;
335                 rtl0 = new_rtl0;
336                 bidi_levels[lpos - bidi_start] = new_level;
337
338                 while (level > new_level2) {
339                         LyXParagraph::size_type old_lpos =
340                                 stack[--level];
341                         int delta = lpos - old_lpos - 1;
342                         if (level % 2)
343                                 delta = -delta;
344                         log2vis_list[lpos - bidi_start] += delta;
345                         log2vis_list[old_lpos - bidi_start] += delta;
346                 }
347                 while (level < new_level)
348                         stack[level++] = lpos;
349         }
350
351         while (level > 0) {
352                 LyXParagraph::size_type const old_lpos = stack[--level];
353                 int delta = bidi_end - old_lpos;
354                 if (level % 2)
355                         delta = -delta;
356                 log2vis_list[old_lpos - bidi_start] += delta;
357         }
358
359         LyXParagraph::size_type vpos = bidi_start - 1;
360         for (LyXParagraph::size_type lpos = bidi_start;
361              lpos <= bidi_end; ++lpos) {
362                 vpos += log2vis_list[lpos - bidi_start];
363                 vis2log_list[vpos - bidi_start] = lpos;
364                 log2vis_list[lpos - bidi_start] = vpos;
365         }
366 }
367
368
369 // This method requires a previous call to ComputeBidiTables()
370 bool LyXText::IsBoundary(Buffer const * buf, LyXParagraph * par,
371                          LyXParagraph::size_type pos) const
372 {
373         if (!lyxrc.rtl_support || pos == 0)
374                 return false;
375
376         if (!bidi_InRange(pos - 1)) {
377                 /// This can happen if pos is the first char of a row.
378                 /// Returning false in this case is incorrect!
379                 return false;
380         }
381
382         bool const rtl = bidi_level(pos - 1) % 2;
383         bool const rtl2 = bidi_InRange(pos)
384                 ? bidi_level(pos) % 2
385                 : par->isRightToLeftPar(buf->params);
386         return rtl != rtl2;
387 }
388
389
390 bool LyXText::IsBoundary(Buffer const * buf, LyXParagraph * par,
391                          LyXParagraph::size_type pos,
392                          LyXFont const & font) const
393 {
394         if (!lyxrc.rtl_support)
395                 return false;    // This is just for speedup
396
397         bool const rtl = font.isVisibleRightToLeft();
398         bool const rtl2 = bidi_InRange(pos)
399                 ? bidi_level(pos) % 2
400                 : par->isRightToLeftPar(buf->params);
401         return rtl != rtl2;
402 }
403
404
405 void LyXText::draw(BufferView * bview, Row const * row,
406                    LyXParagraph::size_type & vpos,
407                    int offset, float & x, bool cleared)
408 {
409         Painter & pain = bview->painter();
410         
411         LyXParagraph::size_type pos = vis2log(vpos);
412         char c = row->par()->GetChar(pos);
413         float tmpx = x;
414
415         if (IsNewlineChar(c)) {
416                 ++vpos;
417                 // Draw end-of-line marker
418                 LyXFont const font = GetFont(bview->buffer(), row->par(), pos);
419                 int const wid = lyxfont::width('n', font);
420                 int const asc = lyxfont::maxAscent(font);
421                 int const y = offset + row->baseline();
422                 int xp[3];
423                 int yp[3];
424                 
425                 if (bidi_level(pos) % 2 == 0) {
426                         xp[0] = int(x + wid * 0.375);
427                         yp[0] = int(y - 0.875 * asc * 0.75);
428                         
429                         xp[1] = int(x);
430                         yp[1] = int(y - 0.500 * asc * 0.75);
431                         
432                         xp[2] = int(x + wid * 0.375);
433                         yp[2] = int(y - 0.125 * asc * 0.75);
434                         
435                         pain.lines(xp, yp, 3, LColor::eolmarker);
436                         
437                         xp[0] = int(x);
438                         yp[0] = int(y - 0.500 * asc * 0.75);
439                         
440                         xp[1] = int(x + wid);
441                         yp[1] = int(y - 0.500 * asc * 0.75);
442                         
443                         xp[2] = int(x + wid);
444                         yp[2] = int(y - asc * 0.75);
445                         
446                         pain.lines(xp, yp, 3, LColor::eolmarker);
447                 } else {
448                         xp[0] = int(x + wid * 0.625);
449                         yp[0] = int(y - 0.875 * asc * 0.75);
450                         
451                         xp[1] = int(x + wid);
452                         yp[1] = int(y - 0.500 * asc * 0.75);
453                         
454                         xp[2] = int(x + wid * 0.625);
455                         yp[2] = int(y - 0.125 * asc * 0.75);
456                         
457                         pain.lines(xp, yp, 3, LColor::eolmarker);
458                         
459                         xp[0] = int(x + wid);
460                         yp[0] = int(y - 0.500 * asc * 0.75);
461                         
462                         xp[1] = int(x);
463                         yp[1] = int(y - 0.500 * asc * 0.75);
464                         
465                         xp[2] = int(x);
466                         yp[2] = int(y - asc * 0.75);
467                         
468                         pain.lines(xp, yp, 3, LColor::eolmarker);
469                 }
470                 x += wid;
471                 return;
472         }
473
474         LyXFont font = GetFont(bview->buffer(), row->par(), pos);
475         LyXFont font2 = font;
476 #ifndef NEW_INSETS
477         if (c == LyXParagraph::META_FOOTNOTE
478             || c == LyXParagraph::META_MARGIN
479             || c == LyXParagraph::META_FIG
480             || c == LyXParagraph::META_TAB
481             || c == LyXParagraph::META_WIDE_FIG
482             || c == LyXParagraph::META_WIDE_TAB
483             || c == LyXParagraph::META_ALGORITHM) {
484                 string fs;
485                 switch (c) {
486                 case LyXParagraph::META_MARGIN:
487                         fs = "margin";
488                         break;
489                 case LyXParagraph::META_FIG:
490                         fs = "fig";
491                         break;
492                 case LyXParagraph::META_TAB:
493                         fs = "tab";
494                         break;
495                 case LyXParagraph::META_ALGORITHM:
496                         fs = "alg";
497                         break;
498                 case LyXParagraph::META_WIDE_FIG:
499                         fs = "wide-fig";
500                         break;
501                 case LyXParagraph::META_WIDE_TAB:
502                         fs = "wide-tab";
503                         break;
504                 case LyXParagraph::META_FOOTNOTE:
505                         fs = "foot";
506                         break;
507                 }
508                 font.decSize();
509                 font.decSize();
510           
511                 // calculate the position of the footnotemark
512                 int const y = (row->baseline() - lyxfont::maxAscent(font2) 
513                                + lyxfont::maxAscent(font));
514           
515                 font.setColor(LColor::footnote);
516
517                 // draw it and set new x position
518                 
519                 pain.text(int(x), offset + y, fs, font);
520                 x += lyxfont::width(fs, font);
521                 pain.line(int(tmpx), offset + row->baseline(),
522                           int(x), offset + row->baseline(),
523                           LColor::footnote);
524
525                 ++vpos;
526                 return;
527         } else
528 #endif
529                 if (c == LyXParagraph::META_INSET) {
530                 Inset * tmpinset = row->par()->GetInset(pos);
531                 if (tmpinset) {
532 //                      tmpinset->update(bview, font, false);
533                         tmpinset->draw(bview, font, offset+row->baseline(), x,
534                                        cleared);
535 #ifdef SEEMS_TO_BE_NOT_NEEDED
536                         if (status == CHANGED_IN_DRAW) {
537                                 UpdateInset(bview, tmpinset);
538                                 status = CHANGED_IN_DRAW;
539                         }
540 #endif
541                 }
542                 ++vpos;
543
544                 if (lyxrc.mark_foreign_language &&
545                     font.language() != bview->buffer()->params.language) {
546                         int const y = offset + row->height() - 1;
547                         pain.line(int(tmpx), y, int(x), y,
548                                   LColor::language);
549                 }
550
551                 return;
552         }
553
554         /* usual characters, no insets */
555
556         // Collect character that we can draw in one command
557
558         // This is dirty, but fast. Notice that it will never be too small.
559         // For the record, I'll note that Microsoft Word has a limit
560         // of 768 here. We have none :-) (Asger)
561         // Ok. I am the first to admit that the use of std::string will be
562         // a tiny bit slower than using a POD char array. However, I claim
563         // that this slowdown is so small that it is close to inperceptive.
564         // So IMHO we should go with the easier and clearer implementation.
565         // And even if 1024 is a large number here it might overflow, string
566         // will only overflow if the machine is out of memory...
567         static string textstring;
568         textstring = c;
569         ++vpos;
570
571         LyXParagraph::size_type const last = RowLastPrintable(row);
572
573         if (font.language()->lang() == "hebrew") {
574                 if (Encodings::IsComposeChar_hebrew(c)) {
575                         int const width = lyxfont::width(c, font2);
576                         int dx = 0;
577                         for (LyXParagraph::size_type i = pos-1; i >= 0; --i) {
578                                 c = row->par()->GetChar(i);
579                                 if (!Encodings::IsComposeChar_hebrew(c)) {
580                                         if (IsPrintableNonspace(c)) {
581                                                 int const width2 =
582                                                         SingleWidth(bview,
583                                                                     row->par(),
584                                                                     i, c);
585                                                 dx = (c == 'ø' || c == 'ã') // dalet / resh
586                                                         ? width2 - width : (width2 - width) / 2;
587                                         }
588                                         break;
589                                 }
590                         }
591                         // Draw nikud
592                         pain.text(int(x) + dx, offset + row->baseline(),
593                                   textstring, font);
594                 } else {
595                         while (vpos <= last &&
596                                (pos = vis2log(vpos)) >= 0
597                                && IsPrintableNonspace(c = row->par()->GetChar(pos))
598                                && !Encodings::IsComposeChar_hebrew(c)
599                                && font2 == GetFont(bview->buffer(), row->par(), pos)) {
600                                 textstring += c;
601                                 ++vpos;
602                         }
603                         // Draw text and set the new x position
604                         pain.text(int(x), offset + row->baseline(),
605                                   textstring, font);
606                         x += lyxfont::width(textstring, font);
607                 }
608         } else if (font.language()->lang() == "arabic" &&
609                    (lyxrc.font_norm_type == LyXRC::ISO_8859_6_8 ||
610                     lyxrc.font_norm_type == LyXRC::ISO_10646_1)) {
611                 if (Encodings::IsComposeChar_arabic(c)) {
612                         c = TransformChar(c, row->par(), pos);
613                         textstring = c;
614                         int const width = lyxfont::width(c, font2);
615                         int dx = 0;
616                         for (LyXParagraph::size_type i = pos-1; i >= 0; --i) {
617                                 c = row->par()->GetChar(i);
618                                 if (!Encodings::IsComposeChar_arabic(c)) {
619                                         if (IsPrintableNonspace(c)) {
620                                                 int const width2 =
621                                                         SingleWidth(bview,
622                                                                     row->par(),
623                                                                     i, c);
624                                                 dx = (width2 - width) / 2;
625                                         }
626                                         break;
627                                 }
628                         }
629                         // Draw nikud
630                         pain.text(int(x) + dx, offset + row->baseline(), 
631                                   textstring, font);
632                 } else {
633                         textstring = TransformChar(c, row->par(), pos);
634                         while (vpos <= last &&
635                                (pos = vis2log(vpos)) >= 0
636                                && IsPrintableNonspace(c = row->par()->GetChar(pos))
637                                && !Encodings::IsComposeChar_arabic(c)
638                                && font2 == GetFont(bview->buffer(), row->par(), pos)) {
639                                 c = TransformChar(c, row->par(), pos);
640                                 textstring += c;
641                                 ++vpos;
642                         }
643                         // Draw text and set the new x position
644                         pain.text(int(x), offset + row->baseline(),
645                                   textstring, font);
646                         x += lyxfont::width(textstring, font);
647                 }
648         } else {
649                 while (vpos <= last &&
650                        (pos = vis2log(vpos)) >= 0
651                        && IsPrintableNonspace(c = row->par()->GetChar(pos))
652                        && font2 == GetFont(bview->buffer(), row->par(), pos)) {
653                         textstring += c;
654                         ++vpos;
655                 }
656                 // Draw text and set the new x position
657                 pain.text(int(x), offset + row->baseline(), textstring, font);
658                 x += lyxfont::width(textstring, font);
659         }
660
661         if (lyxrc.mark_foreign_language &&
662             font.language() != bview->buffer()->params.language) {
663                 int const y = offset + row->height() - 1;
664                 pain.line(int(tmpx), y, int(x), y,
665                           LColor::language);
666         }
667
668         // If we want ulem.sty support, drawing
669         // routines should go here. (Asger)
670         // Why shouldn't LyXFont::drawText handle it internally?
671 }
672
673
674 // Returns the left beginning of the text. 
675 // This information cannot be taken from the layouts-objekt, because in 
676 // LaTeX the beginning of the text fits in some cases (for example sections)
677 // exactly the label-width.
678 int LyXText::LeftMargin(BufferView * bview, Row const * row) const
679 {
680         LyXLayout const & layout =
681                 textclasslist.Style(bview->buffer()->params.textclass,
682                                     row->par()->GetLayout());
683         
684         string parindent = layout.parindent; 
685
686         int x = LYX_PAPER_MARGIN;
687         
688         x += lyxfont::signedWidth(textclasslist
689                                   .TextClass(bview->buffer()->params.textclass)
690                                   .leftmargin(),
691                                   textclasslist
692                                   .TextClass(bview->buffer()->params.textclass)
693                                   .defaultfont());
694 #ifndef NEW_INSETS
695         if (row->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)  {
696                 LyXFont font(LyXFont::ALL_SANE);
697                 font.setSize(LyXFont::SIZE_SMALL);
698                 x += lyxfont::width("Mwide-figM", font)
699                         + LYX_PAPER_MARGIN/2;
700         }
701 #endif
702         // this is the way, LyX handles the LaTeX-Environments.
703         // I have had this idea very late, so it seems to be a
704         // later added hack and this is true
705         if (!row->par()->GetDepth()) {
706                 if (!row->par()->GetLayout()) {
707                         // find the previous same level paragraph
708 #ifndef NEW_INSETS
709                         if (row->par()->FirstPhysicalPar()->previous()) {
710 #else
711                         if (row->par()->previous()) {
712 #endif
713                                 LyXParagraph * newpar = row->par()
714                                         ->DepthHook(row->par()->GetDepth());
715                                 if (newpar &&
716                                     textclasslist.Style(bview->buffer()->params.textclass,
717                                                         newpar->GetLayout())
718                                     .nextnoindent)
719                                         parindent.erase();
720                         }
721                 }
722         } else {
723                 // find the next level paragraph
724                 
725                 LyXParagraph * newpar =
726                         row->par()->DepthHook(row->par()->GetDepth()-1);
727                 
728                 // make a corresponding row. Needed to call LeftMargin()
729                 
730                 // check wether it is a sufficent paragraph 
731                 if (newpar
732 #ifndef NEW_INSETS
733                     && newpar->footnoteflag == row->par()->footnoteflag
734 #endif
735                     && textclasslist
736                         .Style(bview->buffer()->params.textclass, 
737                                newpar->GetLayout()).isEnvironment()) {
738                         Row dummyrow;
739                         dummyrow.par(newpar);
740 #ifndef NEW_INSETS
741                         dummyrow.pos(newpar->Last());
742 #else
743                         dummyrow.pos(newpar->size());
744 #endif
745                         x = LeftMargin(bview, &dummyrow);
746                 } else {
747                         // this is no longer an error, because this function
748                         // is used to clear impossible depths after changing
749                         // a layout. Since there is always a redo,
750                         // LeftMargin() is always called
751 #ifndef NEW_INSETS
752                         row->par()->FirstPhysicalPar()->params.depth(0);
753 #else
754                         row->par()->params.depth(0);
755 #endif
756                 }
757                 
758                 if (newpar && !row->par()->GetLayout()) {
759 #ifndef NEW_INSETS
760                         if (newpar->FirstPhysicalPar()->params.noindent())
761 #else
762                         if (newpar->params.noindent())
763 #endif
764                                 parindent.erase();
765                         else
766                                 parindent = textclasslist
767                                         .Style(bview->buffer()->params.textclass, 
768                                                newpar->GetLayout()).parindent;
769                 }
770                 
771         }
772         
773         LyXFont const labelfont = GetFont(bview->buffer(), row->par(), -2);
774         switch (layout.margintype) {
775         case MARGIN_DYNAMIC:
776                 if (!layout.leftmargin.empty()) {
777                         x += lyxfont::signedWidth(layout.leftmargin,
778                                                   textclasslist
779                                                   .TextClass(bview->buffer()->params.
780                                                              textclass)
781                                                   .defaultfont());
782                 }
783                 if (!row->par()->GetLabelstring().empty()) {
784                         x += lyxfont::signedWidth(layout.labelindent,
785                                                   labelfont);
786                         x += lyxfont::width(row->par()->GetLabelstring(),
787                                             labelfont);
788                         x += lyxfont::width(layout.labelsep, labelfont);
789                 }
790                 break;
791         case MARGIN_MANUAL:
792                 x += lyxfont::signedWidth(layout.labelindent, labelfont);
793                 if (row->pos() >= BeginningOfMainBody(bview->buffer(), row->par())) {
794                         if (!row->par()->GetLabelWidthString().empty()) {
795                                 x += lyxfont::width(row->par()->GetLabelWidthString(),
796                                                labelfont);
797                                 x += lyxfont::width(layout.labelsep, labelfont);
798                         }
799                 }
800                 break;
801         case MARGIN_STATIC:
802                 x += lyxfont::signedWidth(layout.leftmargin, textclasslist.TextClass(bview->buffer()->params.textclass).defaultfont()) * 4
803                         / (row->par()->GetDepth() + 4);
804                 break;
805         case MARGIN_FIRST_DYNAMIC:
806                 if (layout.labeltype == LABEL_MANUAL) {
807                         if (row->pos() >= BeginningOfMainBody(bview->buffer(), row->par())) {
808                                 x += lyxfont::signedWidth(layout.leftmargin,
809                                                           labelfont);
810                         } else {
811                                 x += lyxfont::signedWidth(layout.labelindent,
812                                                           labelfont);
813                         }
814                 } else if (row->pos()
815                            // Special case to fix problems with
816                            // theorems (JMarc)
817                            || (layout.labeltype == LABEL_STATIC
818                                && layout.latextype == LATEX_ENVIRONMENT
819                                && ! row->par()->IsFirstInSequence())) {
820                         x += lyxfont::signedWidth(layout.leftmargin,
821                                                   labelfont);
822                 } else if (layout.labeltype != LABEL_TOP_ENVIRONMENT
823                            && layout.labeltype != LABEL_BIBLIO
824                            && layout.labeltype !=
825                            LABEL_CENTERED_TOP_ENVIRONMENT) {
826                         x += lyxfont::signedWidth(layout.labelindent,
827                                                   labelfont);
828                         x += lyxfont::width(layout.labelsep, labelfont);
829                         x += lyxfont::width(row->par()->GetLabelstring(),
830                                             labelfont);
831                 } 
832                 break;
833                 
834         case MARGIN_RIGHT_ADDRESS_BOX:
835         {
836                 // ok, a terrible hack. The left margin depends on the widest
837                 // row in this paragraph. Do not care about footnotes, they
838                 // are *NOT* allowed in the LaTeX realisation of this layout.
839                 
840                 // find the first row of this paragraph
841                 Row const * tmprow = row;
842                 while (tmprow->previous()
843                        && tmprow->previous()->par() == row->par())
844                         tmprow = tmprow->previous();
845                 
846                 int minfill = tmprow->fill();
847                 while (tmprow->next() && tmprow->next()->par() == row->par()) {
848                         tmprow = tmprow->next();
849                         if (tmprow->fill() < minfill)
850                                 minfill = tmprow->fill();
851                 }
852                 
853                 x += lyxfont::signedWidth(layout.leftmargin,
854                                           textclasslist
855                                           .TextClass(bview->buffer()->params.textclass)
856                                           .defaultfont());
857                 x += minfill;
858         }
859         break;
860         }
861 #ifndef NO_PEXTRA
862         if ((workWidth(bview) > 0) &&
863             (row->par()->params.pextraType() == LyXParagraph::PEXTRA_INDENT)) {
864                 if (!row->par()->params.pextraWidthp().empty()) {
865                         x += workWidth(bview) *
866                                 lyx::atoi(row->par()->params.pextraWidthp()) / 100;
867                 } else if (!row->par()->params.pextraWidth().empty()) {
868                         int xx = VSpace(row->par()->params.pextraWidth()).inPixels(bview);
869                         if (xx > workWidth(bview))
870                                 xx = workWidth(bview) * 80 / 100;
871                         x += xx;
872                 } else { // should not happen
873                         LyXFont font(LyXFont::ALL_SANE);
874                         x += lyxfont::width("XXXXXX", font);
875                 }
876         }
877 #endif
878         
879         int align; // wrong type
880 #ifndef NEW_INSETS
881         if (row->par()->FirstPhysicalPar()->params.align() == LYX_ALIGN_LAYOUT)
882                 align = layout.align;
883         else
884                 align = row->par()->FirstPhysicalPar()->params.align();
885 #else
886         if (row->par()->params.align() == LYX_ALIGN_LAYOUT)
887                 align = layout.align;
888         else
889                 align = row->par()->params.align();
890 #endif  
891         // set the correct parindent
892         if (row->pos() == 0) {
893                 if ((layout.labeltype == LABEL_NO_LABEL 
894                      || layout.labeltype == LABEL_TOP_ENVIRONMENT 
895                      || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT
896                      || (layout.labeltype == LABEL_STATIC
897                          && layout.latextype == LATEX_ENVIRONMENT
898                          && ! row->par()->IsFirstInSequence()))
899 #ifndef NEW_INSETS
900                     && row->par() == row->par()->FirstPhysicalPar()
901 #endif
902                     && align == LYX_ALIGN_BLOCK
903                     && !row->par()->params.noindent()
904                     && (row->par()->layout ||
905                         bview->buffer()->params.paragraph_separation ==
906                         BufferParams::PARSEP_INDENT))
907                         x += lyxfont::signedWidth(parindent,
908                                                   textclasslist
909                                                   .TextClass(bview->buffer()->params
910                                                              .textclass)
911                                                   .defaultfont());
912                 else if (layout.labeltype == LABEL_BIBLIO) {
913                         // ale970405 Right width for bibitems
914                         x += bibitemMaxWidth(bview,textclasslist
915                                              .TextClass(bview->buffer()->params
916                                                         .textclass)
917                                              .defaultfont());
918                 }
919         }
920         return x;
921 }
922
923
924 int LyXText::RightMargin(Buffer const * buf, Row const * row) const
925 {
926         LyXLayout const & layout =
927                 textclasslist.Style(buf->params.textclass,
928                                     row->par()->GetLayout());
929         
930         int x = LYX_PAPER_MARGIN
931                 + lyxfont::signedWidth(textclasslist
932                                        .TextClass(buf->params.textclass)
933                                        .rightmargin(),
934                                        textclasslist
935                                        .TextClass(buf->params.textclass)
936                                        .defaultfont());
937
938 #ifndef NEW_INSETS
939         if (row->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)  {
940                 x += LYX_PAPER_MARGIN / 2;
941         }
942 #endif
943         // this is the way, LyX handles the LaTeX-Environments.
944         // I have had this idea very late, so it seems to be a
945         // later added hack and this is true
946         if (row->par()->GetDepth()) {
947                 // find the next level paragraph
948                 
949                 LyXParagraph * newpar = row->par();
950                 
951 #ifndef NEW_INSETS
952                 do {
953                         newpar = newpar->FirstPhysicalPar()->previous();
954                         if (newpar) 
955                                 newpar = newpar->FirstPhysicalPar();
956                 } while (newpar && newpar->GetDepth() >= row->par()->GetDepth()
957                          && newpar->footnoteflag == row->par()->footnoteflag);
958 #else
959                 do {
960                         newpar = newpar->previous();
961                 } while (newpar
962                          && newpar->GetDepth() >= row->par()->GetDepth());
963 #endif
964                 
965                 // make a corresponding row. Needed to call LeftMargin()
966                 
967                 // check wether it is a sufficent paragraph
968                 if (newpar
969 #ifndef NEW_INSETS
970                     && newpar->footnoteflag == row->par()->footnoteflag
971 #endif
972                     && textclasslist.Style(buf->params.textclass,
973                                            newpar->GetLayout())
974                        .isEnvironment()) {
975                         Row dummyrow;
976                         dummyrow.par(newpar);
977                         dummyrow.pos(0);
978                         x = RightMargin(buf, &dummyrow);
979                 } else {
980                         // this is no longer an error, because this function
981                         // is used to clear impossible depths after changing
982                         // a layout. Since there is always a redo,
983                         // LeftMargin() is always called
984 #ifndef NEW_INSETS
985                         row->par()->FirstPhysicalPar()->params.depth(0);
986 #else
987                         row->par()->params.depth(0);
988 #endif
989                 }
990         }
991         
992         //lyxerr << "rightmargin: " << layout->rightmargin << endl;
993         x += lyxfont::signedWidth(layout.rightmargin, textclasslist
994                                   .TextClass(buf->params.textclass)
995                                   .defaultfont()) * 4 / (row->par()->GetDepth()
996                                                          + 4);
997         return x;
998 }
999
1000
1001 int LyXText::LabelEnd(BufferView * bview, Row const * row) const
1002 {
1003         if (textclasslist.Style(bview->buffer()->params.textclass,
1004                                 row->par()->GetLayout()).margintype
1005             == MARGIN_MANUAL) {
1006                 Row tmprow;
1007                 tmprow = *row;
1008 #ifndef NEW_INSETS
1009                 tmprow.pos(row->par()->Last());
1010 #else
1011                 tmprow.pos(row->par()->size());
1012 #endif
1013                 return LeftMargin(bview, &tmprow);  /* just the beginning 
1014                                                 of the main body */
1015         } else
1016                 return 0;  /* LabelEnd is only needed, if the  
1017                               layout fills a flushleft
1018                               label. */
1019 }
1020
1021
1022 // get the next breakpoint in a given paragraph
1023 LyXParagraph::size_type
1024 LyXText::NextBreakPoint(BufferView * bview, Row const * row, int width) const
1025 {
1026         LyXParagraph * par = row->par();
1027
1028         if (width < 0)
1029 #ifndef NEW_INSETS
1030                 return par->Last();
1031 #else
1032                 return par->size();
1033 #endif
1034
1035         LyXParagraph::size_type const pos = row->pos();
1036
1037
1038         // position of the last possible breakpoint 
1039         // -1 isn't a suitable value, but a flag
1040         LyXParagraph::size_type last_separator = -1;
1041         width -= RightMargin(bview->buffer(), row);
1042         
1043         LyXParagraph::size_type const main_body =
1044                 BeginningOfMainBody(bview->buffer(), par);
1045         LyXLayout const & layout =
1046                 textclasslist.Style(bview->buffer()->params.textclass, par->GetLayout());
1047         LyXParagraph::size_type i = pos;
1048
1049         if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
1050                 /* special code for right address boxes, only newlines count */
1051 #ifndef NEW_INSETS
1052                 while (i < par->Last()) {
1053 #else
1054                 while (i < par->size()) {
1055 #endif
1056                         if (par->IsNewline(i)) {
1057                                 last_separator = i;
1058 #ifndef NEW_INSETS
1059                                 i = par->Last() - 1; // this means break
1060 #else
1061                                 i = par->size() - 1; // this means break
1062 #endif
1063                                 //x = width;
1064                         } else if (par->GetChar(i) == LyXParagraph::META_INSET &&
1065                                    par->GetInset(i) && par->GetInset(i)->display()){
1066                                 par->GetInset(i)->display(false);
1067                         }
1068                         ++i;
1069                 }
1070         } else {
1071                 // Last position is an invariant
1072 #ifndef NEW_INSETS
1073                 LyXParagraph::size_type const last = 
1074                         par->Last();
1075 #else
1076                 LyXParagraph::size_type const last = 
1077                         par->size();
1078 #endif
1079                 // this is the usual handling
1080                 int x = LeftMargin(bview, row);
1081                 bool doitonetime = true;
1082                 while (doitonetime || ((x < width) && (i < last))) {
1083                         doitonetime = false;
1084                         char const c = par->GetChar(i);
1085                         if (IsNewlineChar(c)) {
1086                                 last_separator = i;
1087                                 x = width; // this means break
1088                         } else if (c == LyXParagraph::META_INSET &&
1089                                    par->GetInset(i)) {
1090                                 
1091                                 // check wether a Display() inset is
1092                                 // valid here. if not, change it to
1093                                 // non-display
1094                                 if (par->GetInset(i)->display() &&
1095                                     (layout.isCommand() ||
1096                                      (layout.labeltype == LABEL_MANUAL
1097                                       && i < BeginningOfMainBody(bview->buffer(), par)))) {
1098                                         // display istn't allowd
1099                                         par->GetInset(i)->display(false);
1100                                         x += SingleWidth(bview, par, i, c);
1101                                 } else if (par->GetInset(i)->display() ||
1102                                          par->GetInset(i)->needFullRow()) {
1103                                         // So break the line here
1104                                         if (i == pos) {
1105                                                 if (pos < last-1) {
1106                                                         last_separator = i;
1107                                                         if (IsLineSeparatorChar(par->GetChar(i+1)))
1108                                                                 ++last_separator;
1109                                                 } else
1110                                                         last_separator = last; // to avoid extra rows
1111                                         } else
1112                                                 last_separator = i - 1;
1113                                         x = width;  // this means break
1114                                 } else {
1115 #if 0
1116                                         last_separator = i;
1117                                         x += width;
1118 #else
1119                                         x += SingleWidth(bview, par, i, c);
1120 #endif
1121                                 }
1122                         } else  {
1123                                 if (IsLineSeparatorChar(c))
1124                                         last_separator = i;
1125                                 x += SingleWidth(bview, par, i, c);
1126                         }
1127                         ++i;
1128                         if (i == main_body) {
1129                                 x += lyxfont::width(layout.labelsep,
1130                                                     GetFont(bview->buffer(), par, -2));
1131                                 if (par->IsLineSeparator(i - 1))
1132                                         x-= SingleWidth(bview, par, i - 1);
1133                                 int left_margin = LabelEnd(bview, row);
1134                                 if (x < left_margin)
1135                                         x = left_margin;
1136                         }
1137                 }
1138                 // end of paragraph is always a suitable separator
1139                 if (i == last && x < width)
1140                         last_separator = i;
1141         }
1142         
1143         // well, if last_separator is still 0, the line isn't breakable. 
1144         // don't care and cut simply at the end
1145         if (last_separator < 0) {
1146                 last_separator = i;
1147         }
1148         
1149         // manual labels cannot be broken in LaTeX, do not care
1150         if (main_body && last_separator < main_body)
1151                 last_separator = main_body - 1;
1152         
1153         return last_separator;
1154 }
1155
1156
1157 // returns the minimum space a row needs on the screen in pixel
1158 int LyXText::Fill(BufferView * bview, Row * row, int paper_width) const
1159 {
1160         if (paper_width < 0)
1161                 return 0;
1162
1163         int w;
1164         // get the pure distance
1165         LyXParagraph::size_type const last = RowLastPrintable(row);
1166         
1167         // special handling of the right address boxes
1168         if (textclasslist.Style(bview->buffer()->params.textclass,
1169                                 row->par()->GetLayout()).margintype
1170             == MARGIN_RIGHT_ADDRESS_BOX) {
1171                 int const tmpfill = row->fill();
1172                 row->fill(0); // the minfill in MarginLeft()
1173                 w = LeftMargin(bview, row);
1174                 row->fill(tmpfill);
1175         } else
1176                 w = LeftMargin(bview, row);
1177         
1178         LyXLayout const & layout = textclasslist.Style(bview->buffer()->params.textclass,
1179                                                        row->par()->GetLayout());
1180         LyXParagraph::size_type const main_body = 
1181                 BeginningOfMainBody(bview->buffer(), row->par());
1182         LyXParagraph::size_type i = row->pos();
1183
1184         while (i <= last) {
1185                 if (main_body > 0 && i == main_body) {
1186                         w += lyxfont::width(layout.labelsep, GetFont(bview->buffer(), row->par(), -2));
1187                         if (row->par()->IsLineSeparator(i - 1))
1188                                 w -= SingleWidth(bview, row->par(), i - 1);
1189                         int left_margin = LabelEnd(bview, row);
1190                         if (w < left_margin)
1191                                 w = left_margin;
1192                 }
1193                 w += SingleWidth(bview, row->par(), i);
1194                 ++i;
1195         }
1196         if (main_body > 0 && main_body > last) {
1197                 w += lyxfont::width(layout.labelsep, GetFont(bview->buffer(), row->par(), -2));
1198                 if (last >= 0 && row->par()->IsLineSeparator(last))
1199                         w -= SingleWidth(bview, row->par(), last);
1200                 int const left_margin = LabelEnd(bview, row);
1201                 if (w < left_margin)
1202                         w = left_margin;
1203         }
1204         
1205         int const fill = paper_width - w - RightMargin(bview->buffer(), row);
1206         return fill;
1207 }
1208
1209
1210 // returns the minimum space a manual label needs on the screen in pixel
1211 int LyXText::LabelFill(BufferView * bview, Row const * row) const
1212 {
1213         LyXParagraph::size_type last = BeginningOfMainBody(bview->buffer(), row->par()) - 1;
1214         // -1 because a label ends either with a space that is in the label, 
1215         // or with the beginning of a footnote that is outside the label.
1216
1217         // I don't understand this code in depth, but sometimes "last" is
1218         // less than 0 and this causes a crash. This fix seems to work
1219         // correctly, but I bet the real error is elsewhere.  The bug is
1220         // triggered when you have an open footnote in a paragraph
1221         // environment with a manual label. (Asger)
1222         if (last < 0) last = 0;
1223         
1224         if (row->par()->IsLineSeparator(last)) /* a sepearator at this end 
1225                                                 does not count */
1226                 --last;
1227         
1228         int w = 0;
1229         int i = row->pos();
1230         while (i <= last) {
1231                 w += SingleWidth(bview, row->par(), i);
1232                 ++i;
1233         }
1234         
1235         int fill = 0;
1236         if (!row->par()->params.labelWidthString().empty()) {
1237                 fill = max(lyxfont::width(row->par()->params.labelWidthString(),
1238                                           GetFont(bview->buffer(), row->par(), -2)) - w,
1239                            0);
1240         }
1241         
1242         return fill;
1243 }
1244
1245
1246 // returns the number of separators in the specified row. The separator 
1247 // on the very last column doesnt count
1248 int LyXText::NumberOfSeparators(Buffer const * buf, Row const * row) const
1249 {
1250         LyXParagraph::size_type const last = RowLast(row);
1251         LyXParagraph::size_type p =
1252                 max(row->pos(), BeginningOfMainBody(buf, row->par()));
1253         int n = 0;
1254         for (; p < last; ++p) {
1255                 if (row->par()->IsSeparator(p)) {
1256                         ++n;
1257                 }
1258         }
1259         return n;
1260 }
1261
1262
1263 // returns the number of hfills in the specified row. The LyX-Hfill is
1264 // a LaTeX \hfill so that the hfills at the beginning and at the end were 
1265 // ignored. This is *MUCH* more usefull than not to ignore!
1266 int LyXText::NumberOfHfills(Buffer const * buf, Row const * row) const
1267 {
1268         LyXParagraph::size_type const last = RowLast(row);
1269         LyXParagraph::size_type first = row->pos();
1270         if (first) { /* hfill *DO* count at the beginning 
1271                       * of paragraphs! */
1272                 while(first <= last && row->par()->IsHfill(first))
1273                         ++first;
1274         }
1275
1276         first = max(first, BeginningOfMainBody(buf, row->par()));
1277         int n = 0;
1278         for (int p = first; p <= last; ++p) { // last, because the end is ignored!
1279                 if (row->par()->IsHfill(p)) {
1280                         ++n;
1281                 }
1282         }
1283         return n;
1284 }
1285
1286
1287 // like NumberOfHfills, but only those in the manual label!
1288 int LyXText::NumberOfLabelHfills(Buffer const * buf, Row const * row) const
1289 {
1290         LyXParagraph::size_type last = RowLast(row);
1291         LyXParagraph::size_type first = row->pos();
1292         if (first) { /* hfill *DO* count at the beginning 
1293                       * of paragraphs! */
1294                 while(first < last && row->par()->IsHfill(first))
1295                         ++first;
1296         }
1297
1298         last = min(last, BeginningOfMainBody(buf, row->par()));
1299         int n = 0;
1300         for (LyXParagraph::size_type p = first;
1301              p < last; ++p) {  // last, because the end is ignored!
1302                 if (row->par()->IsHfill(p)) {
1303                         ++n;
1304                 }
1305         }
1306         return n;
1307 }
1308
1309
1310 // returns true, if a expansion is needed.
1311 // Rules are given by LaTeX
1312 bool LyXText::HfillExpansion(Buffer const * buf, Row const * row_ptr,
1313                              LyXParagraph::size_type pos) const
1314 {
1315         // by the way, is it a hfill?
1316         if (!row_ptr->par()->IsHfill(pos))
1317                 return false;
1318         
1319         // at the end of a row it does not count
1320         if (pos >= RowLast(row_ptr))
1321                 return false;
1322         
1323         // at the beginning of a row it does not count, if it is not 
1324         // the first row of a paragaph
1325         if (!row_ptr->pos())
1326                 return true;
1327         
1328         // in some labels  it does not count
1329         if (textclasslist.Style(buf->params.textclass,
1330                                 row_ptr->par()->GetLayout()).margintype
1331             != MARGIN_MANUAL
1332             && pos < BeginningOfMainBody(buf, row_ptr->par()))
1333                 return false; 
1334         
1335         // if there is anything between the first char of the row and
1336         // the sepcified position that is not a newline and not a hfill,
1337         // the hfill will count, otherwise not
1338         LyXParagraph::size_type i = row_ptr->pos();
1339         while (i < pos && (row_ptr->par()->IsNewline(i)
1340                            || row_ptr->par()->IsHfill(i)))
1341                 ++i;
1342         
1343         return i != pos;
1344 }
1345
1346
1347 void LyXText::SetHeightOfRow(BufferView * bview, Row * row_ptr) const
1348 {
1349     /* get the maximum ascent and the maximum descent */
1350    int asc = 0;
1351    int desc = 0;
1352    float layoutasc = 0;
1353    float layoutdesc = 0;
1354    float tmptop = 0;
1355    LyXFont tmpfont;
1356    Inset * tmpinset = 0;
1357
1358    /* this must not happen before the currentrow for clear reasons.
1359       so the trick is just to set the current row onto this row */
1360    int unused_y;
1361    GetRow(row_ptr->par(), row_ptr->pos(), unused_y);
1362
1363    /* ok , let us initialize the maxasc and maxdesc value. 
1364     * This depends in LaTeX of the font of the last character
1365     * in the paragraph. The hack below is necessary because
1366     * of the possibility of open footnotes */
1367
1368    /* Correction: only the fontsize count. The other properties
1369       are taken from the layoutfont. Nicer on the screen :) */
1370 #ifndef NEW_INSETS   
1371    LyXParagraph * par = row_ptr->par()->LastPhysicalPar();
1372    LyXParagraph * firstpar = row_ptr->par()->FirstPhysicalPar();
1373 #else
1374    LyXParagraph * par = row_ptr->par();
1375    LyXParagraph * firstpar = row_ptr->par();
1376 #endif
1377    
1378    LyXLayout const & layout = textclasslist.Style(bview->buffer()->params.textclass,
1379                                                   firstpar->GetLayout());
1380
1381 #ifndef NEW_INSETS
1382    LyXFont font = GetFont(bview->buffer(), par, par->Last() - 1);
1383 #else
1384    LyXFont font = GetFont(bview->buffer(), par, par->size() - 1);
1385 #endif
1386    LyXFont::FONT_SIZE const size = font.size();
1387    font = GetFont(bview->buffer(), par, -1);
1388    font.setSize(size);
1389
1390    LyXFont labelfont = GetFont(bview->buffer(), par, -2);
1391
1392    float spacing_val = 1.0;
1393    if (!row_ptr->par()->params.spacing().isDefault()) {
1394            spacing_val = row_ptr->par()->params.spacing().getValue();
1395    } else {
1396            spacing_val = bview->buffer()->params.spacing.getValue();
1397    }
1398    //lyxerr << "spacing_val = " << spacing_val << endl;
1399    
1400    int maxasc = int(lyxfont::maxAscent(font) *
1401                    layout.spacing.getValue() *
1402                    spacing_val);
1403    int maxdesc = int(lyxfont::maxDescent(font) *
1404                     layout.spacing.getValue() *
1405                     spacing_val);
1406    int const pos_end = RowLast(row_ptr);
1407    int labeladdon = 0;
1408    int maxwidth = 0;
1409
1410    // Check if any insets are larger
1411    for (int pos = row_ptr->pos(); pos <= pos_end; ++pos) {
1412            if (row_ptr->par()->GetChar(pos) == LyXParagraph::META_INSET) {
1413                    tmpfont = GetFont(bview->buffer(), row_ptr->par(), pos);
1414                    tmpinset = row_ptr->par()->GetInset(pos);
1415                    if (tmpinset) {
1416                            tmpinset->update(bview, tmpfont);
1417                            asc = tmpinset->ascent(bview, tmpfont);
1418                            desc = tmpinset->descent(bview, tmpfont);
1419                            maxwidth += tmpinset->width(bview, tmpfont);
1420                            maxasc = max(maxasc, asc);
1421                            maxdesc = max(maxdesc, desc);
1422                    }
1423            } else {
1424                    maxwidth += SingleWidth(bview, row_ptr->par(), pos);
1425            }
1426    }
1427
1428    // Check if any custom fonts are larger (Asger)
1429    // This is not completely correct, but we can live with the small,
1430    // cosmetic error for now.
1431    LyXFont::FONT_SIZE const maxsize =
1432            row_ptr->par()->HighestFontInRange(row_ptr->pos(),
1433                                               pos_end);
1434    if (maxsize > font.size()) {
1435         font.setSize(maxsize);
1436
1437         asc = lyxfont::maxAscent(font);
1438         desc = lyxfont::maxDescent(font);
1439         if (asc > maxasc) 
1440                 maxasc = asc;
1441         if (desc > maxdesc)
1442                 maxdesc = desc;
1443    }
1444
1445    // This is nicer with box insets:
1446    ++maxasc;
1447    ++maxdesc;
1448
1449    row_ptr->ascent_of_text(maxasc);
1450    
1451    // is it a top line?
1452    if (!row_ptr->pos() && (row_ptr->par() == firstpar)) {
1453       
1454            // some parksips VERY EASY IMPLEMENTATION
1455       if (bview->buffer()->params.paragraph_separation ==
1456           BufferParams::PARSEP_SKIP) {
1457          if (layout.isParagraph()
1458              && firstpar->GetDepth() == 0
1459              && firstpar->previous())
1460             maxasc += bview->buffer()->params.getDefSkip().inPixels(bview);
1461          else if (firstpar->previous()
1462                   && textclasslist.Style(bview->buffer()->params.textclass,
1463                            firstpar->previous()->GetLayout()).isParagraph()
1464                   && firstpar->previous()->GetDepth() == 0)
1465            // is it right to use defskip here too? (AS)
1466            maxasc += bview->buffer()->params.getDefSkip().inPixels(bview);
1467       }
1468       
1469       // the paper margins
1470 #ifndef NEW_INSETS
1471       if (!row_ptr->par()->previous_ && bv_owner)
1472          maxasc += LYX_PAPER_MARGIN;
1473 #else
1474       if (!row_ptr->par()->previous() && bv_owner)
1475          maxasc += LYX_PAPER_MARGIN;
1476 #endif
1477       
1478       // add the vertical spaces, that the user added
1479       if (firstpar->params.spaceTop().kind() != VSpace::NONE)
1480          maxasc += int(firstpar->params.spaceTop().inPixels(bview));
1481       
1482       // do not forget the DTP-lines!
1483       // there height depends on the font of the nearest character
1484       if (firstpar->params.lineTop())
1485          maxasc += 2 * lyxfont::ascent('x', GetFont(bview->buffer(),
1486                                                     firstpar, 0));
1487       
1488       // and now the pagebreaks
1489       if (firstpar->params.pagebreakTop())
1490          maxasc += 3 * DefaultHeight();
1491       
1492       // This is special code for the chapter, since the label of this
1493       // layout is printed in an extra row
1494       if (layout.labeltype == LABEL_COUNTER_CHAPTER
1495           && bview->buffer()->params.secnumdepth >= 0) {
1496               float spacing_val = 1.0;
1497               if (!row_ptr->par()->params.spacing().isDefault()) {
1498                       spacing_val = row_ptr->par()->params.spacing().getValue();
1499               } else {
1500                       spacing_val = bview->buffer()->params.spacing.getValue();
1501               }
1502               
1503               labeladdon = int(lyxfont::maxDescent(labelfont) *
1504                                layout.spacing.getValue() *
1505                                spacing_val)
1506                       + int(lyxfont::maxAscent(labelfont) *
1507                             layout.spacing.getValue() *
1508                             spacing_val);
1509       }
1510       
1511       // special code for the top label
1512       if ((layout.labeltype == LABEL_TOP_ENVIRONMENT
1513            || layout.labeltype == LABEL_BIBLIO
1514            || layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT)
1515           && row_ptr->par()->IsFirstInSequence()
1516           && !row_ptr->par()->GetLabelstring().empty()) {
1517               float spacing_val = 1.0;
1518               if (!row_ptr->par()->params.spacing().isDefault()) {
1519                       spacing_val = row_ptr->par()->params.spacing().getValue();
1520               } else {
1521                       spacing_val = bview->buffer()->params.spacing.getValue();
1522               }
1523               
1524               labeladdon = int(
1525                       (lyxfont::maxAscent(labelfont) *
1526                        layout.spacing.getValue() *
1527                        spacing_val)
1528                       +(lyxfont::maxDescent(labelfont) *
1529                         layout.spacing.getValue() *
1530                         spacing_val)
1531                       + layout.topsep * DefaultHeight()
1532                       + layout.labelbottomsep *  DefaultHeight());
1533       }
1534    
1535       // and now the layout spaces, for example before and after a section, 
1536       // or between the items of a itemize or enumerate environment
1537       
1538       if (!firstpar->params.pagebreakTop()) {
1539          LyXParagraph * prev = row_ptr->par()->previous();
1540          if (prev)
1541             prev = row_ptr->par()->DepthHook(row_ptr->par()->GetDepth());
1542          if (prev && prev->GetLayout() == firstpar->GetLayout()
1543              && prev->GetDepth() == firstpar->GetDepth()
1544              && prev->GetLabelWidthString() == firstpar->GetLabelWidthString())
1545            {
1546               layoutasc = (layout.itemsep * DefaultHeight());
1547            }
1548          else if (row_ptr->previous()) {
1549             tmptop = layout.topsep;
1550             
1551             if (row_ptr->previous()->par()->GetDepth() >= row_ptr->par()->GetDepth())
1552                tmptop -= textclasslist.Style(bview->buffer()->params.textclass,
1553                                              row_ptr->previous()->par()->
1554                                              GetLayout()).bottomsep;
1555             
1556             if (tmptop > 0)
1557                layoutasc = (tmptop * DefaultHeight());
1558          }
1559          else if (row_ptr->par()->params.lineTop()) {
1560             tmptop = layout.topsep;
1561             
1562             if (tmptop > 0)
1563                layoutasc = (tmptop * DefaultHeight());
1564          }
1565          
1566          prev = row_ptr->par()->DepthHook(row_ptr->par()->GetDepth()-1);
1567          if (prev)  {
1568             maxasc += int(textclasslist.Style(bview->buffer()->params.textclass,
1569                                          prev->GetLayout()).parsep * DefaultHeight());
1570          }
1571          else {
1572                 if (firstpar->previous()
1573                     && firstpar->previous()->GetDepth() == 0
1574                     && firstpar->previous()->GetLayout() != firstpar->GetLayout()) {
1575                         // avoid parsep
1576                 }
1577             else if (firstpar->previous()){
1578                maxasc += int(layout.parsep * DefaultHeight());
1579             }
1580          }
1581       }
1582    }
1583    
1584    // is it a bottom line?
1585    if (
1586 #ifndef NEW_INSETS
1587            row_ptr->par()->ParFromPos(RowLast(row_ptr) + 1) == par
1588 #else
1589            row_ptr->par() == par
1590 #endif
1591        && (!row_ptr->next() || row_ptr->next()->par() != row_ptr->par())) {
1592           
1593            // the paper margins
1594 #ifndef NEW_INSETS
1595           if (!par->next_ && bv_owner)
1596             maxdesc += LYX_PAPER_MARGIN;
1597 #else
1598           if (!par->next() && bv_owner)
1599             maxdesc += LYX_PAPER_MARGIN;
1600 #endif
1601           
1602           // add the vertical spaces, that the user added
1603           if (firstpar->params.spaceBottom().kind() != VSpace::NONE)
1604                   maxdesc += int(firstpar->params.spaceBottom().inPixels(bview));
1605           
1606           // do not forget the DTP-lines!
1607           // there height depends on the font of the nearest character
1608 #ifndef NEW_INSETS
1609           if (firstpar->params.lineBottom())
1610                   maxdesc += 2 * lyxfont::ascent('x', GetFont(bview->buffer(),
1611                                                               par, par->Last() - 1));
1612 #else
1613           if (firstpar->params.lineBottom())
1614                   maxdesc += 2 * lyxfont::ascent('x',
1615                                                  GetFont(bview->buffer(),
1616                                                          par, par->size() - 1));
1617 #endif
1618           
1619           // and now the pagebreaks
1620           if (firstpar->params.pagebreakBottom())
1621             maxdesc += 3 * DefaultHeight();
1622           
1623           // and now the layout spaces, for example before and after
1624           // a section, or between the items of a itemize or enumerate
1625           // environment
1626           if (!firstpar->params.pagebreakBottom() && row_ptr->par()->next()) {
1627              LyXParagraph * nextpar = row_ptr->par()->next();
1628              LyXParagraph * comparepar = row_ptr->par();
1629              float usual = 0;
1630              float unusual = 0;
1631              
1632              if (comparepar->GetDepth() > nextpar->GetDepth()) {
1633                 usual = (textclasslist.Style(bview->buffer()->params.textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1634                 comparepar = comparepar->DepthHook(nextpar->GetDepth());
1635                 if (comparepar->GetLayout()!= nextpar->GetLayout()
1636                     || nextpar->GetLabelWidthString() != 
1637                         comparepar->GetLabelWidthString())
1638                   unusual = (textclasslist.Style(bview->buffer()->params.textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1639                 
1640                 if (unusual > usual)
1641                   layoutdesc = unusual;
1642                 else
1643                   layoutdesc = usual;
1644              }
1645              else if (comparepar->GetDepth() ==  nextpar->GetDepth()) {
1646                 
1647                 if (comparepar->GetLayout()!= nextpar->GetLayout()
1648                     || nextpar->GetLabelWidthString() != 
1649                         comparepar->GetLabelWidthString())
1650                   layoutdesc = int(textclasslist.Style(bview->buffer()->params.textclass, comparepar->GetLayout()).bottomsep * DefaultHeight());
1651              }
1652           }
1653        }
1654    
1655    // incalculate the layout spaces
1656    maxasc += int(layoutasc * 2 / (2 + firstpar->GetDepth()));
1657    maxdesc += int(layoutdesc * 2 / (2 + firstpar->GetDepth()));
1658
1659    // calculate the new height of the text
1660    height -= row_ptr->height();
1661    
1662    row_ptr->height(maxasc + maxdesc + labeladdon);
1663    row_ptr->baseline(maxasc + labeladdon);
1664    
1665    height += row_ptr->height();
1666    float x, dummy;
1667    PrepareToPrint(bview, row_ptr, x, dummy, dummy, dummy, false);
1668    row_ptr->width(int(maxwidth + x));
1669    if (inset_owner) {
1670            Row * r = firstrow;
1671            width = max(0,workWidth(bview));
1672            while(r) {
1673                    if (r->width() > width)
1674                            width = r->width();
1675                    r = r->next();
1676            }
1677    }
1678 }
1679
1680
1681 /* Appends the implicit specified paragraph behind the specified row,
1682  * start at the implicit given position */
1683 void LyXText::AppendParagraph(BufferView * bview, Row * row) const
1684 {
1685    bool not_ready = true;
1686    
1687    // The last character position of a paragraph is an invariant so we can 
1688    // safely get it here. (Asger)
1689 #ifndef NEW_INSETS
1690    int const lastposition = row->par()->Last();
1691 #else
1692    int const lastposition = row->par()->size();
1693 #endif
1694    do {
1695       // Get the next breakpoint
1696       int z = NextBreakPoint(bview, row, workWidth(bview));
1697       
1698       Row * tmprow = row;
1699
1700       // Insert the new row
1701       if (z < lastposition) {
1702          ++z;
1703          InsertRow(row, row->par(), z);
1704          row = row->next();
1705
1706          row->height(0);
1707       } else
1708          not_ready = false;
1709       
1710       // Set the dimensions of the row
1711       tmprow->fill(Fill(bview, tmprow, workWidth(bview)));
1712       SetHeightOfRow(bview, tmprow);
1713
1714    } while (not_ready);
1715 }
1716
1717
1718 void LyXText::BreakAgain(BufferView * bview, Row * row) const
1719 {
1720    bool not_ready = true;
1721    
1722    do  {
1723            // get the next breakpoint
1724         LyXParagraph::size_type z = NextBreakPoint(bview, row, workWidth(bview));
1725       Row * tmprow = row;
1726
1727 #ifndef NEW_INSETS
1728       if (z < row->par()->Last()) {
1729 #else
1730       if (z < row->par()->size()) {
1731 #endif
1732          if (!row->next() || (row->next() && row->next()->par() != row->par())) {
1733                  // insert a new row
1734             ++z;
1735             InsertRow(row, row->par(), z);
1736             row = row->next();
1737             row->height(0);
1738          } else  {
1739             row = row->next();
1740             ++z;
1741             if (row->pos() == z)
1742                     not_ready = false;     // the rest will not change
1743             else {
1744                row->pos(z);
1745             }
1746          }
1747       } else {
1748          /* if there are some rows too much, delete them */
1749          /* only if you broke the whole paragraph! */ 
1750          Row * tmprow2 = row;
1751          while (tmprow2->next() && tmprow2->next()->par() == row->par()) {
1752             tmprow2 = tmprow2->next();
1753          }
1754          while (tmprow2 != row) {
1755             tmprow2 = tmprow2->previous();
1756             RemoveRow(tmprow2->next());
1757          }
1758          not_ready = false;
1759       }
1760        
1761       /* set the dimensions of the row */ 
1762       tmprow->fill(Fill(bview, tmprow, workWidth(bview)));
1763       SetHeightOfRow(bview, tmprow);
1764    } while (not_ready);
1765 }
1766
1767
1768 // this is just a little changed version of break again
1769 void LyXText::BreakAgainOneRow(BufferView * bview, Row * row)
1770 {
1771         // get the next breakpoint
1772         LyXParagraph::size_type z = NextBreakPoint(bview, row, workWidth(bview));
1773         Row * tmprow = row;
1774
1775 #ifndef NEW_INSETS
1776         if (z < row->par()->Last()) {
1777 #else
1778         if (z < row->par()->size()) {
1779 #endif
1780                 if (!row->next()
1781                     || (row->next() && row->next()->par() != row->par())) {
1782                         /* insert a new row */ 
1783                         ++z;
1784                         InsertRow(row, row->par(), z);
1785                         row = row->next();
1786                         row->height(0);
1787                 } else  {
1788                         row= row->next();
1789                         ++z;
1790                         if (row->pos() != z)
1791                                 row->pos(z);
1792                 }
1793         } else {
1794                 // if there are some rows too much, delete them
1795                 // only if you broke the whole paragraph!
1796                 Row * tmprow2 = row;
1797                 while (tmprow2->next()
1798                        && tmprow2->next()->par() == row->par()) {
1799                         tmprow2 = tmprow2->next();
1800                 }
1801                 while (tmprow2 != row) {
1802                         tmprow2 = tmprow2->previous();
1803                         RemoveRow(tmprow2->next());
1804                 }
1805         }
1806         
1807         // set the dimensions of the row
1808         tmprow->fill(Fill(bview, tmprow, workWidth(bview)));
1809         SetHeightOfRow(bview, tmprow);
1810 }
1811
1812
1813 void LyXText::BreakParagraph(BufferView * bview, char keep_layout)
1814 {
1815    LyXLayout const & layout =
1816            textclasslist.Style(bview->buffer()->params.textclass,
1817                                cursor.par()->GetLayout());
1818
1819    // this is only allowed, if the current paragraph is not empty or caption
1820 #ifndef NEW_INSETS
1821    if ((cursor.par()->Last() <= 0
1822         && !cursor.par()->IsDummy())
1823        && layout.labeltype!= LABEL_SENSITIVE)
1824            return;
1825
1826    SetUndo(bview->buffer(), Undo::INSERT,
1827            cursor.par()->ParFromPos(cursor.pos())->previous_, 
1828            cursor.par()->ParFromPos(cursor.pos())->next_); 
1829 #else
1830    if ((cursor.par()->size() <= 0)
1831        && layout.labeltype!= LABEL_SENSITIVE)
1832            return;
1833    
1834    SetUndo(bview->buffer(), Undo::INSERT,
1835            cursor.par()->previous(), 
1836            cursor.par()->next()); 
1837 #endif
1838
1839    // Always break behind a space
1840    //
1841    // It is better to erase the space (Dekel)
1842 #ifndef NEW_INSETS
1843    if (cursor.pos() < cursor.par()->Last()
1844 #else
1845    if (cursor.pos() < cursor.par()->size()
1846 #endif
1847        && cursor.par()->IsLineSeparator(cursor.pos()))
1848            cursor.par()->Erase(cursor.pos());
1849            // cursor.pos(cursor.pos() + 1);
1850
1851    // break the paragraph
1852    if (keep_layout)
1853      keep_layout = 2;
1854    else 
1855      keep_layout = layout.isEnvironment();
1856    cursor.par()->BreakParagraph(bview->buffer()->params, cursor.pos(),
1857                                 keep_layout);
1858
1859    // well this is the caption hack since one caption is really enough
1860    if (layout.labeltype == LABEL_SENSITIVE) {
1861      if (!cursor.pos())
1862              // set to standard-layout
1863 #ifndef NEW_INSETS
1864              cursor.par()->SetLayout(bview->buffer()->params, 0);
1865 #else
1866              cursor.par()->SetLayout(0);
1867 #endif
1868      else
1869              // set to standard-layout
1870 #ifndef NEW_INSETS
1871              cursor.par()->next()->SetLayout(bview->buffer()->params, 0);
1872 #else
1873              cursor.par()->next()->SetLayout(0);
1874 #endif
1875    }
1876    
1877    /* if the cursor is at the beginning of a row without prior newline, 
1878     * move one row up! 
1879     * This touches only the screen-update. Otherwise we would may have
1880     * an empty row on the screen */
1881    if (cursor.pos() && !cursor.row()->par()->IsNewline(cursor.row()->pos() - 1)
1882        && cursor.row()->pos() == cursor.pos()) {
1883            CursorLeft(bview);
1884    } 
1885    
1886    status = LyXText::NEED_MORE_REFRESH;
1887    refresh_row = cursor.row();
1888    refresh_y = cursor.y() - cursor.row()->baseline();
1889    
1890    // Do not forget the special right address boxes
1891    if (layout.margintype == MARGIN_RIGHT_ADDRESS_BOX) {
1892       while (refresh_row->previous() &&
1893              refresh_row->previous()->par() == refresh_row->par()) {
1894               refresh_row = refresh_row->previous();
1895               refresh_y -= refresh_row->height();
1896       }
1897    }
1898    RemoveParagraph(cursor.row());
1899    
1900    // set the dimensions of the cursor row
1901    cursor.row()->fill(Fill(bview, cursor.row(), workWidth(bview)));
1902
1903    SetHeightOfRow(bview, cursor.row());
1904
1905 #ifndef NEW_INSETS
1906    while (cursor.par()->next()->Last()
1907 #else
1908    while (cursor.par()->next()->size()
1909 #endif
1910           && cursor.par()->next()->IsNewline(0))
1911            cursor.par()->next()->Erase(0);
1912    
1913    InsertParagraph(bview, cursor.par()->next(), cursor.row());
1914
1915    UpdateCounters(bview, cursor.row()->previous());
1916    
1917    /* This check is necessary. Otherwise the new empty paragraph will
1918     * be deleted automatically. And it is more friendly for the user! */ 
1919    if (cursor.pos())
1920            SetCursor(bview, cursor.par()->next(), 0);
1921    else
1922            SetCursor(bview, cursor.par(), 0);
1923    
1924    if (cursor.row()->next())
1925            BreakAgain(bview, cursor.row()->next());
1926
1927    need_break_row = 0;
1928 }
1929
1930
1931 #ifndef NEW_INSETS
1932 void LyXText::OpenFootnote(BufferView * bview)
1933 {
1934    LyXParagraph * endpar,* tmppar;
1935    Row * row;
1936    
1937    LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
1938    
1939    /* if there is no footnote in this paragraph, just return. */ 
1940    if (!par->next_
1941        || par->next_->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1942      return;
1943    
1944    /* ok, move the cursor right before the footnote */ 
1945    
1946    /* just a little faster than using CursorRight() */
1947    for (cursor.pos(0);
1948         cursor.par()->ParFromPos(cursor.pos()) != par;) {
1949            cursor.pos(cursor.pos() + 1);
1950    }
1951    
1952    /* now the cursor is at the beginning of the physical par */
1953    SetCursor(bview, cursor.par(),
1954              cursor.pos() + cursor.par()->ParFromPos(cursor.pos())->size());
1955    
1956    /* the cursor must be exactly before the footnote */ 
1957    par = cursor.par()->ParFromPos(cursor.pos());
1958    
1959    status = LyXText::NEED_MORE_REFRESH;
1960    refresh_row = cursor.row();
1961    refresh_y = cursor.y() - cursor.row()->baseline();
1962    
1963    tmppar = cursor.par();
1964    endpar = cursor.par()->next();
1965    row = cursor.row();
1966    
1967    tmppar->OpenFootnote(cursor.pos());
1968    RemoveParagraph(row);
1969    /* set the dimensions of the cursor row */
1970    row->fill(Fill(bview, row, workWidth(bview)));
1971    SetHeightOfRow(bview, row);
1972    // CHECK See comment on top of text.C
1973    tmppar = tmppar->next();
1974    
1975    while (tmppar != endpar) {
1976       if (tmppar) {
1977          InsertParagraph(bview, tmppar, row);
1978          while (row->next() && row->next()->par() == tmppar)
1979            row = row->next();
1980          tmppar = tmppar->next();
1981       }
1982    }
1983    SetCursor(bview, par->next_, 0);
1984    sel_cursor = cursor;
1985 }
1986 #endif
1987
1988
1989 // Just a macro to make some thing easier. 
1990 void LyXText::RedoParagraph(BufferView * bview) const
1991 {
1992         ClearSelection(bview);
1993         RedoParagraphs(bview, cursor, cursor.par()->next());
1994         SetCursorIntern(bview, cursor.par(), cursor.pos());
1995 }
1996
1997
1998 /* insert a character, moves all the following breaks in the 
1999  * same Paragraph one to the right and make a rebreak */
2000 void LyXText::InsertChar(BufferView * bview, char c)
2001 {
2002         SetUndo(bview->buffer(), Undo::INSERT,
2003 #ifndef NEW_INSETS
2004                 cursor.par()->ParFromPos(cursor.pos())->previous_,
2005                 cursor.par()->ParFromPos(cursor.pos())->next_
2006 #else
2007                 cursor.par()->previous(),
2008                 cursor.par()->next()
2009 #endif
2010                 );
2011
2012         // When the free-spacing option is set for the current layout,
2013         // disable the double-space checking
2014
2015         bool const freeSpacing = 
2016                 textclasslist.Style(bview->buffer()->params.textclass,
2017                                cursor.row()->par()->GetLayout()).free_spacing;
2018
2019
2020         if (lyxrc.auto_number) {
2021                 static string const number_operators = "+-/*";
2022                 static string const number_unary_operators = "+-";
2023                 static string const number_seperators = ".,:";
2024
2025                 if (current_font.number() == LyXFont::ON) {
2026                         if (!isdigit(c) && !contains(number_operators, c) &&
2027                             !(contains(number_seperators, c) &&
2028                               cursor.pos() >= 1 &&
2029                               cursor.pos() < cursor.par()->size() &&
2030                               GetFont(bview->buffer(),
2031                                       cursor.par(),
2032                                       cursor.pos()).number() == LyXFont::ON &&
2033                               GetFont(bview->buffer(),
2034                                       cursor.par(),
2035                                       cursor.pos()-1).number() == LyXFont::ON)
2036                             )
2037                                 Number(bview); // Set current_font.number to OFF
2038                 } else if (isdigit(c) &&
2039                            real_current_font.isVisibleRightToLeft()) {
2040                         Number(bview); // Set current_font.number to ON
2041
2042                         if (cursor.pos() > 0) {
2043                                 char const c = cursor.par()->GetChar(cursor.pos() - 1);
2044                                 if (contains(number_unary_operators, c) &&
2045                                     (cursor.pos() == 1 ||
2046                                      cursor.par()->IsSeparator(cursor.pos() - 2) ||
2047                                      cursor.par()->IsNewline(cursor.pos() - 2) )
2048                                    ) {
2049                                         SetCharFont(bview->buffer(),
2050                                                     cursor.par(),
2051                                                     cursor.pos() - 1,
2052                                                     current_font);
2053                                 } else if (contains(number_seperators, c) &&
2054                                            cursor.pos() >= 2 &&
2055                                            GetFont(bview->buffer(),
2056                                                    cursor.par(),
2057                                                    cursor.pos()-2).number() == LyXFont::ON) {
2058                                         SetCharFont(bview->buffer(),
2059                                                     cursor.par(),
2060                                                     cursor.pos() - 1,
2061                                                     current_font);
2062                                 }
2063                         }
2064                 }
2065         }
2066
2067
2068         /* First check, if there will be two blanks together or a blank at 
2069           the beginning of a paragraph. 
2070           I decided to handle blanks like normal characters, the main 
2071           difference are the special checks when calculating the row.fill
2072           (blank does not count at the end of a row) and the check here */ 
2073
2074         // The bug is triggered when we type in a description environment:
2075         // The current_font is not changed when we go from label to main text
2076         // and it should (along with realtmpfont) when we type the space.
2077         // CHECK There is a bug here! (Asger)
2078         
2079         LyXFont realtmpfont = real_current_font;
2080         LyXFont rawtmpfont = current_font;  /* store the current font.
2081                                      * This is because of the use
2082                                      * of cursor movements. The moving
2083                                      * cursor would refresh the 
2084                                      * current font */
2085
2086         // Get the font that is used to calculate the baselineskip
2087 #ifndef NEW_INSETS
2088         LyXParagraph::size_type const lastpos = cursor.par()->Last();
2089 #else
2090         LyXParagraph::size_type const lastpos = cursor.par()->size();
2091 #endif
2092         LyXFont rawparfont = cursor.par()->GetFontSettings(bview->buffer()->params,
2093                                                            lastpos - 1);
2094
2095         bool jumped_over_space = false;
2096    
2097         if (!freeSpacing && IsLineSeparatorChar(c)) {
2098                 if ((cursor.pos() > 0 
2099                      && cursor.par()->IsLineSeparator(cursor.pos() - 1))
2100                     || (cursor.pos() > 0
2101                         && cursor.par()->IsNewline(cursor.pos() - 1))
2102                     || (cursor.pos() == 0
2103 #ifndef NEW_INSETS
2104                         && !(cursor.par()->previous()
2105                              && cursor.par()->previous()->footnoteflag
2106                              == LyXParagraph::OPEN_FOOTNOTE)
2107 #endif
2108                             )) {
2109                         if (cursor.pos() == 0 )
2110                                 bview->owner()->getMiniBuffer()->Set(_("You cannot insert a space at the beginning of a paragraph.  Please read the Tutorial."));
2111                         else
2112                                 bview->owner()->getMiniBuffer()->Set(_("You cannot type two spaces this way.  Please read the Tutorial."));
2113                         charInserted();
2114                         return;
2115                 }
2116         } else if (IsNewlineChar(c)) {
2117 #ifndef NEW_INSETS
2118                 if (cursor.par()->FirstPhysicalPar() == cursor.par()
2119 #else
2120                 if (cursor.par() == cursor.par()
2121 #endif
2122                     && cursor.pos() <= BeginningOfMainBody(bview->buffer(), cursor.par())) {
2123                         charInserted();
2124                         return;
2125                 }
2126                 /* No newline at first position 
2127                  * of a paragraph or behind labels. 
2128                  * TeX does not allow that. */
2129
2130 #ifndef NEW_INSETS
2131                 if (cursor.pos() < cursor.par()->Last() &&
2132 #else
2133                 if (cursor.pos() < cursor.par()->size() &&
2134 #endif
2135                     cursor.par()->IsLineSeparator(cursor.pos()))
2136                         // newline always after a blank!
2137                         CursorRight(bview);
2138                 cursor.row()->fill(-1);        // to force a new break
2139         }
2140    
2141         // the display inset stuff
2142         if (cursor.row()->par()->GetChar(cursor.row()->pos()) == LyXParagraph::META_INSET
2143             && cursor.row()->par()->GetInset(cursor.row()->pos())
2144             && (cursor.row()->par()->GetInset(cursor.row()->pos())->display() ||
2145                 cursor.row()->par()->GetInset(cursor.row()->pos())->needFullRow()))
2146                 cursor.row()->fill(-1); // to force a new break  
2147
2148         // get the cursor row fist
2149         Row * row = cursor.row();
2150         int y = cursor.y() - row->baseline();
2151         if (c != LyXParagraph::META_INSET) /* Here case LyXText::InsertInset 
2152                                             * already insertet the character */
2153                 cursor.par()->InsertChar(cursor.pos(), c);
2154         SetCharFont(bview->buffer(), cursor.par(), cursor.pos(), rawtmpfont);
2155
2156         if (!jumped_over_space) {
2157                 // refresh the positions
2158                 Row * tmprow = row;
2159                 while (tmprow->next() && tmprow->next()->par() == row->par()) {
2160                         tmprow = tmprow->next();
2161                         tmprow->pos(tmprow->pos() + 1);
2162                 }
2163         }
2164    
2165         // Is there a break one row above
2166         if ((cursor.par()->IsLineSeparator(cursor.pos())
2167              || cursor.par()->IsNewline(cursor.pos())
2168              || cursor.row()->fill() == -1)
2169             && row->previous() && row->previous()->par() == row->par()) {
2170                 LyXParagraph::size_type z = NextBreakPoint(bview,
2171                                                            row->previous(),
2172                                                            workWidth(bview));
2173                 if (z >= row->pos()) {
2174                         row->pos(z + 1);
2175                         
2176                         // set the dimensions of the row above
2177                         row->previous()->fill(Fill(bview,
2178                                                    row->previous(),
2179                                                    workWidth(bview)));
2180
2181                         SetHeightOfRow(bview, row->previous());
2182              
2183                         y -= row->previous()->height();
2184                         refresh_y = y;
2185                         refresh_row = row->previous();
2186                         status = LyXText::NEED_MORE_REFRESH;
2187              
2188                         BreakAgainOneRow(bview, row);
2189
2190                         current_font = rawtmpfont;
2191                         real_current_font = realtmpfont;
2192                         SetCursor(bview, cursor.par(), cursor.pos() + 1,
2193                                   false, cursor.boundary());
2194                         // cursor MUST be in row now.
2195              
2196                         if (row->next() && row->next()->par() == row->par())
2197                                 need_break_row = row->next();
2198                         else
2199                                 need_break_row = 0;
2200              
2201                         // check, wether the last characters font has changed.
2202 #ifndef NEW_INSETS
2203                         if (cursor.pos() && cursor.pos() == cursor.par()->Last()
2204 #else
2205                         if (cursor.pos() && cursor.pos() == cursor.par()->size()
2206 #endif
2207                             && rawparfont != rawtmpfont)
2208                                 RedoHeightOfParagraph(bview, cursor);
2209                         
2210                         charInserted();
2211                         return;
2212                 }
2213         }
2214    
2215         // recalculate the fill of the row
2216         if (row->fill() >= 0)  /* needed because a newline
2217                               * will set fill to -1. Otherwise
2218                               * we would not get a rebreak! */
2219                 row->fill(Fill(bview, row, workWidth(bview)));
2220         if (row->fill() < 0) {
2221                 refresh_y = y;
2222                 refresh_row = row; 
2223                 refresh_x = cursor.x();
2224                 refresh_pos = cursor.pos();
2225                 status = LyXText::NEED_MORE_REFRESH;
2226                 BreakAgainOneRow(bview, row); 
2227                 // will the cursor be in another row now?
2228                 if (RowLast(row) <= cursor.pos() + 1 && row->next()) {
2229                         if (row->next() && row->next()->par() == row->par())
2230                                 // this should always be true
2231                                 row = row->next();
2232                         BreakAgainOneRow(bview, row);
2233                 }
2234                 current_font = rawtmpfont;
2235                 real_current_font = realtmpfont;
2236
2237                 SetCursor(bview, cursor.par(), cursor.pos() + 1, false,
2238                           cursor.boundary());
2239                 if (IsBoundary(bview->buffer(), cursor.par(), cursor.pos())
2240                     != cursor.boundary())
2241                         SetCursor(bview, cursor.par(), cursor.pos(), false,
2242                           !cursor.boundary());
2243                 if (row->next() && row->next()->par() == row->par())
2244                         need_break_row = row->next();
2245                 else
2246                         need_break_row = 0;             
2247         } else {
2248                 refresh_y = y;
2249                 refresh_x = cursor.x();
2250                 refresh_row = row;
2251                 refresh_pos = cursor.pos();
2252                 
2253                 int const tmpheight = row->height();
2254                 SetHeightOfRow(bview, row);
2255                 if (tmpheight == row->height())
2256                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
2257                 else
2258                         status = LyXText::NEED_MORE_REFRESH;
2259             
2260                 current_font = rawtmpfont;
2261                 real_current_font = realtmpfont;
2262                 SetCursor(bview, cursor.par(), cursor.pos() + 1, false,
2263                           cursor.boundary());
2264         }
2265
2266         // check, wether the last characters font has changed.
2267 #ifndef NEW_INSETS
2268         if (cursor.pos() && cursor.pos() == cursor.par()->Last()
2269 #else
2270         if (cursor.pos() && cursor.pos() == cursor.par()->size()
2271 #endif
2272             && rawparfont != rawtmpfont) {
2273                 RedoHeightOfParagraph(bview, cursor);
2274         } else {
2275                 // now the special right address boxes
2276                 if (textclasslist.Style(bview->buffer()->params.textclass,
2277                                    cursor.par()->GetLayout()).margintype
2278                     == MARGIN_RIGHT_ADDRESS_BOX) {
2279                         RedoDrawingOfParagraph(bview, cursor); 
2280                 }
2281         }
2282
2283         charInserted();
2284 }
2285    
2286
2287 void LyXText::charInserted()
2288 {
2289         // Here we could call FinishUndo for every 20 characters inserted.
2290         // This is from my experience how emacs does it.
2291         static unsigned int counter = 0;
2292         if (counter < 20) {
2293                 ++counter;
2294         } else {
2295                 FinishUndo();
2296                 counter = 0;
2297         }
2298 }
2299
2300
2301 void LyXText::PrepareToPrint(BufferView * bview,
2302                              Row * row, float & x,
2303                              float & fill_separator, 
2304                              float & fill_hfill,
2305                              float & fill_label_hfill,
2306                              bool bidi) const
2307 {
2308         float nlh, ns;
2309         
2310         float w = row->fill();
2311         fill_hfill = 0;
2312         fill_label_hfill = 0;
2313         fill_separator = 0;
2314         fill_label_hfill = 0;
2315
2316         bool const is_rtl =
2317                 row->par()->isRightToLeftPar(bview->buffer()->params);
2318         if (is_rtl) {
2319                 x = (workWidth(bview) > 0)
2320                         ? RightMargin(bview->buffer(), row) : 0;
2321 #ifndef NEW_INSETS
2322                 if (row->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
2323                         LyXFont font(LyXFont::ALL_SANE);
2324                         font.setSize(LyXFont::SIZE_SMALL);
2325                         x += lyxfont::width("Mwide-figM", font);
2326                 }
2327 #endif
2328         } else
2329                 x = (workWidth(bview) > 0) ? LeftMargin(bview, row) : 0;
2330         
2331         // is there a manual margin with a manual label
2332         if (textclasslist.Style(bview->buffer()->params.textclass,
2333                            row->par()->GetLayout()).margintype == MARGIN_MANUAL
2334             && textclasslist.Style(bview->buffer()->params.textclass,
2335                               row->par()->GetLayout()).labeltype == LABEL_MANUAL) {
2336                
2337                 /* one more since labels are left aligned */ 
2338                 nlh = NumberOfLabelHfills(bview->buffer(), row) + 1;
2339                 if (nlh && !row->par()->GetLabelWidthString().empty()) {
2340                         fill_label_hfill = LabelFill(bview, row) / nlh;
2341                 }
2342         }
2343                 
2344         // are there any hfills in the row?
2345         float const nh = NumberOfHfills(bview->buffer(), row);
2346
2347         if (nh)
2348           fill_hfill = w / nh;
2349         else  {
2350                 // is it block, flushleft or flushright? 
2351                 // set x how you need it
2352         int align;
2353 #ifndef NEW_INSETS
2354         if (row->par()->FirstPhysicalPar()->params.align() == LYX_ALIGN_LAYOUT)
2355           align = textclasslist.Style(bview->buffer()->params.textclass, row->par()->GetLayout()).align;
2356         else
2357           align = row->par()->FirstPhysicalPar()->params.align();
2358 #else
2359         if (row->par()->params.align() == LYX_ALIGN_LAYOUT)
2360           align = textclasslist.Style(bview->buffer()->params.textclass, row->par()->GetLayout()).align;
2361         else
2362           align = row->par()->params.align();
2363 #endif
2364            
2365         // center displayed insets 
2366         Inset * inset;
2367            if (row->par()->GetChar(row->pos()) == LyXParagraph::META_INSET
2368                && (inset=row->par()->GetInset(row->pos()))
2369                && (inset->display())) // || (inset->scroll() < 0)))
2370              align = (inset->LyxCode() == Inset::MATHMACRO_CODE)
2371                      ? LYX_ALIGN_BLOCK : LYX_ALIGN_CENTER;
2372
2373            switch (align) {
2374             case LYX_ALIGN_BLOCK:
2375               ns = NumberOfSeparators(bview->buffer(), row);
2376               if (ns && row->next() && row->next()->par() == row->par() &&
2377                   !(row->next()->par()->IsNewline(row->next()->pos() - 1))
2378                   && !(row->next()->par()->GetChar(row->next()->pos()) == LyXParagraph::META_INSET
2379                        && row->next()->par()->GetInset(row->next()->pos())
2380                        && row->next()->par()->GetInset(row->next()->pos())->display())
2381                   )
2382                 fill_separator = w / ns;
2383               else if (is_rtl)
2384                 x += w;
2385               break;
2386             case LYX_ALIGN_RIGHT:
2387               x += w;
2388               break;
2389             case LYX_ALIGN_CENTER:
2390               x += w / 2;
2391               break;
2392            }
2393         }
2394         if (!bidi)
2395                 return;
2396
2397         ComputeBidiTables(bview->buffer(), row);
2398         if (is_rtl) {
2399                 LyXParagraph::size_type main_body = 
2400                         BeginningOfMainBody(bview->buffer(), row->par());
2401                 LyXParagraph::size_type last = RowLast(row);
2402
2403                 if (main_body > 0 &&
2404                     (main_body-1 > last || 
2405                      !row->par()->IsLineSeparator(main_body-1))) {
2406                         LyXLayout const & layout =
2407                                 textclasslist.Style(bview->buffer()->params.textclass,
2408                                                     row->par()->GetLayout());
2409                         x += lyxfont::width(layout.labelsep,
2410                                             GetFont(bview->buffer(), row->par(), -2));
2411                         if (main_body-1 <= last)
2412                                 x += fill_label_hfill;
2413                 }
2414         }
2415 }
2416       
2417 /* important for the screen */
2418
2419
2420 /* the cursor set functions have a special mechanism. When they
2421 * realize, that you left an empty paragraph, they will delete it.
2422 * They also delete the corresponding row */
2423
2424 void LyXText::CursorRightOneWord(BufferView * bview) const
2425 {
2426         // treat floats, HFills and Insets as words
2427         LyXCursor tmpcursor = cursor;
2428         // CHECK See comment on top of text.C
2429
2430 #ifndef NEW_INSETS
2431         if (tmpcursor.pos() == tmpcursor.par()->Last()
2432 #else
2433         if (tmpcursor.pos() == tmpcursor.par()->size()
2434 #endif
2435             && tmpcursor.par()->next()) {
2436                         tmpcursor.par(tmpcursor.par()->next());
2437                         tmpcursor.pos(0);
2438         } else {
2439                 int steps = 0;
2440
2441                 // Skip through initial nonword stuff.
2442 #ifndef NEW_INSETS
2443                 while (tmpcursor.pos() < tmpcursor.par()->Last() &&
2444 #else
2445                 while (tmpcursor.pos() < tmpcursor.par()->size() &&
2446 #endif
2447                         ! tmpcursor.par()->IsWord( tmpcursor.pos() ) ) 
2448                 {
2449                   //    printf("Current pos1 %d", tmpcursor.pos()) ;
2450                         tmpcursor.pos(tmpcursor.pos() + 1);
2451                         ++steps;
2452                 }
2453                 // Advance through word.
2454 #ifndef NEW_INSETS
2455                 while (tmpcursor.pos() < tmpcursor.par()->Last() &&
2456 #else
2457                 while (tmpcursor.pos() < tmpcursor.par()->size() &&
2458 #endif
2459                         tmpcursor.par()->IsWord( tmpcursor.pos() ) )
2460                 {
2461                   //     printf("Current pos2 %d", tmpcursor.pos()) ;
2462                         tmpcursor.pos(tmpcursor.pos() + 1);
2463                         ++steps;
2464                 }
2465         }
2466         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
2467 }
2468
2469
2470 void LyXText::CursorTab(BufferView * bview) const
2471 {
2472     LyXCursor tmpcursor = cursor;
2473 #ifndef NEW_INSETS
2474     while (tmpcursor.pos() < tmpcursor.par()->Last()
2475 #else
2476     while (tmpcursor.pos() < tmpcursor.par()->size()
2477 #endif
2478            && !tmpcursor.par()->IsNewline(tmpcursor.pos()))
2479         tmpcursor.pos(tmpcursor.pos() + 1);
2480
2481 #ifndef NEW_INSETS
2482     if (tmpcursor.pos() == tmpcursor.par()->Last()){
2483 #else
2484     if (tmpcursor.pos() == tmpcursor.par()->size()){
2485 #endif
2486         if (tmpcursor.par()->next()) {
2487             tmpcursor.par(tmpcursor.par()->next());
2488             tmpcursor.pos(0);
2489         }
2490     } else
2491         tmpcursor.pos(tmpcursor.pos() + 1);
2492     SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
2493 }
2494
2495
2496 /* -------> Skip initial whitespace at end of word and move cursor to *start*
2497             of prior word, not to end of next prior word. */
2498
2499 void LyXText::CursorLeftOneWord(BufferView * bview)  const
2500 {
2501         // treat HFills, floats and Insets as words
2502         LyXCursor tmpcursor = cursor;
2503         while (tmpcursor.pos() 
2504                && (tmpcursor.par()->IsSeparator(tmpcursor.pos() - 1) 
2505                    || tmpcursor.par()->IsKomma(tmpcursor.pos() - 1))
2506                && !(tmpcursor.par()->IsHfill(tmpcursor.pos() - 1)
2507 #ifndef NEW_INSETS
2508                     || tmpcursor.par()->IsFloat(tmpcursor.pos() - 1)
2509 #endif
2510                     || tmpcursor.par()->IsInset(tmpcursor.pos() - 1)))
2511                 tmpcursor.pos(tmpcursor.pos() - 1);
2512
2513         if (tmpcursor.pos()
2514             && (tmpcursor.par()->IsInset(tmpcursor.pos() - 1)
2515 #ifndef NEW_INSETS
2516                 || tmpcursor.par()->IsFloat(tmpcursor.pos() - 1)
2517 #endif
2518                 || tmpcursor.par()->IsHfill(tmpcursor.pos() - 1))) {
2519                 tmpcursor.pos(tmpcursor.pos() - 1);
2520         } else if (!tmpcursor.pos()) {
2521                 if (tmpcursor.par()->previous()){
2522                         tmpcursor.par(tmpcursor.par()->previous());
2523 #ifndef NEW_INSETS
2524                         tmpcursor.pos(tmpcursor.par()->Last());
2525 #else
2526                         tmpcursor.pos(tmpcursor.par()->size());
2527 #endif
2528                 }
2529         } else {                // Here, tmpcursor != 0 
2530                 while (tmpcursor.pos() > 0 &&
2531                        tmpcursor.par()->IsWord(tmpcursor.pos()-1) )
2532                         tmpcursor.pos(tmpcursor.pos() - 1);
2533         }
2534         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
2535 }
2536
2537 /* -------> Select current word. This depends on behaviour of CursorLeftOneWord(), so it is
2538                         patched as well. */
2539
2540 void LyXText::SelectWord(BufferView * bview) 
2541 {
2542         // Move cursor to the beginning, when not already there.
2543         if (cursor.pos()
2544             && !cursor.par()->IsSeparator(cursor.pos()-1)
2545             && !cursor.par()->IsKomma(cursor.pos()-1) )
2546                 CursorLeftOneWord(bview);
2547
2548         // set the sel cursor
2549         sel_cursor = cursor;
2550
2551 #ifndef NEW_INSETS
2552         while (cursor.pos() < cursor.par()->Last()
2553 #else
2554         while (cursor.pos() < cursor.par()->size()
2555 #endif
2556                && !cursor.par()->IsSeparator(cursor.pos())
2557                && !cursor.par()->IsKomma(cursor.pos()) )
2558                 cursor.pos(cursor.pos() + 1);
2559         SetCursor(bview, cursor.par(), cursor.pos() );
2560         
2561         // finally set the selection
2562         SetSelection(bview);
2563 }
2564
2565
2566 /* -------> Select the word currently under the cursor when:
2567                         1: no selection is currently set,
2568                         2: the cursor is not at the borders of the word. */
2569
2570 bool LyXText::SelectWordWhenUnderCursor(BufferView * bview) 
2571 {
2572         if (!selection &&
2573 #ifndef NEW_INSETS
2574             cursor.pos() > 0 && cursor.pos() < cursor.par()->Last()
2575 #else
2576             cursor.pos() > 0 && cursor.pos() < cursor.par()->size()
2577 #endif
2578             && !cursor.par()->IsSeparator(cursor.pos())
2579             && !cursor.par()->IsKomma(cursor.pos())
2580             && !cursor.par()->IsSeparator(cursor.pos() -1)
2581             && !cursor.par()->IsKomma(cursor.pos() -1)) {
2582                 SelectWord(bview);
2583                 return true;
2584         }
2585         return false;
2586 }
2587
2588
2589 // This function is only used by the spellchecker for NextWord().
2590 // It doesn't handle LYX_ACCENTs and probably never will.
2591 string const LyXText::SelectNextWord(BufferView * bview,
2592                                      float & value) const
2593 {
2594         LyXParagraph * tmppar = cursor.par();
2595         
2596         // If this is not the very first word, skip rest of
2597         // current word because we are probably in the middle
2598         // of a word if there is text here.
2599 #ifndef NEW_INSETS
2600         if (cursor.pos() || cursor.par()->previous_) {
2601                 while (cursor.pos() < cursor.par()->Last()
2602                        && cursor.par()->IsLetter(cursor.pos()))
2603                         cursor.pos(cursor.pos() + 1);
2604         }
2605 #else
2606         if (cursor.pos() || cursor.par()->previous()) {
2607                 while (cursor.pos() < cursor.par()->size()
2608                        && cursor.par()->IsLetter(cursor.pos()))
2609                         cursor.pos(cursor.pos() + 1);
2610         }
2611 #endif
2612         
2613         // Now, skip until we have real text (will jump paragraphs)
2614 #ifndef NEW_INSETS
2615         while ((cursor.par()->Last() > cursor.pos()
2616 #else
2617         while ((cursor.par()->size() > cursor.pos()
2618 #endif
2619                 && (!cursor.par()->IsLetter(cursor.pos())
2620                     || cursor.par()->getFont(bview->buffer()->params, cursor.pos())
2621                     .latex() == LyXFont::ON))
2622 #ifndef NEW_INSETS
2623                || (cursor.par()->Last() == cursor.pos()
2624 #else
2625                || (cursor.par()->size() == cursor.pos()
2626 #endif
2627                    && cursor.par()->next())){
2628 #ifndef NEW_INSETS
2629                 if (cursor.pos() == cursor.par()->Last()) {
2630 #else
2631                 if (cursor.pos() == cursor.par()->size()) {
2632 #endif
2633                         cursor.par(cursor.par()->next());
2634                         cursor.pos(0);
2635                 } else
2636                         cursor.pos(cursor.pos() + 1);
2637         }
2638   
2639         // Update the value if we changed paragraphs
2640         if (cursor.par() != tmppar){
2641                 SetCursor(bview, cursor.par(), cursor.pos());
2642                 value = float(cursor.y())/float(height);
2643         }
2644
2645         // Start the selection from here
2646         sel_cursor = cursor;
2647
2648         std::ostringstream latex;
2649
2650         // and find the end of the word 
2651         // (optional hyphens are part of a word)
2652 #ifndef NEW_INSETS
2653         while (cursor.pos() < cursor.par()->Last()
2654 #else
2655         while (cursor.pos() < cursor.par()->size()
2656 #endif
2657                && (cursor.par()->IsLetter(cursor.pos())) 
2658                    || (cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
2659                        && cursor.par()->GetInset(cursor.pos()) != 0
2660                        && cursor.par()->GetInset(cursor.pos())->Latex(bview->buffer(), latex, false, false) == 0
2661                        && latex.str() == "\\-"
2662                            ))
2663                 cursor.pos(cursor.pos() + 1);
2664
2665         // Finally, we copy the word to a string and return it
2666         string str;
2667         if (sel_cursor.pos() < cursor.pos()) {
2668                 LyXParagraph::size_type i;
2669                 for (i = sel_cursor.pos(); i < cursor.pos(); ++i) {
2670                         if (cursor.par()->GetChar(i) != LyXParagraph::META_INSET)
2671                                 str += cursor.par()->GetChar(i);
2672                 }
2673         }
2674         return str;
2675 }
2676
2677
2678 // This one is also only for the spellchecker
2679 void LyXText::SelectSelectedWord(BufferView * bview)
2680 {
2681         // move cursor to the beginning
2682         SetCursor(bview, sel_cursor.par(), sel_cursor.pos());
2683         
2684         // set the sel cursor
2685         sel_cursor = cursor;
2686
2687         std::ostringstream latex;
2688         
2689         // now find the end of the word
2690 #ifndef NEW_INSETS
2691         while (cursor.pos() < cursor.par()->Last()
2692 #else
2693         while (cursor.pos() < cursor.par()->size()
2694 #endif
2695                && (cursor.par()->IsLetter(cursor.pos())
2696                    || (cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
2697                        && cursor.par()->GetInset(cursor.pos()) != 0
2698                        && cursor.par()->GetInset(cursor.pos())->Latex(bview->buffer(), latex, false, false) == 0
2699                        && latex.str() == "\\-"
2700                            )))
2701                 cursor.pos(cursor.pos() + 1);
2702         
2703         SetCursor(bview, cursor.par(), cursor.pos());
2704         
2705         // finally set the selection
2706         SetSelection(bview);
2707 }
2708
2709
2710 /* -------> Delete from cursor up to the end of the current or next word. */
2711 void LyXText::DeleteWordForward(BufferView * bview)
2712 {
2713 #ifndef NEW_INSETS
2714         if (!cursor.par()->Last())
2715 #else
2716         if (!cursor.par()->size())
2717 #endif
2718                 CursorRight(bview);
2719         else {
2720                 LyXCursor tmpcursor = cursor;
2721                 tmpcursor.row(0); // ??
2722                 selection = true; // to avoid deletion 
2723                 CursorRightOneWord(bview);
2724                 SetCursor(bview, tmpcursor, tmpcursor.par(), tmpcursor.pos());
2725                 sel_cursor = cursor;
2726                 cursor = tmpcursor;
2727                 SetSelection(bview); 
2728                 
2729                 /* -----> Great, CutSelection() gets rid of multiple spaces. */
2730                 CutSelection(bview);
2731         }
2732 }
2733
2734
2735 /* -------> Delete from cursor to start of current or prior word. */
2736 void LyXText::DeleteWordBackward(BufferView * bview)
2737 {
2738 #ifndef NEW_INSETS
2739        if (!cursor.par()->Last())
2740 #else
2741        if (!cursor.par()->size())
2742 #endif
2743                CursorLeft(bview);
2744        else {
2745                LyXCursor tmpcursor = cursor;
2746                tmpcursor.row(0); // ??
2747                selection = true; // to avoid deletion 
2748                CursorLeftOneWord(bview);
2749                SetCursor(bview, tmpcursor, tmpcursor.par(), tmpcursor.pos());
2750                sel_cursor = cursor;
2751                cursor = tmpcursor;
2752                SetSelection(bview);
2753                CutSelection(bview);
2754        }
2755 }
2756
2757
2758 /* -------> Kill to end of line. */
2759 void LyXText::DeleteLineForward(BufferView * bview)
2760 {
2761 #ifndef NEW_INSETS
2762         if (!cursor.par()->Last())
2763 #else
2764         if (!cursor.par()->size())
2765 #endif
2766                 // Paragraph is empty, so we just go to the right
2767                 CursorRight(bview);
2768         else {
2769                 LyXCursor tmpcursor = cursor;
2770                 // We can't store the row over a regular SetCursor
2771                 // so we set it to 0 and reset it afterwards.
2772                 tmpcursor.row(0); // ??
2773                 selection = true; // to avoid deletion 
2774                 CursorEnd(bview);
2775                 SetCursor(bview, tmpcursor, tmpcursor.par(), tmpcursor.pos());
2776                 sel_cursor = cursor;
2777                 cursor = tmpcursor;
2778                 SetSelection(bview);
2779                 // What is this test for ??? (JMarc)
2780                 if (!selection) {
2781                         DeleteWordForward(bview);
2782                 } else {
2783                         CutSelection(bview);
2784                 }
2785         }
2786 }
2787
2788
2789 // Change the case of a word at cursor position. 
2790 // This function directly manipulates LyXParagraph::text because there
2791 // is no LyXParagraph::SetChar currently. I did what I could to ensure
2792 // that it is correct. I guess part of it should be moved to
2793 // LyXParagraph, but it will have to change for 1.1 anyway. At least
2794 // it does not access outside of the allocated array as the older
2795 // version did. (JMarc) 
2796 void LyXText::ChangeWordCase(BufferView * bview, LyXText::TextCase action) 
2797 {
2798 #ifndef NEW_INSETS
2799         LyXParagraph * tmppar = cursor.par()->ParFromPos(cursor.pos());
2800
2801         SetUndo(bview->buffer(),Undo::FINISH,
2802                 tmppar->previous_, tmppar->next_); 
2803
2804         LyXParagraph::size_type tmppos = 
2805                 cursor.par()->PositionInParFromPos(cursor.pos());
2806 #else
2807         LyXParagraph * tmppar = cursor.par();
2808
2809         SetUndo(bview->buffer(),Undo::FINISH,
2810                 tmppar->previous(), tmppar->next()); 
2811
2812         LyXParagraph::size_type tmppos = cursor.pos();
2813 #endif
2814
2815         while (tmppos < tmppar->size()) {
2816                 unsigned char c = tmppar->GetChar(tmppos);
2817                 if (IsKommaChar(c) || IsLineSeparatorChar(c))
2818                         break;
2819                 if (c != LyXParagraph::META_INSET) {
2820                         switch (action) {
2821                         case text_lowercase:
2822                                 c = tolower(c);
2823                                 break;
2824                         case text_capitalization:
2825                                 c = toupper(c);
2826                                 action = text_lowercase;
2827                                 break;
2828                         case text_uppercase:
2829                                 c = toupper(c);
2830                                 break;
2831                         }
2832                 }
2833                 
2834                 //tmppar->text[tmppos] = c;
2835                 tmppar->SetChar(tmppos, c);
2836                 ++tmppos;
2837         }
2838         CheckParagraph(bview, tmppar, tmppos);
2839         CursorRightOneWord(bview);
2840 }
2841
2842
2843 void LyXText::Delete(BufferView * bview)
2844 {
2845         // this is a very easy implementation
2846
2847         LyXCursor old_cursor = cursor;
2848         int const old_cur_par_id = old_cursor.par()->id();
2849 #ifndef NEW_INSETS
2850         int const old_cur_par_prev_id = old_cursor.par()->previous_ ?
2851                 old_cursor.par()->previous_->id() : 0;
2852 #else
2853         int const old_cur_par_prev_id = old_cursor.par()->previous() ?
2854                 old_cursor.par()->previous()->id() : 0;
2855 #endif
2856         
2857         // just move to the right
2858         CursorRight(bview);
2859
2860         // CHECK Look at the comment here.
2861         // This check is not very good...
2862         // The CursorRightIntern calls DeleteEmptyParagrapgMechanism
2863         // and that can very well delete the par or par->previous in
2864         // old_cursor. Will a solution where we compare paragraph id's
2865         //work better?
2866         if (
2867 #ifndef NEW_INSETS
2868                 (cursor.par()->previous_ ? cursor.par()->previous_->id() : 0)
2869 #else
2870                 (cursor.par()->previous() ? cursor.par()->previous()->id() : 0)
2871 #endif
2872             == old_cur_par_prev_id
2873             && cursor.par()->id() != old_cur_par_id)
2874                 return; // delete-empty-paragraph-mechanism has done it
2875
2876         // if you had success make a backspace
2877         if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
2878                 LyXCursor tmpcursor = cursor;
2879                 cursor = old_cursor; // to make sure undo gets the right cursor position
2880                 SetUndo(bview->buffer(), Undo::DELETE,
2881 #ifndef NEW_INSETS
2882                         cursor.par()->ParFromPos(cursor.pos())->previous_, 
2883                         cursor.par()->ParFromPos(cursor.pos())->next_
2884 #else
2885                         cursor.par()->previous(), 
2886                         cursor.par()->next()
2887 #endif
2888                         ); 
2889                 cursor = tmpcursor;
2890                 Backspace(bview);
2891         }
2892 }
2893
2894
2895 void LyXText::Backspace(BufferView * bview)
2896 {
2897         // Get the font that is used to calculate the baselineskip
2898 #ifndef NEW_INSETS
2899         LyXParagraph::size_type lastpos = cursor.par()->Last();
2900 #else
2901         LyXParagraph::size_type lastpos = cursor.par()->size();
2902 #endif
2903         LyXFont rawparfont = cursor.par()->GetFontSettings(bview->buffer()->params,
2904                                                          lastpos - 1);
2905
2906         if (cursor.pos() == 0) {
2907                 // The cursor is at the beginning of a paragraph,
2908                 // so the the backspace will collapse two paragraphs into one.
2909                 
2910                 // we may paste some paragraphs
2911       
2912                 // is it an empty paragraph?
2913       
2914                 if ((lastpos == 0
2915                      || (lastpos == 1 && cursor.par()->IsSeparator(0)))
2916 #ifndef NEW_INSETS
2917                     && !(cursor.par()->next() 
2918                          && cursor.par()->footnoteflag == LyXParagraph::NO_FOOTNOTE
2919                          && cursor.par()->next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
2920 #endif
2921                         ) {
2922                         // This is an empty paragraph and we delete it just by moving the cursor one step
2923                         // left and let the DeleteEmptyParagraphMechanism handle the actual deletion
2924                         // of the paragraph.
2925                         
2926 #ifndef NEW_INSETS
2927                         if (cursor.par()->previous_) {
2928                                 LyXParagraph * tmppar = cursor.par()->previous_->FirstPhysicalPar();
2929                                 if (cursor.par()->GetLayout() == tmppar->GetLayout()
2930                                     && cursor.par()->footnoteflag == tmppar->footnoteflag
2931 #else
2932                         if (cursor.par()->previous()) {
2933                                 LyXParagraph * tmppar = cursor.par()->previous();
2934                                 if (cursor.par()->GetLayout() == tmppar->GetLayout()
2935 #endif
2936                                     && cursor.par()->GetAlign() == tmppar->GetAlign()) {
2937                                         // Inherit bottom DTD from the paragraph below.
2938                                         // (the one we are deleting)
2939                                         tmppar->params.lineBottom(cursor.par()->params.lineBottom());
2940                                         tmppar->params.spaceBottom(cursor.par()->params.spaceBottom());
2941                                         tmppar->params.pagebreakBottom(cursor.par()->params.pagebreakBottom());
2942                                 }
2943                                 
2944                                 CursorLeft(bview);
2945                      
2946                                 // the layout things can change the height of a row !
2947                                 int const tmpheight = cursor.row()->height();
2948                                 SetHeightOfRow(bview, cursor.row());
2949                                 if (cursor.row()->height() != tmpheight) {
2950                                         refresh_y = cursor.y() - cursor.row()->baseline();
2951                                         refresh_row = cursor.row();
2952                                         status = LyXText::NEED_MORE_REFRESH;
2953                                 }
2954                                 return;
2955                         }
2956                 }
2957
2958 #ifndef NEW_INSETS
2959                 if (cursor.par()->ParFromPos(cursor.pos())->previous_) {
2960                         SetUndo(bview->buffer(), Undo::DELETE,
2961                                 cursor.par()->ParFromPos(cursor.pos())->previous_->previous_,
2962                                 cursor.par()->ParFromPos(cursor.pos())->next_);
2963                 }
2964 #else
2965                 if (cursor.par()->previous()) {
2966                         SetUndo(bview->buffer(), Undo::DELETE,
2967                                 cursor.par()->previous()->previous(),
2968                                 cursor.par()->next());
2969                 }
2970 #endif
2971                 
2972                 LyXParagraph * tmppar = cursor.par();
2973                 Row * tmprow = cursor.row();
2974
2975                 // We used to do CursorLeftIntern() here, but it is
2976                 // not a good idea since it triggers the auto-delete
2977                 // mechanism. So we do a CursorLeftIntern()-lite,
2978                 // without the dreaded mechanism. (JMarc)
2979                 if (cursor.par()->previous()) { 
2980                         // steps into the above paragraph.
2981 #ifndef NEW_INSETS
2982                         SetCursorIntern(bview, cursor.par()->previous(),
2983                                         cursor.par()->previous()->Last(), false);
2984 #else
2985                         SetCursorIntern(bview, cursor.par()->previous(),
2986                                         cursor.par()->previous()->size(),
2987                                         false);
2988 #endif
2989                 }
2990
2991                 /* Pasting is not allowed, if the paragraphs have different
2992                    layout. I think it is a real bug of all other
2993                    word processors to allow it. It confuses the user.
2994                    Even so with a footnote paragraph and a non-footnote
2995                    paragraph. I will not allow pasting in this case, 
2996                    because the user would be confused if the footnote behaves 
2997                    different wether it is open or closed.
2998                   
2999                    Correction: Pasting is always allowed with standard-layout
3000                 */
3001                 if (cursor.par() != tmppar
3002                     && (cursor.par()->GetLayout() == tmppar->GetLayout()
3003                         || tmppar->GetLayout() == 0 /*standard*/)
3004 #ifndef NEW_INSETS
3005                     && cursor.par()->footnoteflag == tmppar->footnoteflag
3006 #endif
3007                     && cursor.par()->GetAlign() == tmppar->GetAlign()) {
3008
3009                         RemoveParagraph(tmprow);
3010                         RemoveRow(tmprow);
3011                         cursor.par()->PasteParagraph(bview->buffer()->params);
3012                         
3013                         if (!cursor.pos() || !cursor.par()->IsSeparator(cursor.pos() - 1))
3014                                 ; //cursor.par()->InsertChar(cursor.pos(), ' ');
3015                         // strangely enough it seems that commenting out the line above removes
3016                         // most or all of the segfaults. I will however also try to move the
3017                         // two Remove... lines in front of the PasteParagraph too.
3018                         else
3019                                 if (cursor.pos())
3020                                         cursor.pos(cursor.pos() - 1);
3021                         
3022                         status = LyXText::NEED_MORE_REFRESH;
3023                         refresh_row = cursor.row();
3024                         refresh_y = cursor.y() - cursor.row()->baseline();
3025                         
3026                         // remove the lost paragraph
3027                         // This one is not safe, since the paragraph that the tmprow and the
3028                         // following rows belong to has been deleted by the PasteParagraph
3029                         // above. The question is... could this be moved in front of the
3030                         // PasteParagraph?
3031                         //RemoveParagraph(tmprow);
3032                         //RemoveRow(tmprow);  
3033                         
3034                         // This rebuilds the rows.
3035                         AppendParagraph(bview, cursor.row());
3036                         UpdateCounters(bview, cursor.row());
3037                         
3038                         // the row may have changed, block, hfills etc.
3039                         SetCursor(bview, cursor.par(), cursor.pos(), false);
3040                 }
3041         } else {
3042                 /* this is the code for a normal backspace, not pasting
3043                  * any paragraphs */ 
3044                 SetUndo(bview->buffer(), Undo::DELETE,
3045 #ifndef NEW_INSETS
3046                         cursor.par()->ParFromPos(cursor.pos())->previous_,
3047                         cursor.par()->ParFromPos(cursor.pos())->next_
3048 #else
3049                         cursor.par()->previous(),
3050                         cursor.par()->next()
3051 #endif
3052                         ); 
3053                 // We used to do CursorLeftIntern() here, but it is
3054                 // not a good idea since it triggers the auto-delete
3055                 // mechanism. So we do a CursorLeftIntern()-lite,
3056                 // without the dreaded mechanism. (JMarc)
3057                 SetCursorIntern(bview, cursor.par(), cursor.pos()- 1,
3058                                 false, cursor.boundary());
3059                 
3060                 // some insets are undeletable here
3061                 if (cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET) {
3062                         if (!cursor.par()->GetInset(cursor.pos())->Deletable())
3063                                 return; 
3064                         // force complete redo when erasing display insets
3065                         // this is a cruel method but safe..... Matthias 
3066                         if (cursor.par()->GetInset(cursor.pos())->display() ||
3067                             cursor.par()->GetInset(cursor.pos())->needFullRow()) {
3068                                 cursor.par()->Erase(cursor.pos());
3069                                 RedoParagraph(bview);
3070                                 return;
3071                         }
3072                 }
3073                 
3074                 Row * row = cursor.row();
3075                 int y = cursor.y() - row->baseline();
3076                 LyXParagraph::size_type z;
3077                 /* remember that a space at the end of a row doesnt count
3078                  * when calculating the fill */ 
3079                 if (cursor.pos() < RowLast(row) ||
3080                     !cursor.par()->IsLineSeparator(cursor.pos())) {
3081                         row->fill(row->fill() + SingleWidth(bview,
3082                                                             cursor.par(),
3083                                                             cursor.pos()));
3084                 }
3085                 
3086                 /* some special code when deleting a newline. This is similar
3087                  * to the behavior when pasting paragraphs */ 
3088                 if (cursor.pos() && cursor.par()->IsNewline(cursor.pos())) {
3089                         cursor.par()->Erase(cursor.pos());
3090                         // refresh the positions
3091                         Row * tmprow = row;
3092                         while (tmprow->next() && tmprow->next()->par() == row->par()) {
3093                                 tmprow = tmprow->next();
3094                                 tmprow->pos(tmprow->pos() - 1);
3095                         }
3096                         if (cursor.par()->IsLineSeparator(cursor.pos() - 1))
3097                                 cursor.pos(cursor.pos() - 1);
3098
3099 #ifndef NEW_INSETS
3100                         if (cursor.pos() < cursor.par()->Last()
3101                             && !cursor.par()->IsSeparator(cursor.pos())) {
3102 #else
3103                         if (cursor.pos() < cursor.par()->size()
3104                             && !cursor.par()->IsSeparator(cursor.pos())) {
3105 #endif
3106                                 cursor.par()->InsertChar(cursor.pos(), ' ');
3107                                 SetCharFont(bview->buffer(), cursor.par(), 
3108                                             cursor.pos(), current_font);
3109                                 // refresh the positions
3110                                 tmprow = row;
3111                                 while (tmprow->next() && tmprow->next()->par() == row->par()) {
3112                                         tmprow = tmprow->next();
3113                                         tmprow->pos(tmprow->pos() + 1);
3114                                 }
3115                         }
3116                 } else {
3117                         cursor.par()->Erase(cursor.pos());
3118                         
3119                         // refresh the positions
3120                         Row * tmprow = row;
3121                         while (tmprow->next()
3122                                && tmprow->next()->par() == row->par()) {
3123                                 tmprow = tmprow->next();
3124                                 tmprow->pos(tmprow->pos() - 1);
3125                         }
3126
3127                         // delete newlines at the beginning of paragraphs
3128 #ifndef NEW_INSETS
3129                         while (cursor.par()->Last() &&
3130 #else
3131                         while (cursor.par()->size() &&
3132 #endif
3133                                cursor.par()->IsNewline(cursor.pos()) &&
3134                                cursor.pos() == BeginningOfMainBody(bview->buffer(),
3135                                                                    cursor.par())) {
3136                                 cursor.par()->Erase(cursor.pos());
3137                                 // refresh the positions
3138                                 tmprow = row;
3139                                 while (tmprow->next() && 
3140                                        tmprow->next()->par() == row->par()) {
3141                                         tmprow = tmprow->next();
3142                                         tmprow->pos(tmprow->pos() - 1);
3143                                 }
3144                         }
3145                 }
3146                 
3147                 // is there a break one row above
3148                 if (row->previous() && row->previous()->par() == row->par()) {
3149                         z = NextBreakPoint(bview, row->previous(),
3150                                            workWidth(bview));
3151                         if (z >= row->pos()) {
3152                                 row->pos(z + 1);
3153                                 
3154                                 Row * tmprow = row->previous();
3155                                 
3156                                 // maybe the current row is now empty
3157 #ifndef NEW_INSETS
3158                                 if (row->pos() >= row->par()->Last()) {
3159 #else
3160                                 if (row->pos() >= row->par()->size()) {
3161 #endif
3162                                         // remove it
3163                                         RemoveRow(row);
3164                                         need_break_row = 0;
3165                                 } else {
3166                                         BreakAgainOneRow(bview, row);
3167                                         if (row->next() && row->next()->par() == row->par())
3168                                                 need_break_row = row->next();
3169                                         else
3170                                                 need_break_row = 0;
3171                                 }
3172                                 
3173                                 // set the dimensions of the row above
3174                                 y -= tmprow->height();
3175                                 tmprow->fill(Fill(bview, tmprow,
3176                                                   workWidth(bview)));
3177                                 SetHeightOfRow(bview, tmprow);
3178                                 
3179                                 refresh_y = y;
3180                                 refresh_row = tmprow;
3181                                 status = LyXText::NEED_MORE_REFRESH;
3182                                 SetCursor(bview, cursor.par(), cursor.pos(),
3183                                           false, cursor.boundary());
3184                                 //current_font = rawtmpfont;
3185                                 //real_current_font = realtmpfont;
3186                                 // check, whether the last character's font has changed.
3187 #ifndef NEW_INSETS
3188                                 if (rawparfont !=
3189                                     cursor.par()->GetFontSettings(bview->buffer()->params,
3190                                                                   cursor.par()->Last() - 1))
3191 #else
3192                                 if (rawparfont !=
3193                                     cursor.par()->GetFontSettings(bview->buffer()->params,
3194                                                                   cursor.par()->size() - 1))
3195 #endif
3196                                         RedoHeightOfParagraph(bview, cursor);
3197                                 return;
3198                         }
3199                 }
3200                 
3201                 // break the cursor row again
3202                 if (row->next() && row->next()->par() == row->par() &&
3203 #ifndef NEW_INSETS
3204                     (RowLast(row) == row->par()->Last() - 1 ||
3205 #else
3206                     (RowLast(row) == row->par()->size() - 1 ||
3207 #endif
3208                      NextBreakPoint(bview, row, workWidth(bview)) != RowLast(row))) {
3209                         
3210                         /* it can happen that a paragraph loses one row
3211                          * without a real breakup. This is when a word
3212                          * is to long to be broken. Well, I don t care this 
3213                          * hack ;-) */
3214 #ifndef NEW_INSETS
3215                         if (RowLast(row) == row->par()->Last() - 1)
3216 #else
3217                         if (RowLast(row) == row->par()->size() - 1)
3218 #endif
3219                                 RemoveRow(row->next());
3220                         
3221                         refresh_y = y;
3222                         refresh_row = row;
3223                         status = LyXText::NEED_MORE_REFRESH;
3224                         
3225                         BreakAgainOneRow(bview, row);
3226                         // will the cursor be in another row now?
3227                         if (row->next() && row->next()->par() == row->par() &&
3228                             RowLast(row) <= cursor.pos()) {
3229                                 row = row->next();
3230                                 BreakAgainOneRow(bview, row);
3231                         }
3232
3233                         SetCursor(bview, cursor.par(), cursor.pos(), false, cursor.boundary());
3234
3235                         if (row->next() && row->next()->par() == row->par())
3236                                 need_break_row = row->next();
3237                         else
3238                                 need_break_row = 0;
3239                 } else  {
3240                         // set the dimensions of the row
3241                         row->fill(Fill(bview, row, workWidth(bview)));
3242                         int const tmpheight = row->height();
3243                         SetHeightOfRow(bview, row);
3244                         if (tmpheight == row->height())
3245                                 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3246                         else
3247                                 status = LyXText::NEED_MORE_REFRESH;
3248                         refresh_y = y;
3249                         refresh_row = row;
3250                         SetCursor(bview, cursor.par(), cursor.pos(), false, cursor.boundary());
3251                 }
3252         }
3253
3254         // current_font = rawtmpfont;
3255         // real_current_font = realtmpfont;
3256
3257         if (IsBoundary(bview->buffer(), cursor.par(), cursor.pos())
3258             != cursor.boundary())
3259                 SetCursor(bview, cursor.par(), cursor.pos(), false,
3260                           !cursor.boundary());
3261
3262 #ifndef NEW_INSETS
3263         lastpos = cursor.par()->Last();
3264 #else
3265         lastpos = cursor.par()->size();
3266 #endif
3267         if (cursor.pos() == lastpos)
3268                 SetCurrentFont(bview);
3269         
3270         // check, whether the last characters font has changed.
3271         if (rawparfont != 
3272             cursor.par()->GetFontSettings(bview->buffer()->params, lastpos - 1)) {
3273                 RedoHeightOfParagraph(bview, cursor);
3274         } else {
3275                 // now the special right address boxes
3276                 if (textclasslist.Style(bview->buffer()->params.textclass,
3277                                         cursor.par()->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
3278                         RedoDrawingOfParagraph(bview, cursor); 
3279                 }
3280         }
3281 }
3282
3283
3284 void LyXText::GetVisibleRow(BufferView * bview, int y_offset, int x_offset,
3285                             Row * row_ptr, int y, bool cleared)
3286 {
3287         // returns a printed row
3288         Painter & pain = bview->painter();
3289         
3290         bool const is_rtl =
3291                 row_ptr->par()->isRightToLeftPar(bview->buffer()->params);
3292         
3293         LyXParagraph::size_type const last = RowLastPrintable(row_ptr);
3294
3295         LyXParagraph::size_type vpos;
3296         LyXParagraph::size_type pos;
3297
3298         float tmpx;
3299
3300         LyXFont font(LyXFont::ALL_SANE);
3301         int maxdesc;
3302         if (row_ptr->height() <= 0) {
3303                 lyxerr << "LYX_ERROR: row.height: "
3304                        << row_ptr->height() << endl;
3305                 return;
3306         }
3307
3308         float x;
3309         float fill_separator;
3310         float fill_hfill;
3311         float fill_label_hfill;
3312         PrepareToPrint(bview, row_ptr, x, fill_separator,
3313                        fill_hfill, fill_label_hfill);
3314         
3315         if (inset_owner && (x < 0))
3316                 x = 0;
3317         x += x_offset;
3318         
3319         // clear the area where we want to paint/print
3320         int const ww = bview->workWidth();
3321
3322         bool clear_area = true;
3323         Inset * inset = 0;
3324
3325         if (!bview->screen()->forceClear() && last == row_ptr->pos()
3326             && row_ptr->par()->GetChar(row_ptr->pos()) == LyXParagraph::META_INSET
3327             && (inset = row_ptr->par()->GetInset(row_ptr->pos()))) {
3328                 clear_area = inset->doClearArea();
3329         }
3330         // we don't need to clear it's already done!!!
3331         if (cleared) {
3332                 clear_area = true;
3333         } else if (clear_area) {
3334 #ifdef WITH_WARNINGS
3335 #warning Should be fixed with a lyxinset::clear_width(bv, font) function! (Jug)
3336 #warning Should we not fix this in the Painter, please have a look Lars! (Jug)
3337 #endif
3338                 int const y = y_offset < 0 ? 0 : y_offset;
3339                 int const h = y_offset < 0 ?
3340                         row_ptr->height() + y_offset : row_ptr->height();
3341                 int const w = inset_owner ?
3342                         inset_owner->width(bview, font) - 2 : ww;
3343                 int const x = x_offset;
3344                 pain.fillRectangle(x, y, w, h);
3345         } else if (inset != 0) {
3346                 int h = row_ptr->baseline() - inset->ascent(bview, font);
3347                 if (h > 0) {
3348                         int const w = (inset_owner ?
3349                                  inset_owner->width(bview, font) : ww);
3350                         pain.fillRectangle(x_offset, y_offset, w, h);
3351                 }
3352                 h += inset->ascent(bview, font) + inset->descent(bview, font);
3353                 if ((row_ptr->height() - h) > 0) {
3354                         int const w = (inset_owner ?
3355                                  inset_owner->width(bview, font) : ww);
3356                         pain.fillRectangle(x_offset, y_offset + h,
3357                                            w, row_ptr->height() - h);
3358                 }
3359                 if (!inset_owner && !inset->display() && !inset->needFullRow())
3360                 {
3361                         int const w = inset->width(bview, font) + int(x);
3362                         pain.fillRectangle(w, y_offset, ww - w, row_ptr->height());
3363                 }
3364         }
3365         
3366         if (selection) {
3367                 int const w = (inset_owner ?
3368                                inset_owner->width(bview, font) : ww);
3369                 // selection code
3370                 if (bidi_same_direction) {
3371                         if (sel_start_cursor.row() == row_ptr &&
3372                             sel_end_cursor.row() == row_ptr) {
3373                                 if (sel_start_cursor.x() < sel_end_cursor.x())
3374                                         pain.fillRectangle(x_offset + sel_start_cursor.x(),
3375                                                            y_offset,
3376                                                            sel_end_cursor.x() - sel_start_cursor.x(),
3377                                                            row_ptr->height(),
3378                                                            LColor::selection);
3379                                 else
3380                                         pain.fillRectangle(x_offset + sel_end_cursor.x(),
3381                                                            y_offset,
3382                                                            sel_start_cursor.x() - sel_end_cursor.x(),
3383                                                            row_ptr->height(),
3384                                                            LColor::selection);
3385                         } else if (sel_start_cursor.row() == row_ptr) {
3386                                 if (is_rtl)
3387                                         pain.fillRectangle(x_offset, y_offset,
3388                                                            sel_start_cursor.x(),
3389                                                            row_ptr->height(),
3390                                                            LColor::selection);
3391                                 else
3392                                         pain.fillRectangle(x_offset + sel_start_cursor.x(),
3393                                                            y_offset,
3394                                                            w - sel_start_cursor.x(),
3395                                                            row_ptr->height(),
3396                                                            LColor::selection);
3397                         } else if (sel_end_cursor.row() == row_ptr) {
3398                                 if (is_rtl)
3399                                         pain.fillRectangle(x_offset + sel_end_cursor.x(),
3400                                                            y_offset,
3401                                                            w - sel_end_cursor.x(),
3402                                                            row_ptr->height(),
3403                                                            LColor::selection);
3404                                 else
3405                                         pain.fillRectangle(x_offset, y_offset,
3406                                                            sel_end_cursor.x(),
3407                                                            row_ptr->height(),
3408                                                            LColor::selection);
3409                         } else if (y > sel_start_cursor.y()
3410                                    && y < sel_end_cursor.y()) {
3411                                 pain.fillRectangle(x_offset, y_offset, w,
3412                                                    row_ptr->height(),
3413                                                    LColor::selection);
3414                         }
3415                 } else if (sel_start_cursor.row() != row_ptr &&
3416                             sel_end_cursor.row() != row_ptr &&
3417                             y > sel_start_cursor.y()
3418                             && y < sel_end_cursor.y()) {
3419                         pain.fillRectangle(x_offset, y_offset, w,
3420                                            row_ptr->height(),
3421                                            LColor::selection);
3422                 } else if (sel_start_cursor.row() == row_ptr ||
3423                            sel_end_cursor.row() == row_ptr) {
3424                         float tmpx = x;
3425                         if ((sel_start_cursor.row() != row_ptr && !is_rtl) ||
3426                              (sel_end_cursor.row() != row_ptr && is_rtl))
3427                                 pain.fillRectangle(x_offset, y_offset,
3428                                                    int(tmpx),
3429                                                    row_ptr->height(),
3430                                                    LColor::selection);
3431                         LyXParagraph::size_type main_body =
3432                                 BeginningOfMainBody(bview->buffer(),
3433                                                     row_ptr->par());
3434                         
3435                         for (vpos = row_ptr->pos(); vpos <= last; ++vpos)  {
3436                                 pos = vis2log(vpos);
3437                                 float const old_tmpx = tmpx;
3438                                 if (main_body > 0 && pos == main_body-1) {
3439                                         tmpx += fill_label_hfill +
3440                                                 lyxfont::width(textclasslist.Style(bview->buffer()->params.textclass,
3441                                                                                    row_ptr->par()->GetLayout()).labelsep,
3442                                                                GetFont(bview->buffer(),row_ptr->par(), -2));
3443                                         if (row_ptr->par()->IsLineSeparator(main_body-1))
3444                                                 tmpx -= SingleWidth(bview, row_ptr->par(), main_body-1);
3445                                 }
3446                                 if (HfillExpansion(bview->buffer(), row_ptr, pos)) {
3447                                         tmpx += SingleWidth(bview, row_ptr->par(), pos);
3448                                         if (pos >= main_body)
3449                                                 tmpx += fill_hfill;
3450                                         else 
3451                                                 tmpx += fill_label_hfill;
3452                                 }
3453                                 else if (row_ptr->par()->IsSeparator(pos)) {
3454                                         tmpx += SingleWidth(bview, row_ptr->par(), pos);
3455                                         if (pos >= main_body)
3456                                                 tmpx += fill_separator;
3457                                 } else
3458                                         tmpx += SingleWidth(bview, row_ptr->par(), pos);
3459                                 
3460                                 if ((sel_start_cursor.row() != row_ptr ||
3461                                       sel_start_cursor.pos() <= pos) &&
3462                                      (sel_end_cursor.row() != row_ptr ||
3463                                       pos < sel_end_cursor.pos()) )
3464                                         // Here we do not use x_offset as x_offset was
3465                                         // added to x.
3466                                         pain.fillRectangle(int(old_tmpx),
3467                                                            y_offset,
3468                                                            int(tmpx - old_tmpx + 1),
3469                                                            row_ptr->height(),
3470                                                            LColor::selection);
3471                         }
3472
3473                         if ((sel_start_cursor.row() != row_ptr && is_rtl) ||
3474                              (sel_end_cursor.row() != row_ptr && !is_rtl) )
3475                                 pain.fillRectangle(x_offset + int(tmpx),
3476                                                    y_offset,
3477                                                    int(ww - tmpx),
3478                                                    row_ptr->height(),
3479                                                    LColor::selection);
3480                 }
3481         }
3482
3483         int box_x = 0;
3484 #ifndef NEW_INSETS
3485         if (row_ptr->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3486                 LyXFont font(LyXFont::ALL_SANE);
3487                 font.setSize(LyXFont::SIZE_FOOTNOTE);
3488                 font.setColor(LColor::footnote);
3489                 
3490                 box_x = LYX_PAPER_MARGIN + lyxfont::width(" wide-tab ", font);
3491                 if (row_ptr->previous() &&
3492                     row_ptr->previous()->par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
3493                         string fs;
3494                         switch (row_ptr->par()->footnotekind) {
3495                         case LyXParagraph::MARGIN:
3496                                 fs = " margin";
3497                                 break;
3498                         case LyXParagraph::FIG:
3499                                 fs = " fig";
3500                                 break;
3501                         case LyXParagraph::TAB:
3502                                 fs = " tab";
3503                                 break;
3504                         case LyXParagraph::WIDE_FIG:
3505                                 fs = " wide-fig";
3506                                 break;
3507                         case LyXParagraph::WIDE_TAB:
3508                                 fs = " wide-tab";
3509                                 break;
3510                         case LyXParagraph::ALGORITHM:
3511                                 fs = " alg";
3512                                 break;
3513                         case LyXParagraph::FOOTNOTE:
3514                                 fs = " foot";
3515                                 break;
3516                         }
3517                         
3518                         pain.fillRectangle(LYX_PAPER_MARGIN,
3519                                            y_offset + 1,
3520                                            box_x - LYX_PAPER_MARGIN,
3521                                            int(lyxfont::maxAscent(font)
3522                                                + lyxfont::maxDescent(font)),
3523                                            LColor::footnotebg);
3524                         
3525                         pain.line(LYX_PAPER_MARGIN, y_offset,
3526                                   workWidth(bview) - LYX_PAPER_MARGIN, y_offset,
3527                                   LColor::footnoteframe);
3528                         
3529                         pain.text(LYX_PAPER_MARGIN,
3530                                   y_offset + int(lyxfont::maxAscent(font)) + 1,
3531                                   fs, font);
3532                         
3533                         pain.line(LYX_PAPER_MARGIN, y_offset,
3534                                   LYX_PAPER_MARGIN,
3535                                   y_offset + int(lyxfont::maxAscent(font)
3536                                                + lyxfont::maxDescent(font)),
3537                                   LColor::footnoteframe);
3538                         
3539                         pain.line(LYX_PAPER_MARGIN,
3540                                   y_offset + int(lyxfont::maxAscent(font)
3541                                                + lyxfont::maxDescent(font)) + 1,
3542                                   box_x,
3543                                   y_offset + int(lyxfont::maxAscent(font)
3544                                                + lyxfont::maxDescent(font)) + 1,
3545                                   LColor::footnoteframe);
3546                         
3547                 }
3548                 
3549                 /* draw the open floats in a red box */
3550                 pain.line(box_x, y_offset,
3551                           box_x, y_offset + row_ptr->height(),
3552                           LColor::footnoteframe);
3553                 
3554                 pain.line(workWidth(bview) - LYX_PAPER_MARGIN,
3555                           y_offset,
3556                           workWidth(bview) - LYX_PAPER_MARGIN,
3557                           y_offset + row_ptr->height(),
3558                           LColor::footnoteframe);
3559
3560
3561                 // Draw appendix lines
3562                 LyXParagraph * p = row_ptr->par()->PreviousBeforeFootnote()->FirstPhysicalPar();
3563                 if (p->params.appendix()) {
3564                         pain.line(1, y_offset,
3565                                   1, y_offset + row_ptr->height(),
3566                                   LColor::appendixline);
3567                         pain.line(workWidth(bview) - 2, y_offset,
3568                                   workWidth(bview) - 2,
3569                                   y_offset + row_ptr->height(),
3570                                   LColor::appendixline);
3571                 }
3572
3573 #ifndef NO_PEXTRA
3574                 // Draw minipage line
3575                 bool const minipage =
3576                         (p->params.pextraType() == LyXParagraph::PEXTRA_MINIPAGE);
3577                 if (minipage)
3578                         pain.line(LYX_PAPER_MARGIN/5, y_offset,
3579                                   LYX_PAPER_MARGIN/5, 
3580                                   y_offset + row_ptr->height() - 1,
3581                                   LColor::minipageline);
3582 #endif
3583                 // Draw depth lines
3584                 int const depth = p->GetDepth();
3585                 for (int i = 1; i <= depth; ++i) {
3586                         int const line_x = (LYX_PAPER_MARGIN / 5) *
3587                                 (i + minipage);
3588                         pain.line(line_x, y_offset, line_x,
3589                                   y_offset + row_ptr->height() - 1,
3590                                   LColor::depthbar);
3591                 }
3592         } else if (row_ptr->previous() &&
3593                    row_ptr->previous()->par()->footnoteflag
3594                    == LyXParagraph::OPEN_FOOTNOTE) {
3595                 LyXFont font(LyXFont::ALL_SANE);
3596                 font.setSize(LyXFont::SIZE_FOOTNOTE);
3597                 
3598                 int const box_x = LYX_PAPER_MARGIN
3599                         + lyxfont::width(" wide-tab ", font);
3600                 
3601                 pain.line(box_x, y_offset,
3602                           workWidth(bview) - LYX_PAPER_MARGIN,
3603                           y_offset, LColor::footnote);
3604         }
3605 #endif
3606         // Draw appendix lines
3607 #ifndef NEW_INSETS
3608         LyXParagraph * firstpar = row_ptr->par()->FirstPhysicalPar();
3609 #else
3610         LyXParagraph * firstpar = row_ptr->par();
3611 #endif
3612         if (firstpar->params.appendix()) {
3613                 pain.line(1, y_offset,
3614                           1, y_offset + row_ptr->height(),
3615                           LColor::appendixline);
3616                 pain.line(ww - 2, y_offset,
3617                           ww - 2, y_offset + row_ptr->height(),
3618                           LColor::appendixline);
3619         }
3620 #ifndef NO_PEXTRA
3621         // Draw minipage line
3622         bool const minipage =
3623                 (firstpar->params.pextraType() == LyXParagraph::PEXTRA_MINIPAGE);
3624         if (minipage)
3625                 pain.line(LYX_PAPER_MARGIN/5 + box_x, y_offset,
3626                           LYX_PAPER_MARGIN/5 + box_x, 
3627                           y_offset + row_ptr->height() - 1,
3628                           LColor::minipageline);
3629 #endif
3630         // Draw depth lines
3631         int const depth = firstpar->GetDepth();
3632         if (depth > 0) {
3633                 int next_depth = 0;
3634                 int prev_depth = 0;
3635                 if (row_ptr->next())
3636 #ifndef NEW_INSETS
3637                         if (row_ptr->par()->footnoteflag ==
3638                             row_ptr->next()->par()->footnoteflag)
3639                                 next_depth = row_ptr->next()->par()->GetDepth();
3640                         else if (row_ptr->par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
3641                                 next_depth = depth;
3642 #else
3643                                 next_depth = row_ptr->next()->par()->GetDepth();
3644 #endif
3645                 if (row_ptr->previous())
3646 #ifndef NEW_INSETS
3647                         if (row_ptr->par()->footnoteflag ==
3648                             row_ptr->previous()->par()->footnoteflag)
3649                                 prev_depth = row_ptr->previous()->par()->GetDepth();
3650                         else if (row_ptr->par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
3651                                 prev_depth = depth;
3652 #else
3653                                 prev_depth = row_ptr->previous()->par()->GetDepth();
3654 #endif
3655
3656                 for (int i = 1; i <= depth; ++i) {
3657                         int const line_x = (LYX_PAPER_MARGIN / 5) *
3658                                 (i
3659 #ifndef NO_PEXTRA
3660                                  + minipage
3661 #endif
3662                                         ) + box_x + x_offset;
3663                         pain.line(line_x, y_offset, line_x,
3664                                   y_offset + row_ptr->height() - 1 - (i - next_depth - 1) * 3,
3665                                   LColor::depthbar);
3666                 
3667                         if (i > prev_depth)
3668                                 pain.fillRectangle(line_x, y_offset, LYX_PAPER_MARGIN / 5, 2,
3669                                                    LColor::depthbar);
3670                         if (i > next_depth)
3671                                 pain.fillRectangle(line_x,
3672                                                    y_offset + row_ptr->height() - 2 - (i - next_depth - 1) * 3,
3673                                                    LYX_PAPER_MARGIN / 5, 2,
3674                                                    LColor::depthbar);
3675                 }
3676         }
3677
3678         
3679         LyXLayout const & layout =
3680                 textclasslist.Style(bview->buffer()->params.textclass,
3681                                     row_ptr->par()->GetLayout());
3682
3683         int y_top = 0;
3684         int y_bottom = row_ptr->height();
3685         
3686         // is it a first row?
3687         if (!row_ptr->pos() && (row_ptr->par() == firstpar)) {
3688                 
3689                 // start of appendix?
3690                 if (row_ptr->par()->params.startOfAppendix()) {
3691                         pain.line(1, y_offset,
3692                                   ww - 2, y_offset,
3693                                   LColor::appendixline);
3694                 }
3695                 
3696                 // think about the margins
3697                 if (!row_ptr->previous() && bv_owner)
3698                         y_top += LYX_PAPER_MARGIN;
3699                 
3700                 // draw a top pagebreak
3701                 if (row_ptr->par()->params.pagebreakTop()) {
3702                         LyXFont pb_font;
3703                         pb_font.setColor(LColor::pagebreak).decSize();
3704                         int w = 0;
3705                         int a = 0;
3706                         int d = 0;
3707                         pain.line(0, y_offset + y_top + 2*DefaultHeight(),
3708                                   ww, 
3709                                   y_offset + y_top + 2 * DefaultHeight(),
3710                                   LColor::pagebreak, 
3711                                   Painter::line_onoffdash)
3712                                 .rectText(0,
3713                                           0,
3714                                           _("Page Break (top)"),
3715                                           pb_font,
3716                                           LColor::background,
3717                                           LColor::background, false, w, a, d);
3718                         pain.rectText((ww - w)/2,
3719                                       y_offset + y_top + 2 * DefaultHeight() + d,
3720                                       _("Page Break (top)"),
3721                                       pb_font,
3722                                       LColor::background,
3723                                       LColor::background);
3724                         y_top += 3 * DefaultHeight();
3725                 }
3726                 
3727                 if (row_ptr->par()->params.spaceTop().kind() == VSpace::VFILL) {
3728                         // draw a vfill top
3729                         pain.line(0, y_offset + 2 + y_top,
3730                                   LYX_PAPER_MARGIN, y_offset + 2 + y_top,
3731                                   LColor::vfillline);
3732                         
3733                         pain.line(0, y_offset + y_top + 3 * DefaultHeight(),
3734                                   LYX_PAPER_MARGIN,
3735                                   y_offset + y_top + 3 * DefaultHeight(),
3736                                   LColor::vfillline);
3737                         
3738                         pain.line(LYX_PAPER_MARGIN / 2, y_offset + 2 + y_top,
3739                                   LYX_PAPER_MARGIN / 2,
3740                                   y_offset + y_top + 3 * DefaultHeight(),
3741                                   LColor::vfillline);
3742                         
3743                         y_top += 3 * DefaultHeight();
3744                 }
3745                 
3746                 // think about user added space
3747                 y_top += int(row_ptr->par()->params.spaceTop().inPixels(bview));
3748                 
3749                 // think about the parskip
3750                 // some parskips VERY EASY IMPLEMENTATION
3751                 if (bview->buffer()->params.paragraph_separation == BufferParams::PARSEP_SKIP) {
3752                         if (layout.latextype == LATEX_PARAGRAPH
3753                             && firstpar->GetDepth() == 0
3754                             && firstpar->previous())
3755                                 y_top += bview->buffer()->params.getDefSkip().inPixels(bview);
3756                         else if (firstpar->previous()
3757                                  && textclasslist.Style(bview->buffer()->params.textclass,
3758                                                         firstpar->previous()->GetLayout()).latextype == LATEX_PARAGRAPH
3759                                  && firstpar->previous()->GetDepth() == 0)
3760                                 // is it right to use defskip here, too? (AS) 
3761                                 y_top += bview->buffer()->params.getDefSkip().inPixels(bview);
3762                 }
3763                 
3764                 if (row_ptr->par()->params.lineTop()) {
3765                         // draw a top line
3766                         y_top +=  lyxfont::ascent('x',
3767                                                   GetFont(bview->buffer(),
3768                                                           row_ptr->par(), 0));
3769                         int const w = (inset_owner ?
3770                                        inset_owner->width(bview, font) : ww);
3771                         int const xp = static_cast<int>(inset_owner ? x : 0);
3772                         pain.line(xp, y_offset + y_top,
3773                                   w, y_offset + y_top,
3774                                   LColor::topline,
3775                                   Painter::line_solid,
3776                                   Painter::line_thick);
3777                         
3778                         y_top +=  lyxfont::ascent('x',GetFont(bview->buffer(),
3779                                                               row_ptr->par(), 0));
3780                 }
3781                 
3782                 // should we print a label?
3783                 if (layout.labeltype >= LABEL_STATIC
3784                     && (layout.labeltype != LABEL_STATIC
3785                         || layout.latextype != LATEX_ENVIRONMENT
3786                         || row_ptr->par()->IsFirstInSequence())) {
3787                         font = GetFont(bview->buffer(), row_ptr->par(), -2);
3788                         if (!row_ptr->par()->GetLabelstring().empty()) {
3789                                 tmpx = x;
3790                                 string const tmpstring =
3791                                         row_ptr->par()->GetLabelstring();
3792                                 
3793                                 if (layout.labeltype == LABEL_COUNTER_CHAPTER) {
3794                                         if (bview->buffer()->params.secnumdepth >= 0) {
3795                                                 // this is special code for
3796                                                 // the chapter layout. This is
3797                                                 // printed in an extra row
3798                                                 // and has a pagebreak at
3799                                                 // the top.
3800                                                 float spacing_val = 1.0;
3801                                                 if (!row_ptr->par()->params.spacing().isDefault()) {
3802                                                         spacing_val = row_ptr->par()->params.spacing().getValue();
3803                                                 } else {
3804                                                         spacing_val = bview->buffer()->params.spacing.getValue();
3805                                                 }
3806    
3807                                                 maxdesc = int(lyxfont::maxDescent(font) * layout.spacing.getValue() * spacing_val)
3808                                                         + int(layout.parsep) * DefaultHeight();
3809                                                 if (is_rtl)
3810                                                         tmpx = ww - LeftMargin(bview, row_ptr) - 
3811                                                                 lyxfont::width(tmpstring, font);
3812                                                 pain.text(int(tmpx),
3813                                                           y_offset + row_ptr->baseline() - row_ptr->ascent_of_text() - maxdesc,
3814                                                           tmpstring, font);
3815                                         }
3816                                 } else {
3817                                         if (is_rtl) {
3818                                                 tmpx = ww - LeftMargin(bview, row_ptr)
3819                                                         + lyxfont::width(layout.labelsep, font);
3820 #ifndef NEW_INSETS
3821                                                 if (row_ptr->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)  {
3822                                                         LyXFont font(LyXFont::ALL_SANE);
3823                                                         font.setSize(LyXFont::SIZE_SMALL);
3824                                                         tmpx += lyxfont::width("Mwide-fixM", font);
3825                                                 }
3826 #endif
3827                                         } else
3828                                                 tmpx = x - lyxfont::width(layout.labelsep, font)
3829                                                         - lyxfont::width(tmpstring, font);
3830
3831                                         // draw it!
3832                                         pain.text(int(tmpx),
3833                                                   y_offset + row_ptr->baseline(),
3834                                                   tmpstring, font);
3835                                 }
3836                         }
3837                         // the labels at the top of an environment.
3838                         // More or less for bibliography
3839                 } else if (layout.labeltype == LABEL_TOP_ENVIRONMENT ||
3840                            layout.labeltype == LABEL_BIBLIO ||
3841                            layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) {
3842                         if (row_ptr->par()->IsFirstInSequence()) {
3843                                 font = GetFont(bview->buffer(),
3844                                                row_ptr->par(), -2);
3845                                 if (!row_ptr->par()->GetLabelstring().empty()) {
3846                                         string const tmpstring =
3847                                                 row_ptr->par()->GetLabelstring();
3848                                         float spacing_val = 1.0;
3849                                         if (!row_ptr->par()->params.spacing().isDefault()) {
3850                                                 spacing_val = row_ptr->par()->params.spacing().getValue();
3851                                         } else {
3852                                                 spacing_val = bview->buffer()->params.spacing.getValue();
3853                                         }
3854    
3855                                         maxdesc = int(lyxfont::maxDescent(font) * layout.spacing.getValue() * spacing_val
3856                                                       + (layout.labelbottomsep * DefaultHeight()));
3857                                         
3858                                         tmpx = x;
3859                                         if (layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT){
3860                                                 tmpx = ( (is_rtl ? LeftMargin(bview, row_ptr) : x)
3861                                                          + ww - RightMargin(bview->buffer(), row_ptr) ) / 2; 
3862                                                 tmpx -= lyxfont::width(tmpstring, font) / 2;
3863                                         } else if (is_rtl)
3864                                                 tmpx = ww - LeftMargin(bview, row_ptr) - 
3865                                                         lyxfont::width(tmpstring, font);
3866                                         pain.text(int(tmpx),
3867                                                   y_offset + row_ptr->baseline()
3868                                                   - row_ptr->ascent_of_text()
3869                                                   - maxdesc,
3870                                                   tmpstring, font);
3871                                 }
3872                         }
3873                 }
3874                 if (layout.labeltype == LABEL_BIBLIO && row_ptr->par()->bibkey) {
3875                         font = GetFont(bview->buffer(), row_ptr->par(), -1);
3876                         if (is_rtl)
3877                                 tmpx = ww - LeftMargin(bview, row_ptr)
3878                                         + lyxfont::width(layout.labelsep, font);
3879                         else
3880                                 tmpx = x - lyxfont::width(layout.labelsep, font)
3881                                         - row_ptr->par()->bibkey->width(bview, font);
3882                         row_ptr->par()->bibkey->draw(bview, font,
3883                                                    y_offset + row_ptr->baseline(), 
3884                                                    tmpx, clear_area);
3885                 }
3886         }
3887         
3888         // is it a last row?
3889 #ifndef NEW_INSETS
3890         LyXParagraph * par = row_ptr->par()->LastPhysicalPar();
3891 #else
3892         LyXParagraph * par = row_ptr->par();
3893 #endif
3894         if (
3895 #ifndef NEW_INSETS
3896                 row_ptr->par()->ParFromPos(last + 1) == par
3897 #else
3898                 row_ptr->par() == par
3899 #endif
3900                 && (!row_ptr->next() || row_ptr->next()->par() != row_ptr->par()))
3901         {
3902                 // think about the margins
3903                 if (!row_ptr->next() && bv_owner)
3904                         y_bottom -= LYX_PAPER_MARGIN;
3905                 
3906                 // draw a bottom pagebreak
3907                 if (firstpar->params.pagebreakBottom()) {
3908                         LyXFont pb_font;
3909                         pb_font.setColor(LColor::pagebreak).decSize();
3910                         int const y_place = y_offset + y_bottom
3911                                 - 2 * DefaultHeight();
3912                         
3913                         int w = 0;
3914                         int a = 0;
3915                         int d = 0;
3916                         pain
3917                                 .line(0, y_place, ww, y_place,
3918                                       LColor::pagebreak,
3919                                       Painter::line_onoffdash)
3920                                 .rectText(0, 0,
3921                                           _("Page Break (bottom)"),
3922                                           pb_font,
3923                                           LColor::background,
3924                                           LColor::background, false, w, a, d);
3925                         pain.rectText((ww - w) / 2, y_place + d,
3926                                       _("Page Break (bottom)"),
3927                                       pb_font,
3928                                       LColor::background,
3929                                       LColor::background);
3930                         y_bottom -= 3 * DefaultHeight();
3931                 }
3932                 
3933                 if (firstpar->params.spaceBottom().kind() == VSpace::VFILL) {
3934                         // draw a vfill bottom
3935                         int const y_place = y_offset + y_bottom
3936                                 - 3 * DefaultHeight();
3937                         
3938                         pain.line(0, y_place,
3939                                   LYX_PAPER_MARGIN, y_place,
3940                                   LColor::vfillline);
3941                         pain.line(0, y_offset + y_bottom - 2,
3942                                   LYX_PAPER_MARGIN,
3943                                   y_offset + y_bottom - 2,
3944                                   LColor::vfillline);
3945                         pain.line(LYX_PAPER_MARGIN / 2,
3946                                   y_place,
3947                                   LYX_PAPER_MARGIN / 2,
3948                                   y_offset + y_bottom - 2,
3949                                   LColor::vfillline);
3950                         y_bottom -= 3 * DefaultHeight();
3951                 }
3952                 
3953                 // think about user added space
3954                 y_bottom -= int(firstpar->params.spaceBottom().inPixels(bview));
3955                 
3956                 if (firstpar->params.lineBottom()) {
3957                         // draw a bottom line
3958 #ifndef NEW_INSETS
3959                         y_bottom -= lyxfont::ascent('x',
3960                                                     GetFont(bview->buffer(),
3961                                                             par,
3962                                                             par->Last() - 1));
3963 #else
3964                         y_bottom -= lyxfont::ascent('x',
3965                                                     GetFont(bview->buffer(),
3966                                                             par,
3967                                                             par->size() - 1));
3968 #endif
3969                         int const w = (inset_owner ?
3970                                        inset_owner->width(bview, font) : ww);
3971                         int const xp = static_cast<int>(inset_owner ? x : 0);
3972                         pain.line(xp, y_offset + y_bottom,
3973                                   w, y_offset + y_bottom,
3974                                   LColor::topline, Painter::line_solid,
3975                                   Painter::line_thick);
3976 #ifndef NEW_INSETS
3977                         y_bottom -= lyxfont::ascent('x',
3978                                                     GetFont(bview->buffer(),
3979                                                             par,
3980                                                             par->Last() - 1));
3981 #else
3982                         y_bottom -= lyxfont::ascent('x',
3983                                                     GetFont(bview->buffer(),
3984                                                             par,
3985                                                             par->size() - 1));
3986 #endif
3987                 }
3988
3989                 // draw an endlabel
3990                 int const endlabel =
3991                         row_ptr->par()->GetEndLabel(bview->buffer()->params);
3992                 switch (endlabel) {
3993                 case END_LABEL_BOX:
3994                 case END_LABEL_FILLED_BOX:
3995                 {
3996                         LyXFont const font = GetFont(bview->buffer(),
3997                                                      row_ptr->par(), last);
3998                         int const size = int(0.75 * lyxfont::maxAscent(font));
3999                         int const y = (y_offset + row_ptr->baseline()) - size;
4000                         int x = is_rtl ? LYX_PAPER_MARGIN 
4001                                 : ww - LYX_PAPER_MARGIN - size;
4002 #ifndef NEW_INSETS
4003                         if (row_ptr->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
4004                                 if (is_rtl) {
4005                                         LyXFont font(LyXFont::ALL_SANE);
4006                                         font.setSize(LyXFont::SIZE_SMALL);
4007                                         x += lyxfont::width("Mwide-figM", font);
4008                                 } else
4009                                         x -= LYX_PAPER_MARGIN/2;
4010 #endif
4011                         if (row_ptr->fill() <= size)
4012                                 x += (size - row_ptr->fill() + 1) * (is_rtl ? -1 : 1);
4013                         if (endlabel == END_LABEL_BOX) {
4014                                 pain.line(x, y, x, y + size,
4015                                           LColor::eolmarker);
4016                                 pain.line(x + size, y, x + size , y + size,
4017                                           LColor::eolmarker);
4018                                 pain.line(x, y, x + size, y,
4019                                           LColor::eolmarker);
4020                                 pain.line(x, y + size, x + size, y + size,
4021                                           LColor::eolmarker);
4022                         } else
4023                                 pain.fillRectangle(x, y, size, size,
4024                                                    LColor::eolmarker);
4025                         break;
4026                 }
4027                 case END_LABEL_STATIC:
4028                 {
4029                         LyXTextClass::LayoutList::size_type layout = row_ptr->par()->GetLayout();
4030                         string const tmpstring = textclasslist.
4031                                 Style(bview->buffer()->params.textclass,
4032                                       layout).endlabelstring();
4033                         font = GetFont(bview->buffer(), row_ptr->par(), -2);
4034                         int const tmpx = is_rtl ?
4035                                 int(x) - lyxfont::width(tmpstring, font)
4036                                 : ww - RightMargin(bview->buffer(), row_ptr) - row_ptr->fill();
4037                         pain.text( tmpx, y_offset + row_ptr->baseline(), tmpstring, font);
4038                         break;
4039                 }
4040                 case END_LABEL_NO_LABEL:
4041                         break;
4042                 }
4043         }
4044         
4045         // draw the text in the pixmap
4046         
4047         vpos = row_ptr->pos();
4048
4049         LyXParagraph::size_type main_body = 
4050                 BeginningOfMainBody(bview->buffer(), row_ptr->par());
4051         if (main_body > 0 &&
4052             (main_body-1 > last || 
4053              !row_ptr->par()->IsLineSeparator(main_body - 1)))
4054                 main_body = 0;
4055         
4056         while (vpos <= last)  {
4057                 pos = vis2log(vpos);
4058                 if (main_body > 0 && pos == main_body - 1) {
4059                         x += fill_label_hfill
4060                                 + lyxfont::width(layout.labelsep,
4061                                                  GetFont(bview->buffer(),
4062                                                          row_ptr->par(), -2))
4063                                 - SingleWidth(bview,
4064                                               row_ptr->par(),
4065                                               main_body - 1);
4066                 }
4067                 
4068                 if (row_ptr->par() ->IsHfill(pos)) {
4069                         x += 1;
4070                         pain.line(int(x),
4071                                   y_offset + row_ptr->baseline() - DefaultHeight() / 2,
4072                                   int(x),
4073                                   y_offset + row_ptr->baseline(),
4074                                   LColor::vfillline);
4075                         
4076                         if (HfillExpansion(bview->buffer(),
4077                                            row_ptr, pos)) {
4078                                 if (pos >= main_body) {
4079                                         pain.line(int(x),
4080                                                   y_offset + row_ptr->baseline() - DefaultHeight() / 4,
4081                                                   int(x + fill_hfill),
4082                                                   y_offset + row_ptr->baseline() - DefaultHeight() / 4,
4083                                                   LColor::vfillline,
4084                                                   Painter::line_onoffdash);
4085                                         x += fill_hfill;
4086                                 } else {
4087                                         pain.line(int(x),
4088                                                   y_offset + row_ptr->baseline() - DefaultHeight() / 4,
4089                                                   int(x + fill_label_hfill),
4090                                                   y_offset + row_ptr->baseline() - DefaultHeight() / 4,
4091                                                   LColor::vfillline,
4092                                                   Painter::line_onoffdash);
4093                                         
4094                                         x += fill_label_hfill;
4095                                 }
4096                                 pain.line(int(x),
4097                                           y_offset + row_ptr->baseline() - DefaultHeight() / 2,
4098                                           int(x),
4099                                           y_offset + row_ptr->baseline(),
4100                                           LColor::vfillline);
4101                         }
4102                         x += 2;
4103                         ++vpos;
4104                 } else if (row_ptr->par()->IsSeparator(pos)) {
4105                         x += SingleWidth(bview,
4106                                          row_ptr->par(), pos);
4107                         if (pos >= main_body)
4108                                 x += fill_separator;
4109                         ++vpos;
4110                 } else
4111                         draw(bview, row_ptr, vpos, y_offset, x, clear_area);
4112         }
4113 }
4114
4115
4116 int LyXText::DefaultHeight() const
4117 {
4118         LyXFont font(LyXFont::ALL_SANE);
4119         return int(lyxfont::maxAscent(font) + lyxfont::maxDescent(font) * 1.5);
4120 }
4121
4122    
4123 /* returns the column near the specified x-coordinate of the row 
4124 * x is set to the real beginning of this column  */ 
4125 int LyXText::GetColumnNearX(BufferView * bview, Row * row, int & x,
4126                             bool & boundary) const
4127 {
4128         float tmpx = 0.0;
4129         float fill_separator, fill_hfill, fill_label_hfill;
4130    
4131         PrepareToPrint(bview, row, tmpx, fill_separator,
4132                        fill_hfill, fill_label_hfill);
4133
4134         LyXParagraph::size_type vc = row->pos();
4135         LyXParagraph::size_type last = RowLastPrintable(row);
4136         LyXParagraph::size_type c = 0;
4137         LyXLayout const & layout =
4138                 textclasslist.Style(bview->buffer()->params.textclass,
4139                                     row->par()->GetLayout());
4140         bool left_side = false;
4141
4142         LyXParagraph::size_type
4143                 main_body = BeginningOfMainBody(bview->buffer(), row->par());
4144         float last_tmpx = tmpx;
4145         
4146         if (main_body > 0 &&
4147             (main_body-1 > last || 
4148              !row->par()->IsLineSeparator(main_body - 1)))
4149                 main_body = 0;
4150         
4151         while (vc <= last && tmpx <= x) {
4152                 c = vis2log(vc);
4153                 last_tmpx = tmpx;
4154                 if (main_body > 0 && c == main_body-1) {
4155                         tmpx += fill_label_hfill +
4156                                 lyxfont::width(layout.labelsep,
4157                                                GetFont(bview->buffer(), row->par(), -2));
4158                         if (row->par()->IsLineSeparator(main_body - 1))
4159                                 tmpx -= SingleWidth(bview, row->par(), main_body-1);
4160                 }
4161                 
4162                 if (HfillExpansion(bview->buffer(), row, c)) {
4163                         x += SingleWidth(bview, row->par(), c);
4164                         if (c >= main_body)
4165                                 tmpx += fill_hfill;
4166                         else
4167                                 tmpx += fill_label_hfill;
4168                 }
4169                 else if (row->par()->IsSeparator(c)) {
4170                         tmpx += SingleWidth(bview, row->par(), c);
4171                         if (c >= main_body)
4172                                 tmpx+= fill_separator;
4173                 } else
4174                         tmpx += SingleWidth(bview, row->par(), c);
4175                 ++vc;
4176         }
4177         
4178         if ((tmpx + last_tmpx) / 2 > x) {
4179                 tmpx = last_tmpx;
4180                 left_side = true;
4181         }
4182
4183         if (vc > last + 1)  // This shouldn't happen.
4184                 vc = last + 1;
4185
4186         boundary = false;
4187         bool const lastrow = lyxrc.rtl_support // This is not needed, but gives
4188                                          // some speedup if rtl_support=false
4189                 && (!row->next() || row->next()->par() != row->par());
4190         bool const rtl = (lastrow)
4191                 ? row->par()->isRightToLeftPar(bview->buffer()->params)
4192                 : false; // If lastrow is false, we don't need to compute
4193                          // the value of rtl.
4194
4195         if (row->pos() > last)  // Row is empty?
4196                 c = row->pos();
4197         else if (lastrow &&
4198                  ( ( rtl &&  left_side && vc == row->pos() && x < tmpx - 5) ||
4199                    (!rtl && !left_side && vc == last + 1   && x > tmpx + 5) ))
4200                 c = last + 1;
4201         else if (vc == row->pos()) {
4202                 c = vis2log(vc);
4203                 if (bidi_level(c) % 2 == 1)
4204                         ++c;
4205         } else {
4206                 c = vis2log(vc - 1);
4207                 bool const rtl = (bidi_level(c) % 2 == 1);
4208                 if (left_side == rtl) {
4209                         ++c;
4210                         boundary = IsBoundary(bview->buffer(), row->par(), c);
4211                 }
4212         }
4213
4214         if (row->pos() <= last && c > last
4215             && row->par()->IsNewline(last)) {
4216                 if (bidi_level(last) % 2 == 0)
4217                         tmpx -= SingleWidth(bview, row->par(), last);
4218                 else
4219                         tmpx += SingleWidth(bview, row->par(), last);
4220                 c = last;
4221         }
4222
4223         c -= row->pos();
4224         x = int(tmpx);
4225         return c;
4226 }
4227
4228
4229 #ifndef NEW_INSETS
4230 /* turn the selection into a new environment. If there is no selection,
4231 * create an empty environment */ 
4232 void LyXText::InsertFootnoteEnvironment(BufferView * bview, 
4233                                         LyXParagraph::footnote_kind kind)
4234 {
4235    /* no footnoteenvironment in a footnoteenvironment */ 
4236    if (cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
4237       WriteAlert(_("Impossible operation"), 
4238                  _("You can't insert a float in a float!"), 
4239                  _("Sorry."));
4240      return;
4241    }
4242 #ifndef NO_PEXTRA
4243    /* no marginpars in minipages */
4244    if (kind == LyXParagraph::MARGIN 
4245       && cursor.par()->params.pextraType() == LyXParagraph::PEXTRA_MINIPAGE) {
4246       WriteAlert(_("Impossible operation"), 
4247                  _("You can't insert a marginpar in a minipage!"), 
4248                  _("Sorry."));
4249       return;
4250    }
4251 #endif
4252    /* this doesnt make sense, if there is no selection */ 
4253    bool dummy_selection = false;
4254    if (!selection) {
4255       sel_start_cursor = cursor;       /* dummy selection  */
4256       sel_end_cursor = cursor;
4257       dummy_selection = true;
4258    }
4259    
4260    LyXParagraph * tmppar;
4261
4262    /* a test to make sure there is not already a footnote
4263     * in the selection. */
4264    
4265    tmppar = sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos());
4266    
4267    while (tmppar != sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()) && 
4268           tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
4269      tmppar = tmppar->next_;
4270    
4271    if (tmppar != sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())
4272        || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
4273       WriteAlert(_("Impossible operation"), 
4274                  _("Float would include float!"), 
4275                  _("Sorry."));
4276       return;
4277    }
4278    
4279    /* ok we have a selection. This is always between sel_start_cursor
4280     * and sel_end cursor */
4281
4282    SetUndo(bview->buffer(), Undo::FINISH, 
4283            sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous_, 
4284            sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next_); 
4285    
4286    if (sel_end_cursor.pos() > 0 
4287        && sel_end_cursor.par()->IsLineSeparator(sel_end_cursor.pos() - 1))
4288            sel_end_cursor.pos(sel_end_cursor.pos() - 1);
4289    /* please break before a space at the end */
4290    if (sel_start_cursor.par() == sel_end_cursor.par()
4291        && sel_start_cursor.pos() > sel_end_cursor.pos())
4292            sel_start_cursor.pos(sel_start_cursor.pos() - 1);
4293
4294    sel_end_cursor.par()->BreakParagraphConservative(bview->buffer()->params, sel_end_cursor.pos());
4295    
4296    sel_end_cursor.par(sel_end_cursor.par()->next());
4297    sel_end_cursor.pos(0);
4298    
4299    // don't forget to insert a dummy layout paragraph if necessary
4300    if (sel_start_cursor.par()->GetLayout() != sel_end_cursor.par()->layout){
4301      sel_end_cursor.par()->BreakParagraphConservative(bview->buffer()->params, 0);
4302      sel_end_cursor.par()->layout = LYX_DUMMY_LAYOUT;
4303      sel_end_cursor.par(sel_end_cursor.par()->next_);
4304    }
4305    else
4306      sel_end_cursor.par()->layout = LYX_DUMMY_LAYOUT;
4307
4308    cursor = sel_end_cursor;
4309
4310    /* please break behind a space, if there is one. The space should
4311     * be erased too */ 
4312    if (sel_start_cursor.pos() > 0 
4313        && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos() - 1))
4314      sel_start_cursor.pos(sel_start_cursor.pos() - 1);
4315    if (sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())) {
4316       sel_start_cursor.par()->Erase(sel_start_cursor.pos());
4317    }
4318    
4319    sel_start_cursor.par()->BreakParagraphConservative(bview->buffer()->params,
4320                                                     sel_start_cursor.pos());
4321    tmppar = sel_start_cursor.par()->next();
4322    
4323    if (dummy_selection) {
4324            tmppar->Clear();
4325            if (kind == LyXParagraph::TAB
4326                || kind == LyXParagraph::FIG 
4327                || kind == LyXParagraph::WIDE_TAB
4328                || kind == LyXParagraph::WIDE_FIG 
4329                || kind == LyXParagraph::ALGORITHM) {
4330                    pair<bool, LyXTextClass::size_type> lres =
4331                            textclasslist.NumberOfLayout(bview->buffer()->params.textclass,
4332                                                         "Caption");
4333                    LyXTextClass::size_type lay;
4334                    if (lres.first) {
4335                            // layout fount
4336                            lay = lres.second;
4337                    } else {
4338                            // layout not found
4339                            lay = 0; // use default layout "Standard" (0)
4340                    }
4341                    tmppar->SetLayout(bview->buffer()->params, lay);
4342            }
4343    } else {
4344      if (sel_start_cursor.pos() > 0) {
4345        /* the footnote-environment should begin with a standard layout.
4346         * Imagine you insert a footnote within an enumeration, you 
4347         * certainly do not want an enumerated footnote! */ 
4348        tmppar->Clear();
4349      } else {
4350        /* this is a exception the user would sometimes expect, I hope */
4351        sel_start_cursor.par()->Clear();
4352      }
4353    }
4354    
4355    while (tmppar != sel_end_cursor.par()) {
4356       tmppar->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
4357       tmppar->footnotekind = kind;
4358       tmppar = tmppar->next();
4359    }
4360
4361    RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->next());
4362    
4363    SetCursor(bview, sel_start_cursor.par()->next(), 0);
4364
4365    ClearSelection(bview);
4366 }
4367 #endif
4368
4369
4370 // returns pointer to a specified row
4371 Row * LyXText::GetRow(LyXParagraph * par,
4372                       LyXParagraph::size_type pos, int & y) const
4373 {
4374         if (!firstrow)
4375                 return 0;
4376         
4377         Row * tmprow = firstrow;
4378         y = 0;
4379         
4380         // find the first row of the specified paragraph
4381         while (tmprow->next() && tmprow->par() != par) {
4382                 y += tmprow->height();
4383                 tmprow = tmprow->next();
4384         }
4385         
4386         // now find the wanted row
4387         while (tmprow->pos() < pos
4388                && tmprow->next()
4389                && tmprow->next()->par() == par
4390                && tmprow->next()->pos() <= pos) {
4391                 y += tmprow->height();
4392                 tmprow = tmprow->next();
4393         }
4394         
4395         return tmprow;
4396 }