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