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