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