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