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