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