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