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