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