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