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