]> git.lyx.org Git - lyx.git/blob - src/text.C
the freespacing patch from Kayvan, draw the math empty delim with onoffdash, asure...
[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 USE_OSTREAM_ONLY
2970 #ifdef HAVE_SSTREAM
2971         ostringstream latex;
2972 #else
2973         ostrstream latex;
2974 #endif
2975 #else
2976         string latex;
2977 #endif
2978         /* and find the end of the word 
2979            (optional hyphens are part of a word) */
2980         while (cursor.pos < cursor.par->Last()
2981                && (cursor.par->IsLetter(cursor.pos)) 
2982                    || (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
2983                        && cursor.par->GetInset(cursor.pos) != 0
2984                        && cursor.par->GetInset(cursor.pos)->Latex(latex, 0, false) == 0
2985 #ifdef USE_OSTREAM_ONLY
2986 #ifdef HAVE_SSTREAM
2987                        && latex.str() == "\\-"
2988 #else
2989                 && string(latex.str(), 3) == "\\-" // this is not nice at all
2990 #endif
2991 #else
2992                        && latex == "\\-"
2993 #endif
2994                            ))
2995                 cursor.pos++;
2996
2997 #ifdef USE_OSTREAM_ONLY
2998 #ifndef HAVE_SSTREAM
2999         delete [] latex.str();
3000 #endif
3001 #endif
3002         // Finally, we copy the word to a string and return it
3003         char * str = 0;
3004
3005         if (sel_cursor.pos < cursor.pos) {
3006                 str = new char [cursor.pos - sel_cursor.pos + 2];
3007                 LyXParagraph::size_type i, j;
3008                 for (i = sel_cursor.pos, j = 0; i < cursor.pos; ++i) {
3009                         if (cursor.par->GetChar(i) != LyXParagraph::META_INSET)
3010                                 str[j++] = cursor.par->GetChar(i);
3011                 }
3012                 str[j] = '\0';
3013         }
3014         return str;
3015 }
3016
3017
3018 // This one is also only for the spellchecker
3019 void LyXText::SelectSelectedWord()
3020 {
3021         /* move cursor to the beginning */
3022         SetCursor(sel_cursor.par, sel_cursor.pos);
3023         
3024         /* set the sel cursor */
3025         sel_cursor = cursor;
3026
3027 #ifdef USE_OSTREAM_ONLY
3028 #ifdef HAVE_SSTREAM
3029         ostringstream latex;
3030 #else
3031         ostrstream latex;
3032 #endif
3033 #else
3034         string latex;
3035 #endif
3036         
3037         /* now find the end of the word */
3038         while (cursor.pos < cursor.par->Last()
3039                && (cursor.par->IsLetter(cursor.pos)
3040                    || (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
3041                        && cursor.par->GetInset(cursor.pos) != 0
3042                        && cursor.par->GetInset(cursor.pos)->Latex(latex, 0, false) == 0
3043 #ifdef USE_OSTREAM_ONLY
3044 #ifdef HAVE_SSTREAM
3045                        && latex.str() == "\\-"
3046 #else
3047                        && string(latex.str(), 3) == "\\-"
3048 #endif
3049 #else
3050                        && latex == "\\-"
3051 #endif
3052                            )))
3053                 cursor.pos++;
3054         
3055 #ifdef USE_OSTREAM_ONLY
3056 #ifndef HAVE_SSTREAM
3057         delete [] latex.str();
3058 #endif
3059 #endif
3060         SetCursor(cursor.par, cursor.pos);
3061         
3062         /* finally set the selection */ 
3063         SetSelection();
3064 }
3065
3066
3067 /* -------> Delete from cursor up to the end of the current or next word. */
3068 void LyXText::DeleteWordForward()
3069 {
3070         LyXCursor tmpcursor = cursor;
3071         
3072         if (!cursor.par->Last())
3073                 CursorRight();
3074 #warning See comment on top of text.C
3075         else {
3076                 /* -------> Skip initial non-word stuff. */
3077                 while ( cursor.pos < cursor.par->Last() 
3078                         && (cursor.par->IsSeparator(cursor.pos)
3079                             || cursor.par->IsKomma(cursor.pos)) )
3080                         cursor.pos++;
3081                 
3082                 SetCursorIntern(cursor.par, cursor.pos);
3083                 selection = True; // to avoid deletion 
3084                 CursorRightOneWord();
3085                 sel_cursor = cursor;
3086                 cursor = tmpcursor;
3087                 SetSelection(); 
3088                 
3089                 /* -----> Great, CutSelection() gets rid of multiple spaces. */
3090                 CutSelection();
3091         }
3092 }
3093
3094
3095 /* -------> Delete from cursor to start of current or prior word. */
3096 void LyXText::DeleteWordBackward()
3097 {
3098        LyXCursor tmpcursor = cursor;
3099        if (!cursor.par->Last())
3100          CursorLeft();
3101 #warning See comment on top of text.C
3102        else{
3103          selection = true; // to avoid deletion 
3104          CursorLeftOneWord();
3105          sel_cursor = cursor;
3106          cursor = tmpcursor;
3107          SetSelection();
3108          CutSelection();
3109        }
3110 }
3111
3112
3113 /* -------> Kill to end of line. */
3114 void LyXText::DeleteLineForward()
3115 {
3116         LyXCursor tmpcursor = cursor;
3117         if (!cursor.par->Last())
3118                 CursorRight();
3119 #warning See comment on top of text.C
3120         else {
3121                 CursorEnd();
3122                 sel_cursor = cursor;
3123                 cursor = tmpcursor;
3124                 SetSelection();
3125                 if (selection == false) {
3126                         DeleteWordForward();
3127                 } else {
3128                         CutSelection();
3129                 }
3130         }
3131 }
3132
3133
3134 // Change the case of a word at cursor position. The meaning of action
3135 // is:
3136 // 0  change to lowercase
3137 // 1  capitalize word
3138 // 2  change to uppercase
3139 // This function directly manipulates LyXParagraph::text because there
3140 // is no LyXParagraph::SetChar currently. I did what I could to ensure
3141 // that it is correct. I guess part of it should be moved to
3142 // LyXParagraph, but it will have to change for 1.1 anyway. At least
3143 // it does not access outside of the allocated array as the older
3144 // version did. (JMarc) 
3145 void LyXText::ChangeWordCase(LyXText::TextCase action) 
3146 {
3147         LyXParagraph * tmppar = cursor.par->ParFromPos(cursor.pos);
3148
3149         SetUndo(Undo::FINISH, tmppar->previous, tmppar->next); 
3150
3151         LyXParagraph::size_type tmppos = 
3152                 cursor.par->PositionInParFromPos(cursor.pos);
3153         while (tmppos < tmppar->size()) {
3154                 unsigned char c = tmppar->text[tmppos];
3155                 if (IsKommaChar(c) || IsLineSeparatorChar(c))
3156                         break;
3157                 if (c != LyXParagraph::META_INSET) {
3158                         switch (action) {
3159                         case text_lowercase:
3160                                 c = tolower(c);
3161                                 break;
3162                         case text_capitalization:
3163                                 c = toupper(c);
3164                                 action = text_lowercase;
3165                                 break;
3166                         case text_uppercase:
3167                                 c = toupper(c);
3168                                 break;
3169                         }
3170                 }
3171                 
3172                 tmppar->text[tmppos] = c;
3173                 ++tmppos;
3174         }
3175         CheckParagraph(tmppar, tmppos);
3176         CursorRightOneWord();
3177 }
3178
3179
3180 void LyXText::Delete()
3181 {
3182         // this is a very easy implementation
3183
3184         LyXCursor old_cursor = cursor;
3185         int old_cur_par_id = old_cursor.par->id();
3186         int old_cur_par_prev_id = old_cursor.par->previous ?
3187                 old_cursor.par->previous->id() : 0;
3188         
3189         // just move to the right
3190         CursorRightIntern();
3191
3192 #warning Look at the comment here.
3193         // This check is not very good...
3194         // The CursorRightIntern calls DeleteEmptyParagrapgMechanism
3195         // and that can very well delete the par or par->previous in
3196         // old_cursor. Will a solution where we compare paragraph id's
3197         //work better?
3198 #if 1
3199         if ((cursor.par->previous ? cursor.par->previous->id() : 0)
3200             == old_cur_par_prev_id
3201             && cursor.par->id() != old_cur_par_id)
3202                 return; // delete-empty-paragraph-mechanism has done it
3203 #else
3204         if (cursor.par->previous == old_cursor.par->previous
3205             && cursor.par != old_cursor.par)
3206                 return; // delete-empty-paragraph-mechanism has done it
3207 #endif
3208         // if you had success make a backspace
3209         if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) {
3210                 LyXCursor tmpcursor = cursor;
3211                 cursor = old_cursor; // to make sure undo gets the right cursor position
3212                 SetUndo(Undo::DELETE, 
3213                         cursor.par->ParFromPos(cursor.pos)->previous, 
3214                         cursor.par->ParFromPos(cursor.pos)->next); 
3215                 cursor = tmpcursor;
3216                 Backspace();
3217         }
3218 }
3219
3220
3221 void  LyXText::Backspace()
3222 {
3223         LyXParagraph * tmppar;
3224         Row * tmprow, * row;
3225         long y;
3226         int tmpheight;
3227
3228         /* table stuff -- begin */
3229         if (cursor.par->table) {
3230                 BackspaceInTable();
3231                 return;
3232         }
3233         /* table stuff -- end */
3234         
3235         LyXFont rawtmpfont = current_font;
3236         LyXFont realtmpfont = real_current_font;
3237    
3238         // Get the font that is used to calculate the baselineskip
3239         int const lastpos = cursor.par->Last();
3240         LyXFont rawparfont = cursor.par->GetFontSettings(lastpos - 1);
3241
3242         if (cursor.pos == 0) {
3243                 // we may paste some paragraphs
3244       
3245                 // is it an empty paragraph?
3246       
3247                 if ((lastpos == 0
3248                      || (lastpos == 1 && cursor.par->IsSeparator(0)))
3249                     && !(cursor.par->Next() 
3250                          && cursor.par->footnoteflag == 
3251                          LyXParagraph::NO_FOOTNOTE
3252                          && cursor.par->Next()->footnoteflag == 
3253                          LyXParagraph::OPEN_FOOTNOTE)) {
3254                         
3255                         if (cursor.par->previous) {
3256                                 tmppar = cursor.par->previous->FirstPhysicalPar();
3257                                 if (cursor.par->GetLayout() == tmppar->GetLayout()
3258                                     && cursor.par->footnoteflag == tmppar->footnoteflag
3259                                     && cursor.par->GetAlign() == tmppar->GetAlign()) {
3260                                         
3261                                         tmppar->line_bottom = cursor.par->line_bottom;
3262                                         tmppar->added_space_bottom = cursor.par->added_space_bottom;
3263                                         tmppar->pagebreak_bottom = cursor.par->pagebreak_bottom;
3264                                 }
3265                                 
3266                                 CursorLeftIntern();
3267                      
3268                                 // the layout things can change the height of a row !
3269                                 tmpheight = cursor.row->height;
3270                                 SetHeightOfRow(cursor.row);
3271                                 if (cursor.row->height != tmpheight) {
3272                                         refresh_y = cursor.y - cursor.row->baseline;
3273                                         refresh_row = cursor.row;
3274                                         status = LyXText::NEED_MORE_REFRESH;
3275                                 }
3276                                 return;
3277                         }
3278                 }
3279                 if (cursor.par->ParFromPos(cursor.pos)->previous){
3280                         SetUndo(Undo::DELETE,
3281                                 cursor.par->ParFromPos(cursor.pos)->previous->previous,
3282                                 cursor.par->ParFromPos(cursor.pos)->next);
3283                 }
3284                 tmppar = cursor.par;
3285                 tmprow = cursor.row;
3286                 CursorLeftIntern();
3287 #warning See comment on top of text.C
3288                 /* Pasting is not allowed, if the paragraphs have different
3289                    layout. I think it is a real bug of all other
3290                    word processors to allow it. It confuses the user.
3291                    Even so with a footnote paragraph and a non-footnote
3292                    paragraph. I will not allow pasting in this case, 
3293                    because the user would be confused if the footnote behaves 
3294                    different wether it is open or closed.
3295                   
3296                    Correction: Pasting is always allowed with standard-layout
3297                 */
3298                 if (cursor.par != tmppar
3299                     && (cursor.par->GetLayout() == tmppar->GetLayout()
3300                         || !tmppar->GetLayout())
3301                     && cursor.par->footnoteflag == tmppar->footnoteflag
3302                     /* table stuff -- begin*/
3303                     && !cursor.par->table /* no pasting of tables */ 
3304                     /* table stuff -- end*/
3305                     && cursor.par->GetAlign() == tmppar->GetAlign()) {
3306                         
3307                         cursor.par->PasteParagraph();
3308                         
3309                         if (!(cursor.pos &&
3310                               cursor.par->IsSeparator(cursor.pos - 1)))
3311                                 cursor.par->InsertChar(cursor.pos, ' ');
3312                         else
3313                                 if (cursor.pos)
3314                                         cursor.pos--;
3315                         
3316                         status = LyXText::NEED_MORE_REFRESH;
3317                         refresh_row = cursor.row;
3318                         refresh_y = cursor.y - cursor.row->baseline;
3319                         
3320                         // remove the lost paragraph
3321                         RemoveParagraph(tmprow);
3322                         RemoveRow(tmprow);  
3323                         
3324                         AppendParagraph(cursor.row);
3325                         UpdateCounters(cursor.row);
3326                         
3327                         // the row may have changed, block, hfills etc.
3328                         SetCursor(cursor.par, cursor.pos);
3329                 }
3330         } else {
3331                 /* this is the code for a normal backspace, not pasting
3332                  * any paragraphs */ 
3333                 SetUndo(Undo::DELETE, 
3334                         cursor.par->ParFromPos(cursor.pos)->previous, 
3335                         cursor.par->ParFromPos(cursor.pos)->next); 
3336                 CursorLeftIntern();
3337                 
3338                 // some insets are undeletable here
3339                 if (cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET) {
3340                         if (!cursor.par->GetInset(cursor.pos)->Deletable())
3341                                 return; 
3342                         // force complete redo when erasing display insets
3343                         // this is a cruel mathod but save..... Matthias 
3344                         if (cursor.par->GetInset(cursor.pos)->display()){
3345                                 cursor.par->Erase(cursor.pos);
3346                                 RedoParagraph();
3347                                 return;
3348                         }
3349                 }
3350                 
3351                 row = cursor.row;
3352                 y = cursor.y - row->baseline;
3353                 LyXParagraph::size_type z;
3354                 /* remember that a space at the end of a row doesnt count
3355                  * when calculating the fill */ 
3356                 if (cursor.pos < RowLast(row) ||
3357                     !cursor.par->IsLineSeparator(cursor.pos)) {
3358                         row->fill += SingleWidth(cursor.par, cursor.pos);
3359                 }
3360                 
3361                 /* some special code when deleting a newline. This is similar
3362                  * to the behavior when pasting paragraphs */ 
3363                 if (cursor.pos && cursor.par->IsNewline(cursor.pos)) {
3364                         cursor.par->Erase(cursor.pos);
3365                         // refresh the positions
3366                         tmprow = row;
3367                         while (tmprow->next && tmprow->next->par == row->par) {
3368                                 tmprow = tmprow->next;
3369                                 tmprow->pos--;
3370                         }
3371                         if (cursor.par->IsLineSeparator(cursor.pos - 1))
3372                                 cursor.pos--;
3373                         
3374                         if (cursor.pos < cursor.par->Last() && !cursor.par->IsSeparator(cursor.pos)) {
3375                                 cursor.par->InsertChar(cursor.pos, ' ');
3376                                 // refresh the positions
3377                                 tmprow = row;
3378                                 while (tmprow->next && tmprow->next->par == row->par) {
3379                                         tmprow = tmprow->next;
3380                                         tmprow->pos++;
3381                                 }
3382                         }
3383                 } else {
3384                         cursor.par->Erase(cursor.pos);
3385                         
3386                         // refresh the positions
3387                         tmprow = row;
3388                         while (tmprow->next && tmprow->next->par == row->par) {
3389                                 tmprow = tmprow->next;
3390                                 tmprow->pos--;
3391                         }
3392
3393 #ifndef FIX_DOUBLE_SPACE
3394                         // delete superfluous blanks 
3395                         if (cursor.pos < cursor.par->Last() - 1 &&
3396                             (cursor.par->IsLineSeparator(cursor.pos))) {
3397                                 
3398                                 if (cursor.pos == BeginningOfMainBody(cursor.par)
3399                                     || !cursor.pos 
3400                                     || cursor.par->IsLineSeparator(cursor.pos - 1)) {
3401                                         cursor.par->Erase(cursor.pos);
3402                                         // refresh the positions
3403                                         tmprow = row;
3404                                         while (tmprow->next && 
3405                                                tmprow->next->par == row->par) {
3406                                                 tmprow = tmprow->next;
3407                                                 tmprow->pos--;
3408                                         }
3409                                         if (cursor.pos)   // move one character left
3410                                                 cursor.pos--;
3411                                 }
3412                         }
3413 #endif
3414                         
3415                         // delete newlines at the beginning of paragraphs
3416                         while (cursor.par->Last() &&
3417                                cursor.par->IsNewline(cursor.pos) &&
3418                                cursor.pos == BeginningOfMainBody(cursor.par)) {
3419                                 cursor.par->Erase(cursor.pos);
3420                                 // refresh the positions
3421                                 tmprow = row;
3422                                 while (tmprow->next && 
3423                                        tmprow->next->par == row->par) {
3424                                         tmprow = tmprow->next;
3425                                         tmprow->pos--;
3426                                 }
3427                         }
3428                 }
3429                 
3430                 // is there a break one row above
3431                 if (row->previous && row->previous->par == row->par) {
3432                         z = NextBreakPoint(row->previous, paperwidth);
3433                         if ( z >= row->pos) {
3434                                 row->pos = z + 1;
3435                                 
3436                                 tmprow = row->previous;
3437                                 
3438                                 // maybe the current row is now empty
3439                                 if (row->pos >= row->par->Last()) {
3440                                         // remove it
3441                                         RemoveRow(row);
3442                                         need_break_row = 0;
3443                                 } else {
3444                                         BreakAgainOneRow(row);
3445                                         if (row->next && row->next->par == row->par)
3446                                                 need_break_row = row->next;
3447                                         else
3448                                                 need_break_row = 0;
3449                                 }
3450                                 
3451                                 // set the dimensions of the row above
3452                                 y -= tmprow->height;
3453                                 tmprow->fill = Fill(tmprow, paperwidth);
3454                                 SetHeightOfRow(tmprow);
3455                                 
3456                                 refresh_y = y;
3457                                 refresh_row = tmprow;
3458                                 status = LyXText::NEED_MORE_REFRESH;
3459                                 current_font = rawtmpfont;
3460                                 real_current_font = realtmpfont;
3461                                 SetCursor(cursor.par, cursor.pos, false);
3462                                 // check, whether the last character's font has changed.
3463                                 rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
3464                                 if (rawparfont != rawtmpfont)
3465                                         RedoHeightOfParagraph(cursor);
3466                                 return;
3467                         }
3468                 }
3469                 
3470                 // break the cursor row again
3471                 z = NextBreakPoint(row, paperwidth);
3472                 
3473                 if (z != RowLast(row) || 
3474                     (row->next && row->next->par == row->par &&
3475                      RowLast(row) == row->par->Last() - 1)){
3476                         
3477                         /* it can happen that a paragraph loses one row
3478                          * without a real breakup. This is when a word
3479                          * is to long to be broken. Well, I don t care this 
3480                          * hack ;-) */ 
3481                         if (row->next && row->next->par == row->par &&
3482                             RowLast(row) == row->par->Last() - 1)
3483                                 RemoveRow(row->next);
3484                         
3485                         refresh_y = y;
3486                         refresh_row = row;
3487                         status = LyXText::NEED_MORE_REFRESH;
3488                         
3489                         BreakAgainOneRow(row);
3490                         current_font = rawtmpfont; 
3491                         real_current_font = realtmpfont;
3492                         SetCursor(cursor.par, cursor.pos, false);
3493                         // cursor MUST be in row now
3494                         
3495                         if (row->next && row->next->par == row->par)
3496                                 need_break_row = row->next;
3497                         else
3498                                 need_break_row = 0;
3499                 } else  {
3500                         // set the dimensions of the row
3501                         row->fill = Fill(row, paperwidth);
3502                         int tmpheight = row->height;
3503                         SetHeightOfRow(row);
3504                         if (tmpheight == row->height)
3505                                 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3506                         else
3507                                 status = LyXText::NEED_MORE_REFRESH;
3508                         refresh_y = y;
3509                         refresh_row = row;
3510                         current_font = rawtmpfont; 
3511                         real_current_font = realtmpfont;
3512                         SetCursor(cursor.par, cursor.pos, false);
3513                 }
3514         }
3515    
3516         // restore the current font
3517         // That is what a user expects!
3518         current_font = rawtmpfont; 
3519         real_current_font = realtmpfont;
3520         
3521         // check, wether the last characters font has changed.
3522         rawtmpfont = cursor.par->GetFontSettings(cursor.par->Last() - 1);
3523         if (rawparfont != rawtmpfont) {
3524                 RedoHeightOfParagraph(cursor);
3525         } else {
3526                 // now the special right address boxes
3527                 if (textclasslist.Style(parameters->textclass,
3528                                         cursor.par->GetLayout()).margintype == MARGIN_RIGHT_ADDRESS_BOX) {
3529                         RedoDrawingOfParagraph(cursor); 
3530                 }
3531         }
3532 }
3533
3534
3535 void LyXText::GetVisibleRow(int offset, 
3536                             Row * row_ptr, long y)
3537 {
3538         /* returns a printed row */
3539         Painter & pain = owner_->painter();
3540         
3541         LyXDirection direction = row_ptr->par->getParDirection();
3542         LyXParagraph::size_type vpos, pos, pos_end;
3543         float x, tmpx;
3544         int y_top, y_bottom;
3545         float fill_separator, fill_hfill, fill_label_hfill;
3546         LyXParagraph * par, * firstpar;
3547         LyXFont font;
3548         int maxdesc;
3549         if (row_ptr->height <= 0) {
3550                 lyxerr << "LYX_ERROR: row.height: " << row_ptr->height << endl;
3551                 return;
3552         }
3553         PrepareToPrint(row_ptr, x, fill_separator,
3554                        fill_hfill, fill_label_hfill);
3555         
3556         /* initialize the pixmap */
3557         
3558         pain.fillRectangle(0, offset, paperwidth, row_ptr->height);
3559         
3560         if (selection) {
3561                 /* selection code */ 
3562                 if (sel_start_cursor.row == row_ptr &&
3563                     sel_end_cursor.row == row_ptr) {
3564                         if (sel_start_cursor.x < sel_end_cursor.x)
3565                                 pain.fillRectangle(sel_start_cursor.x, offset,
3566                                                    sel_end_cursor.x - sel_start_cursor.x,
3567                                                    row_ptr->height,
3568                                                    LColor::selection);
3569                         else
3570                                 pain.fillRectangle(sel_end_cursor.x, offset,
3571                                                    sel_start_cursor.x - sel_end_cursor.x,
3572                                                    row_ptr->height,
3573                                                    LColor::selection);
3574                 } else if (sel_start_cursor.row == row_ptr) {
3575                         if (direction == LYX_DIR_LEFT_TO_RIGHT)
3576                                 pain.fillRectangle(sel_start_cursor.x, offset,
3577                                                    paperwidth - sel_start_cursor.x,
3578                                                    row_ptr->height,
3579                                                    LColor::selection);
3580                         else
3581                                 pain.fillRectangle(0, offset,
3582                                                    sel_start_cursor.x,
3583                                                    row_ptr->height,
3584                                                    LColor::selection);
3585                 } else if (sel_end_cursor.row == row_ptr) {
3586                         if (direction == LYX_DIR_LEFT_TO_RIGHT)
3587                                 pain.fillRectangle(0, offset,
3588                                                    sel_end_cursor.x,
3589                                                    row_ptr->height,
3590                                                    LColor::selection);
3591                         else
3592                                 pain.fillRectangle(sel_end_cursor.x, offset,
3593                                                    paperwidth - sel_end_cursor.x,
3594                                                    row_ptr->height,
3595                                                    LColor::selection);
3596                         
3597                 } else if (y > sel_start_cursor.y && y < sel_end_cursor.y) {
3598                         pain.fillRectangle(0, offset,
3599                                            paperwidth, row_ptr->height,
3600                                            LColor::selection);
3601                 }
3602         }
3603         
3604         if (row_ptr->par->appendix){
3605                 pain.line(1, offset,
3606                           1, offset + row_ptr->height,
3607                           LColor::appendixline);
3608                 pain.line(paperwidth - 2, offset,
3609                           paperwidth - 2, offset + row_ptr->height,
3610                           LColor::appendixline);
3611         }
3612         
3613         if (row_ptr->par->pextra_type == LyXParagraph::PEXTRA_MINIPAGE) {
3614                 /* draw a marker at the left margin! */ 
3615                 LyXFont font = GetFont(row_ptr->par, 0);
3616                 int asc = font.maxAscent();
3617                 int x = (LYX_PAPER_MARGIN - font.width('|')) / 2;
3618                 int y1 = (offset + row_ptr->baseline);
3619                 int y2 = (offset + row_ptr->baseline) - asc;
3620                 pain.line(x, y1, x, y2, LColor::minipageline);
3621         }       
3622         if (row_ptr->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
3623                 LyXFont font(LyXFont::ALL_SANE);
3624                 font.setSize(LyXFont::SIZE_FOOTNOTE);
3625                 font.setColor(LColor::footnote);
3626                 
3627                 int box_x = LYX_PAPER_MARGIN;
3628                 box_x += font.textWidth(" wide-tab ", 10);
3629                 if (row_ptr->previous && 
3630                     row_ptr->previous->par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE){
3631                         string fs;
3632                         switch (row_ptr->par->footnotekind) {
3633                         case LyXParagraph::MARGIN:
3634                                 fs = " margin";
3635                                 break;
3636                         case LyXParagraph::FIG:
3637                                 fs = " fig";
3638                                 break;
3639                         case LyXParagraph::TAB:
3640                                 fs = " tab";
3641                                 break;
3642                         case LyXParagraph::WIDE_FIG:
3643                                 fs = " wide-fig";
3644                                 break;
3645                         case LyXParagraph::WIDE_TAB:
3646                                 fs = " wide-tab";
3647                                 break;
3648                         case LyXParagraph::ALGORITHM:
3649                                 fs = " alg";
3650                                 break;
3651                         case LyXParagraph::FOOTNOTE:
3652                                 fs = " foot";
3653                                 break;
3654                         }
3655                         
3656                         pain.fillRectangle(LYX_PAPER_MARGIN,
3657                                            offset + 1,
3658                                            box_x - LYX_PAPER_MARGIN,
3659                                            int(font.maxAscent()
3660                                                + font.maxDescent()),
3661                                            LColor::footnotebg);
3662                         
3663                         pain.line(LYX_PAPER_MARGIN, offset,
3664                                   paperwidth - LYX_PAPER_MARGIN, offset,
3665                                   LColor::footnoteframe);
3666                         
3667                         pain.text(LYX_PAPER_MARGIN,
3668                                   offset + int(font.maxAscent()) + 1,
3669                                   fs, font);
3670                         
3671                         pain.line(LYX_PAPER_MARGIN, offset,
3672                                   LYX_PAPER_MARGIN,
3673                                   offset + int(font.maxAscent()
3674                                                + font.maxDescent()),
3675                                   LColor::footnoteframe);
3676                         
3677                         pain.line(LYX_PAPER_MARGIN,
3678                                   offset + int(font.maxAscent()
3679                                                + font.maxDescent()) + 1,
3680                                   box_x,
3681                                   offset + int(font.maxAscent()
3682                                                + font.maxDescent()) + 1,
3683                                   LColor::footnoteframe);
3684                         
3685                 }
3686                 
3687                 /* draw the open floats in a red box */
3688                 pain.line(box_x, offset,
3689                           box_x, offset + row_ptr->height,
3690                           LColor::footnoteframe);
3691                 
3692                 pain.line(paperwidth - LYX_PAPER_MARGIN,
3693                           offset,
3694                           paperwidth - LYX_PAPER_MARGIN,
3695                           offset + row_ptr->height,
3696                           LColor::footnoteframe);
3697         } else if (row_ptr->previous &&
3698                    row_ptr->previous->par->footnoteflag
3699                    == LyXParagraph::OPEN_FOOTNOTE) {
3700                 LyXFont font(LyXFont::ALL_SANE);
3701                 font.setSize(LyXFont::SIZE_FOOTNOTE);
3702                 
3703                 int box_x = LYX_PAPER_MARGIN;
3704                 box_x += font.textWidth(" wide-tab ", 10);
3705                 
3706                 pain.line(box_x, offset,
3707                           paperwidth - LYX_PAPER_MARGIN,
3708                           offset, LColor::footnote);
3709         }
3710         
3711         LyXLayout const & layout =
3712                 textclasslist.Style(parameters->textclass,
3713                                     row_ptr->par->GetLayout());
3714         firstpar = row_ptr->par->FirstPhysicalPar();
3715         
3716         y_top = 0;
3717         y_bottom = row_ptr->height;
3718         
3719         /* is it a first row? */ 
3720         if (row_ptr->pos == 0
3721             && row_ptr->par == firstpar) {
3722                 
3723                 /* start of appendix? */
3724                 if (row_ptr->par->start_of_appendix){
3725                         pain.line(1, offset,
3726                                   paperwidth - 2, offset,
3727                                   LColor::appendixline);
3728                 }
3729                 
3730                 /* think about the margins */ 
3731                 if (!row_ptr->previous)
3732                         y_top += LYX_PAPER_MARGIN;
3733                 
3734                 if (row_ptr->par->pagebreak_top){ /* draw a top pagebreak  */
3735                         pain.line(0, offset + y_top + 2 * DefaultHeight(),
3736                                   paperwidth,
3737                                   offset + y_top + 2 * DefaultHeight(),
3738                                   LColor::pagebreak, Painter::line_onoffdash);
3739                         y_top += 3 * DefaultHeight();
3740                 }
3741                 
3742                 if (row_ptr->par->added_space_top.kind() == VSpace::VFILL) {
3743                         /* draw a vfill top  */
3744                         pain.line(0, offset + 2 + y_top,
3745                                   LYX_PAPER_MARGIN, offset + 2 + y_top,
3746                                   LColor::vfillline);
3747                         
3748                         pain.line(0, offset + y_top + 3 * DefaultHeight(),
3749                                   LYX_PAPER_MARGIN,
3750                                   offset + y_top + 3 * DefaultHeight(),
3751                                   LColor::vfillline);
3752                         
3753                         pain.line(LYX_PAPER_MARGIN / 2, offset + 2 + y_top,
3754                                   LYX_PAPER_MARGIN / 2,
3755                                   offset + y_top + 3 * DefaultHeight(),
3756                                   LColor::vfillline);
3757                         
3758                         y_top += 3 * DefaultHeight();
3759                 }
3760                 
3761                 /* think about user added space */ 
3762                 y_top += int(row_ptr->par->added_space_top.inPixels(owner_));
3763                 
3764                 /* think about the parskip */ 
3765                 /* some parskips VERY EASY IMPLEMENTATION */ 
3766                 if (parameters->paragraph_separation == BufferParams::PARSEP_SKIP) {
3767                         if (layout.latextype == LATEX_PARAGRAPH
3768                             && firstpar->GetDepth() == 0
3769                             && firstpar->Previous())
3770                                 y_top += parameters->getDefSkip().inPixels(owner_);
3771                         else if (firstpar->Previous()
3772                                  && textclasslist.Style(parameters->textclass,
3773                                                         firstpar->Previous()->GetLayout()).latextype == LATEX_PARAGRAPH
3774                                  && firstpar->Previous()->GetDepth() == 0)
3775                                 // is it right to use defskip here, too? (AS) 
3776                                 y_top += parameters->getDefSkip().inPixels(owner_);
3777                 }
3778                 
3779                 if (row_ptr->par->line_top) {      /* draw a top line  */
3780                         y_top +=  GetFont(row_ptr->par, 0).ascent('x');
3781                         
3782                         pain.line(0, offset + y_top,
3783                                   paperwidth, offset + y_top,
3784                                   LColor::topline,
3785                                   Painter::line_solid,
3786                                   Painter::line_thick);
3787                         
3788                         y_top +=  GetFont(row_ptr->par, 0).ascent('x');
3789                 }
3790                 
3791                 /* should we print a label? */ 
3792                 if (layout.labeltype >= LABEL_STATIC
3793                     && (layout.labeltype != LABEL_STATIC
3794                         || layout.latextype != LATEX_ENVIRONMENT
3795                         || row_ptr->par->IsFirstInSequence())) {
3796                         font = GetFont(row_ptr->par, -2);
3797                         if (!row_ptr->par->GetLabestring().empty()) {
3798                                 tmpx = x;
3799                                 string tmpstring = row_ptr->par->GetLabestring();
3800                                 
3801                                 if (layout.labeltype == LABEL_COUNTER_CHAPTER) {
3802                                         if (parameters->secnumdepth >= 0){
3803                                                 /* this is special code for the chapter layout. This is printed in
3804                                                  * an extra row and has a pagebreak at the top. */
3805                                                 maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue())
3806                                                         + int(layout.parsep) * DefaultHeight();
3807                                                 if (direction == LYX_DIR_RIGHT_TO_LEFT)
3808                                                         tmpx = paperwidth - LeftMargin(row_ptr) - 
3809                                                                 font.stringWidth(tmpstring);
3810                                                 pain.text(int(tmpx),
3811                                                           offset + row_ptr->baseline - row_ptr->ascent_of_text - maxdesc,
3812                                                           tmpstring, font);
3813                                         }
3814                                 } else {
3815                                         if (direction == LYX_DIR_LEFT_TO_RIGHT)
3816                                                 tmpx = x - font.stringWidth(layout.labelsep)
3817                                                         - font.stringWidth(tmpstring);
3818                                         else {
3819                                                 tmpx = paperwidth - LeftMargin(row_ptr)
3820                                                         + font.stringWidth(layout.labelsep);
3821                                                 if (row_ptr->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)  {
3822                                                         LyXFont font(LyXFont::ALL_SANE);
3823                                                         font.setSize(LyXFont::SIZE_SMALL);
3824                                                         tmpx += font.textWidth("Mwide-figM", 10);
3825                                                 }
3826                                         }
3827                                         /* draw it! */
3828                                         pain.text(int(tmpx),
3829                                                   offset + row_ptr->baseline,
3830                                                   tmpstring, font);
3831                                 }
3832                         }
3833                         /* the labels at the top of an environment. More or less for bibliography */ 
3834                 } else if (layout.labeltype == LABEL_TOP_ENVIRONMENT ||
3835                            layout.labeltype == LABEL_BIBLIO ||
3836                            layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT) {
3837                         if (row_ptr->par->IsFirstInSequence()) {
3838                                 font = GetFont(row_ptr->par, -2);
3839                                 if (!row_ptr->par->GetLabestring().empty()) {
3840                                         string tmpstring = row_ptr->par->GetLabestring();
3841                                         
3842                                         maxdesc = int(font.maxDescent() * layout.spacing.getValue() * parameters->spacing.getValue()
3843                                                       + (layout.labelbottomsep * DefaultHeight()));
3844                                         
3845                                         tmpx = x;
3846                                         if (layout.labeltype == LABEL_CENTERED_TOP_ENVIRONMENT){
3847                                                 tmpx = ( ((direction == LYX_DIR_LEFT_TO_RIGHT)
3848                                                           ? x : LeftMargin(row_ptr) )
3849                                                          + paperwidth - RightMargin(row_ptr) ) / 2; 
3850                                                 tmpx -= (font.stringWidth(tmpstring)/2);
3851                                         } else if (direction == LYX_DIR_RIGHT_TO_LEFT)
3852                                                 tmpx = paperwidth - LeftMargin(row_ptr) - 
3853                                                         font.stringWidth(tmpstring);
3854                                         pain.text(int(tmpx),
3855                                                   offset + row_ptr->baseline
3856                                                   - row_ptr->ascent_of_text
3857                                                   - maxdesc,
3858                                                   tmpstring, font);
3859                                 }
3860                         }
3861                 }
3862                 if (layout.labeltype == LABEL_BIBLIO && row_ptr->par->bibkey) {
3863                         font = GetFont(row_ptr->par, -1);
3864                         if (direction == LYX_DIR_LEFT_TO_RIGHT)
3865                                 tmpx = x - font.stringWidth(layout.labelsep)
3866                                         - row_ptr->par->bibkey->width(owner_->painter(), font);
3867                         else
3868                                 tmpx = paperwidth - LeftMargin(row_ptr)
3869                                         + font.stringWidth(layout.labelsep);
3870                         row_ptr->par->bibkey->draw(owner_->painter(),
3871                                                    font,
3872                                                    offset + row_ptr->baseline, 
3873                                                    tmpx);
3874                 }
3875         }
3876         
3877         /* is it a last row? */
3878         par = row_ptr->par->LastPhysicalPar();
3879         if (row_ptr->par->ParFromPos(RowLast(row_ptr) + 1) == par
3880             && (!row_ptr->next || row_ptr->next->par != row_ptr->par)) {     
3881                 
3882                 /* think about the margins */ 
3883                 if (!row_ptr->next)
3884                         y_bottom -= LYX_PAPER_MARGIN;
3885                 
3886                 /* draw a bottom pagebreak */ 
3887                 if (firstpar->pagebreak_bottom) {
3888                         pain.line(0, offset + y_bottom - 2 * DefaultHeight(),
3889                                   paperwidth,
3890                                   offset + y_bottom - 2 * DefaultHeight(),
3891                                   LColor::pagebreak, Painter::line_onoffdash);
3892                         y_bottom -= 3 * DefaultHeight();
3893                 }
3894                 
3895                 if (firstpar->added_space_bottom.kind() == VSpace::VFILL) {
3896                         /* draw a vfill bottom  */
3897                         pain.line(0, offset + y_bottom - 3 * DefaultHeight(),
3898                                   LYX_PAPER_MARGIN,
3899                                   offset + y_bottom - 3 * DefaultHeight(),
3900                                   LColor::vfillline);
3901                         pain.line(0, offset + y_bottom - 2,
3902                                   LYX_PAPER_MARGIN,
3903                                   offset + y_bottom - 2,
3904                                   LColor::vfillline);
3905                         pain.line(LYX_PAPER_MARGIN / 2,
3906                                   offset + y_bottom - 3 * DefaultHeight(),
3907                                   LYX_PAPER_MARGIN / 2,
3908                                   offset + y_bottom - 2,
3909                                   LColor::vfillline);
3910                         y_bottom -= 3* DefaultHeight();
3911                 }
3912                 
3913                 /* think about user added space */ 
3914                 y_bottom -= int(firstpar->added_space_bottom.inPixels(owner_));
3915                 
3916                 if (firstpar->line_bottom) {
3917                         /* draw a bottom line */
3918                         y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3919                         pain.line(0, offset + y_bottom,
3920                                   paperwidth, offset + y_bottom,
3921                                   LColor::topline, Painter::line_solid,
3922                                   Painter::line_thick);
3923                         y_bottom -= GetFont(par, par->Last() - 1).ascent('x');
3924                 }
3925         }
3926         
3927         /* draw the text in the pixmap */  
3928         pos_end = RowLast(row_ptr);
3929         
3930         vpos = row_ptr->pos;
3931         /* table stuff -- begin*/
3932         if (row_ptr->par->table) {
3933                 bool on_off;
3934                 int cell = NumberOfCell(row_ptr->par, row_ptr->pos);
3935                 float x_old = x;
3936                 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3937                 
3938                 while (vpos <= pos_end)  {
3939                         pos = vis2log(vpos);
3940                         if (row_ptr->par->IsNewline(pos)) {
3941                                 
3942                                 x = x_old + row_ptr->par->table->WidthOfColumn(cell);
3943                                 /* draw the table lines, still very simple */
3944                                 on_off = !row_ptr->par->table->TopLine(cell);
3945                                 if ((!on_off ||
3946                                      !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
3947                                     !row_ptr->par->table->IsContRow(cell))
3948                                         pain.line(int(x_old),
3949                                                   offset + row_ptr->baseline - row_ptr->ascent_of_text,
3950                                                   int(x),
3951                                                   offset + row_ptr->baseline - row_ptr->ascent_of_text,
3952                                                   LColor::tableline,
3953                                                   on_off ? Painter::line_onoffdash : Painter::line_solid);
3954                                 
3955                                 on_off = !row_ptr->par->table->BottomLine(cell);
3956                                 if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
3957                                     row_ptr->par->table->VeryLastRow(cell))
3958                                         
3959                                         pain.line(int(x_old),
3960                                                   offset + y_bottom - 1,
3961                                                   int(x),
3962                                                   offset + y_bottom - 1,
3963                                                   LColor::tableline,
3964                                                   on_off ? Painter::line_onoffdash : Painter::line_solid);
3965                                 
3966                                 on_off = !row_ptr->par->table->LeftLine(cell);
3967                                 
3968                                 pain.line(int(x_old),
3969                                           offset + row_ptr->baseline - row_ptr->ascent_of_text,
3970                                           int(x_old),
3971                                           offset + y_bottom - 1,
3972                                           LColor::tableline,
3973                                           on_off ? Painter::line_onoffdash : Painter::line_solid);
3974                                 
3975                                 on_off = !row_ptr->par->table->RightLine(cell);
3976                                 
3977                                 pain.line(int(x) - row_ptr->par->table->AdditionalWidth(cell),
3978                                           offset + row_ptr->baseline - row_ptr->ascent_of_text,
3979                                           int(x) - row_ptr->par->table->AdditionalWidth(cell),
3980                                           offset + y_bottom - 1,
3981                                           LColor::tableline,
3982                                           on_off ? Painter::line_onoffdash : Painter::line_solid);
3983                                 
3984                                 x_old = x;
3985                                 /* take care about the alignment and other spaces */
3986                                 ++cell;
3987                                 x += row_ptr->par->table->GetBeginningOfTextInCell(cell);
3988                                 if (row_ptr->par->table->IsFirstCell(cell))
3989                                         --cell; // little hack, sorry
3990                                 ++vpos;
3991                         } else if (row_ptr->par->IsHfill(pos)) {
3992                                 x += 1;
3993                                 
3994                                 pain.line(int(x),
3995                                           offset + row_ptr->baseline - DefaultHeight() / 2,
3996                                           int(x),
3997                                           offset + row_ptr->baseline,
3998                                           LColor::vfillline);
3999                                 
4000                                 x += 2;
4001                                 ++vpos;
4002                         } else if (row_ptr->par->IsSeparator(pos)) {
4003                                 tmpx = x;
4004                                 x+= SingleWidth(row_ptr->par, pos);
4005 #warning Think about this.
4006 #if 0
4007                                 /* -------> Only draw protected spaces when
4008                                  * not in free-spacing mode. */
4009                                 if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
4010                                         pain.line(int(tmpx),
4011                                                   offset + row_ptr->baseline - 3,
4012                                                   int(tmpx),
4013                                                   offset + row_ptr->baseline - 1,
4014                                                   LColor::vfillline);
4015                                         
4016                                         pain.line(int(tmpx),
4017                                                   offset + row_ptr->baseline - 1,
4018                                                   int(x - 2),
4019                                                   offset + row_ptr->baseline - 1,
4020                                                   LColor::vfillline);
4021                                         
4022                                         pain.line(int(x - 2),
4023                                                   offset + row_ptr->baseline - 3,
4024                                                   int(x - 2),
4025                                                   offset + row_ptr->baseline - 1,
4026                                                   LColor::vfillline);
4027                                         
4028                                         /* what about underbars? */
4029                                         font = GetFont(row_ptr->par, pos); 
4030                                         if (font.underbar() == LyXFont::ON
4031                                             && font.latex() != LyXFont::ON) {
4032                                                 pain.line(int(tmpx),
4033                                                           offset + row_ptr->baseline + 2,
4034                                                           int(x - tmpx),
4035                                                           offset + row_ptr->baseline + 2);
4036                                         }
4037                                 }
4038 #endif
4039                                 ++vpos;
4040                         } else
4041                                 draw(row_ptr, vpos, offset, x);
4042                 }
4043                 
4044                 /* do not forget the very last cell. This has no NEWLINE so 
4045                  * ignored by the code above*/ 
4046                 if (cell == row_ptr->par->table->GetNumberOfCells()-1){
4047                         x = x_old + row_ptr->par->table->WidthOfColumn(cell);
4048                         on_off = !row_ptr->par->table->TopLine(cell);
4049                         if ((!on_off ||
4050                              !row_ptr->par->table->TopAlreadyDrawed(cell)) &&
4051                             !row_ptr->par->table->IsContRow(cell))
4052                                 
4053                                 pain.line(int(x_old),
4054                                           offset + row_ptr->baseline - row_ptr->ascent_of_text,
4055                                           int(x),
4056                                           offset + row_ptr->baseline - row_ptr->ascent_of_text,
4057                                           LColor::tableline,
4058                                           on_off ? Painter::line_onoffdash : Painter::line_solid);
4059                         on_off = !row_ptr->par->table->BottomLine(cell);
4060                         if ((!on_off && !row_ptr->par->table->RowHasContRow(cell)) ||
4061                             row_ptr->par->table->VeryLastRow(cell))
4062                                 
4063                                 pain.line(int(x_old),
4064                                           offset + y_bottom - 1,
4065                                           int(x),
4066                                           offset + y_bottom - 1,
4067                                           LColor::tableline,
4068                                           on_off ? Painter::line_onoffdash : Painter::line_solid);
4069                         
4070                         on_off = !row_ptr->par->table->LeftLine(cell);
4071                         
4072                         pain.line(int(x_old),
4073                                   offset + row_ptr->baseline - row_ptr->ascent_of_text,
4074                                   int(x_old),
4075                                   offset + y_bottom - 1,
4076                                   LColor::tableline,
4077                                   on_off ? Painter::line_onoffdash : Painter::line_solid);
4078                         
4079                         on_off = !row_ptr->par->table->RightLine(cell);
4080                         
4081                         pain.line(int(x) - row_ptr->par->table->AdditionalWidth(cell),
4082                                   offset + row_ptr->baseline - row_ptr->ascent_of_text,
4083                                   int(x) - row_ptr->par->table->AdditionalWidth(cell),
4084                                   offset + y_bottom - 1,
4085                                   LColor::tableline,
4086                                   on_off ? Painter::line_onoffdash : Painter::line_solid);
4087                 }
4088         } else {
4089                 /* table stuff -- end*/
4090                 LyXParagraph::size_type main_body = 
4091                         BeginningOfMainBody(row_ptr->par);
4092                 if (main_body > 0 &&
4093                     (main_body-1 > pos_end || 
4094                      !row_ptr->par->IsLineSeparator(main_body-1)))
4095                         main_body = 0;
4096                 
4097                 while (vpos <= pos_end)  {
4098                         pos = vis2log(vpos);
4099                         if (main_body > 0 && pos == main_body-1) {
4100                                 x += fill_label_hfill
4101                                         + GetFont(row_ptr->par, -2).stringWidth(layout.labelsep)
4102                                         - SingleWidth(row_ptr->par, main_body-1);
4103                         }
4104                         
4105                         if (row_ptr->par->IsHfill(pos)) {
4106                                 x += 1;
4107                                 pain.line(int(x),
4108                                           offset + row_ptr->baseline - DefaultHeight() / 2,
4109                                           int(x),
4110                                           offset + row_ptr->baseline,
4111                                           LColor::vfillline);
4112                                 
4113                                 if (HfillExpansion(row_ptr, pos)) {
4114                                         if (pos >= main_body) {
4115                                                 pain.line(int(x),
4116                                                           offset + row_ptr->baseline - DefaultHeight() / 4,
4117                                                           int(x + fill_hfill),
4118                                                           offset + row_ptr->baseline - DefaultHeight() / 4,
4119                                                           LColor::vfillline,
4120                                                           Painter::line_onoffdash);
4121                                                 x += fill_hfill;
4122                                         } else {
4123                                                 pain.line(int(x),
4124                                                           offset + row_ptr->baseline - DefaultHeight() / 4,
4125                                                           int(x + fill_label_hfill),
4126                                                           offset + row_ptr->baseline - DefaultHeight() / 4,
4127                                                           LColor::vfillline,
4128                                                           Painter::line_onoffdash);
4129                                                 
4130                                                 x += fill_label_hfill;
4131                                         }
4132                                         pain.line(int(x),
4133                                                   offset + row_ptr->baseline - DefaultHeight() / 2,
4134                                                   int(x),
4135                                                   offset + row_ptr->baseline,
4136                                                   LColor::vfillline);
4137                                 }
4138                                 x += 2;
4139                                 ++vpos;
4140                         } else if (row_ptr->par->IsSeparator(pos)) {
4141                                 tmpx = x;
4142                                 x+= SingleWidth(row_ptr->par, pos);
4143                                 if (pos >= main_body)
4144                                         x+= fill_separator;
4145 #warning Think about this
4146 #if 0
4147                                 /* -------> Only draw protected spaces when
4148                                  * not in free-spacing mode. */
4149                                 if (row_ptr->par->GetChar(pos) == LyXParagraph::META_PROTECTED_SEPARATOR && !layout.free_spacing) {
4150                                         
4151                                         pain.line(int(tmpx),
4152                                                   offset + row_ptr->baseline - 3,
4153                                                   int(tmpx),
4154                                                   offset + row_ptr->baseline - 1,
4155                                                   LColor::vfillline);
4156                                         
4157                                         pain.line(int(tmpx),
4158                                                   offset + row_ptr->baseline - 1,
4159                                                   int(x - 2),
4160                                                   offset + row_ptr->baseline - 1,
4161                                                   LColor::vfillline);
4162                                         
4163                                         pain.line(int(x - 2),
4164                                                   offset + row_ptr->baseline - 3,
4165                                                   int(x - 2),
4166                                                   offset + row_ptr->baseline - 1,
4167                                                   LColor::vfillline);
4168                                         
4169                                         /* what about underbars? */
4170                                         font = GetFont(row_ptr->par, pos); 
4171                                         if (font.underbar() == LyXFont::ON
4172                                             && font.latex() != LyXFont::ON) {
4173                                                 pain.line(int(tmpx),
4174                                                           offset + row_ptr->baseline + 2,
4175                                                           int(x - tmpx),
4176                                                           offset + row_ptr->baseline + 2);
4177                                         }
4178                                 }
4179 #endif
4180                                 ++vpos;
4181                         } else
4182                                 draw(row_ptr, vpos, offset, x);
4183                 }
4184         }
4185 }
4186
4187
4188 int LyXText::DefaultHeight() const
4189 {
4190         LyXFont font(LyXFont::ALL_SANE);
4191         return int(font.maxAscent() + font.maxDescent() * 1.5);
4192 }
4193
4194    
4195 /* returns the column near the specified x-coordinate of the row 
4196 * x is set to the real beginning of this column  */ 
4197 int LyXText::GetColumnNearX(Row * row, int & x) const
4198 {
4199         float tmpx = 0.0;
4200         float fill_separator, fill_hfill, fill_label_hfill;
4201    
4202         PrepareToPrint(row, tmpx, fill_separator,
4203                        fill_hfill, fill_label_hfill);
4204
4205         LyXDirection direction = row->par->getParDirection();
4206         LyXParagraph::size_type vc = row->pos;
4207         LyXParagraph::size_type last = RowLast(row);
4208         LyXParagraph::size_type c = 0;
4209
4210         LyXLayout const & layout = textclasslist.Style(parameters->textclass,
4211                                                        row->par->GetLayout());
4212         /* table stuff -- begin */
4213         if (row->par->table) {
4214                 if (row->next && row->next->par == row->par //the last row doesn't need a newline at the end
4215                     && row->par->IsNewline(last))
4216                         last--;
4217                 int cell = NumberOfCell(row->par, row->pos);
4218                 float x_old = tmpx;
4219                 bool ready = false;
4220                 tmpx += row->par->table->GetBeginningOfTextInCell(cell);
4221                 while (vc <= last
4222                        && (c = vis2log(vc)) >= 0
4223                        && tmpx + (SingleWidth(row->par, c)/2) <= x
4224                        && !ready){
4225                         if (row->par->IsNewline(c)) {
4226                                 if (x_old + row->par->table->WidthOfColumn(cell) <= x){
4227                                         tmpx = x_old + row->par->table->WidthOfColumn(cell);
4228                                         x_old = tmpx;
4229                                         ++cell;
4230                                         tmpx += row->par->table->GetBeginningOfTextInCell(cell);
4231                                         ++vc;
4232                                 } else
4233                                         ready = true;
4234                         } else {
4235                                 tmpx += SingleWidth(row->par, c);
4236                                 ++vc;
4237                         }
4238                 }
4239         } else {
4240                 /* table stuff -- end*/
4241                 LyXParagraph::size_type main_body = BeginningOfMainBody(row->par);
4242                 float last_tmpx = tmpx;
4243
4244                 if (main_body > 0 &&
4245                     (main_body-1 > last || 
4246                      !row->par->IsLineSeparator(main_body-1)))
4247                         main_body = 0;
4248
4249                 while (vc <= last && tmpx <= x) {
4250                         c = vis2log(vc);
4251                         last_tmpx = tmpx;
4252                         if (main_body > 0 && c == main_body-1) {
4253                                 tmpx += fill_label_hfill +
4254                                         GetFont(row->par, -2).stringWidth(layout.labelsep);
4255                                 if (row->par->IsLineSeparator(main_body-1))
4256                                         tmpx -= SingleWidth(row->par, main_body-1);
4257                         }
4258              
4259                         tmpx += SingleWidth(row->par, c);
4260                         if (HfillExpansion(row, c)) {
4261                                 if (c >= main_body)
4262                                         tmpx += fill_hfill;
4263                                 else
4264                                         tmpx += fill_label_hfill;
4265                         }
4266                         else if (c >= main_body
4267                                  && row->par->IsSeparator(c)) {
4268                                 tmpx+= fill_separator;  
4269                         }
4270                         ++vc;
4271                 }
4272
4273                 if (vc > row->pos && (tmpx+last_tmpx)/2 > x) {
4274                         vc--;
4275                         tmpx = last_tmpx;
4276                 }
4277         }
4278         /* make sure that a last space in a row doesnt count */
4279         if (row->pos <= last
4280             && !(!row->next || row->next->par != row->par))
4281                 if (direction == LYX_DIR_LEFT_TO_RIGHT && vc > last
4282                     && row->par->IsLineSeparator(vis2log(last)) ) {
4283                         vc = last;
4284                         tmpx -= fill_separator+SingleWidth(row->par, vis2log(last));
4285                 } else if (direction == LYX_DIR_RIGHT_TO_LEFT 
4286                            && vc == row->pos
4287                            && row->par->IsLineSeparator(vis2log(row->pos)) ) {
4288                         vc = row->pos+1;
4289                         tmpx += fill_separator+SingleWidth(row->par, vis2log(row->pos));
4290                 }
4291
4292         if (row->pos > last)  // Row is empty?
4293                 c = row->pos;
4294         else if (vc <= last) {
4295                 c = vis2log(vc);
4296                 LyXDirection direction = row->par->getLetterDirection(c);
4297                 if (vc > row->pos && row->par->IsLineSeparator(c)
4298                     && row->par->getLetterDirection(vis2log(vc - 1)) != direction)
4299                         c = vis2log(vc-1);
4300                 if (direction == LYX_DIR_RIGHT_TO_LEFT)
4301                         ++c;
4302         } else {
4303                 c = vis2log(last)+1;
4304                 if (row->par->getLetterDirection(c - 1) == LYX_DIR_RIGHT_TO_LEFT)
4305                         --c;            
4306         }
4307
4308         if (!row->par->table && row->pos <= last && c > last
4309             && row->par->IsNewline(last)) {
4310                 if (row->par->getLetterDirection(last) == LYX_DIR_LEFT_TO_RIGHT)
4311                         tmpx -= SingleWidth(row->par, last);
4312                 else
4313                         tmpx += SingleWidth(row->par, last);
4314                 c = last;
4315         }
4316
4317         c -= row->pos;
4318         x = int(tmpx);
4319         return c;
4320 }
4321
4322    
4323 /* turn the selection into a new environment. If there is no selection,
4324 * create an empty environment */ 
4325 void LyXText::InsertFootnoteEnvironment(LyXParagraph::footnote_kind kind)
4326 {
4327    /* no footnoteenvironment in a footnoteenvironment */ 
4328    if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
4329       WriteAlert(_("Impossible operation"), 
4330                  _("You can't insert a float in a float!"), 
4331                  _("Sorry."));
4332      return;
4333    }
4334    /* no marginpars in minipages */
4335    if (kind == LyXParagraph::MARGIN 
4336       && cursor.par->pextra_type == LyXParagraph::PEXTRA_MINIPAGE) {
4337       WriteAlert(_("Impossible operation"), 
4338                  _("You can't insert a marginpar in a minipage!"), 
4339                  _("Sorry."));
4340       return;
4341    }
4342    
4343    /* this doesnt make sense, if there is no selection */ 
4344    bool dummy_selection = false;
4345    if (!selection) {
4346       sel_start_cursor = cursor;       /* dummy selection  */
4347       sel_end_cursor = cursor;
4348       dummy_selection = true;
4349    }
4350    
4351    LyXParagraph *tmppar;
4352
4353    if (sel_start_cursor.par->table || sel_end_cursor.par->table){
4354       WriteAlert(_("Impossible operation"), _("Cannot cut table."), _("Sorry."));
4355       return;
4356    }
4357      
4358    /* a test to make sure there is not already a footnote
4359     * in the selection. */
4360    
4361    tmppar = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
4362    
4363    while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos) && 
4364           tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
4365      tmppar = tmppar->next;
4366    
4367    if (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
4368        || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
4369       WriteAlert(_("Impossible operation"), 
4370                  _("Float would include float!"), 
4371                  _("Sorry."));
4372       return;
4373    }
4374    
4375    /* ok we have a selection. This is always between sel_start_cursor
4376     * and sel_end cursor */
4377
4378    SetUndo(Undo::FINISH, 
4379            sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous, 
4380            sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next); 
4381    
4382    if (sel_end_cursor.pos > 0 
4383        && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1))
4384      sel_end_cursor.pos--;             /* please break before a space at
4385                                         * the end */
4386    if (sel_start_cursor.par == sel_end_cursor.par
4387        && sel_start_cursor.pos > sel_end_cursor.pos)
4388      sel_start_cursor.pos--;
4389
4390    sel_end_cursor.par->BreakParagraphConservative(sel_end_cursor.pos);
4391    
4392    sel_end_cursor.par = sel_end_cursor.par->Next();
4393    sel_end_cursor.pos = 0;
4394    
4395    // don't forget to insert a dummy layout paragraph if necessary
4396    if (sel_start_cursor.par->GetLayout() != sel_end_cursor.par->layout){
4397      sel_end_cursor.par->BreakParagraphConservative(0);
4398      sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
4399      sel_end_cursor.par = sel_end_cursor.par->next;
4400    }
4401    else
4402      sel_end_cursor.par->layout = LYX_DUMMY_LAYOUT;
4403
4404    cursor = sel_end_cursor;
4405
4406    /* please break behind a space, if there is one. The space should
4407     * be erased too */ 
4408    if (sel_start_cursor.pos > 0 
4409        && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos - 1))
4410      sel_start_cursor.pos--;
4411    if (sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)) {
4412       sel_start_cursor.par->Erase(sel_start_cursor.pos);
4413    }
4414    
4415    sel_start_cursor.par->BreakParagraphConservative(sel_start_cursor.pos);
4416    tmppar = sel_start_cursor.par->Next();
4417    
4418    if (dummy_selection) {
4419            tmppar->Clear();
4420            if (kind == LyXParagraph::TAB
4421                || kind == LyXParagraph::FIG 
4422                || kind == LyXParagraph::WIDE_TAB
4423                || kind == LyXParagraph::WIDE_FIG 
4424                || kind == LyXParagraph::ALGORITHM) {
4425                    pair<bool, LyXTextClass::size_type> lres =
4426                            textclasslist.NumberOfLayout(parameters->textclass,
4427                                                         "Caption");
4428                    LyXTextClass::size_type lay;
4429                    if (lres.first) {
4430                            // layout fount
4431                            lay = lres.second;
4432                    } else {
4433                            // layout not found
4434                            lay = 0; // use default layout "Standard" (0)
4435                    }
4436                    tmppar->SetLayout(lay);
4437            }
4438    }
4439    else {
4440      if (sel_start_cursor.pos > 0) {
4441        /* the footnote-environment should begin with a standard layout.
4442         * Imagine you insert a footnote within an enumeration, you 
4443         * certainly do not want an enumerated footnote! */ 
4444        tmppar->Clear();
4445      }
4446      else {
4447        /* this is a exception the user would sometimes expect, I hope */
4448        sel_start_cursor.par->Clear();
4449      }
4450    }
4451    
4452    while (tmppar != sel_end_cursor.par) {
4453       tmppar->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
4454       tmppar->footnotekind = kind;
4455       tmppar = tmppar->Next();
4456    } 
4457
4458    RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
4459    
4460    SetCursor(sel_start_cursor.par->Next(), 0);
4461
4462    ClearSelection();
4463 }
4464    
4465
4466 // returns pointer to a specified row
4467 Row * LyXText::GetRow(LyXParagraph * par,
4468                       LyXParagraph::size_type pos, long & y) const
4469 {
4470         Row * tmprow;
4471
4472         if (currentrow) {
4473                 if (par == currentrow->par
4474                     || par == currentrow->par->Previous()) {
4475                         // do not dereference par, it may have been deleted
4476                         // already! (Matthias)
4477
4478                         // Walk backwards as long as the previous
4479                         // rows par is not par
4480                         while (currentrow->previous
4481                                && currentrow->previous->par != par) {
4482                                 currentrow = currentrow->previous;
4483                                 currentrow_y -= currentrow->height;
4484                         }
4485                         // Walk backwards as long as the previous
4486                         // rows par _is_ par
4487                         while (currentrow->previous
4488                                && currentrow->previous->par == par) {
4489                                 currentrow = currentrow->previous;
4490                                 currentrow_y -= currentrow->height;
4491                         }
4492                 }
4493
4494                 tmprow = currentrow;
4495                 y = currentrow_y;
4496                 // find the first row of the specified paragraph
4497                 while (tmprow->next
4498                        && tmprow->par != par) {
4499                         y += tmprow->height;
4500                         tmprow = tmprow->next;
4501                 }
4502                 
4503                 if (tmprow->par == par){
4504                         // now find the wanted row
4505                         while (tmprow->pos < pos
4506                                && tmprow->next
4507                                && tmprow->next->par == par
4508                                && tmprow->next->pos <= pos) {
4509                                 y += tmprow->height;
4510                                 tmprow = tmprow->next;
4511                         }
4512                         currentrow = tmprow;
4513                         currentrow_y = y;
4514                         return tmprow;
4515                 }
4516         }
4517
4518         tmprow = firstrow;
4519         y = 0;
4520         // find the first row of the specified paragraph
4521         while (tmprow->next && tmprow->par != par) {
4522                 y += tmprow->height;
4523                 tmprow = tmprow->next;
4524         }
4525         
4526         // now find the wanted row
4527         while (tmprow->pos < pos
4528                && tmprow->next
4529                && tmprow->next->par == par
4530                && tmprow->next->pos <= pos) {
4531                 y += tmprow->height;
4532                 tmprow = tmprow->next;
4533         }
4534         
4535         currentrow = tmprow;
4536         currentrow_y = y;
4537         
4538         return tmprow;
4539 }