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