]> git.lyx.org Git - lyx.git/blob - src/text2.C
Changes to make text-inset work better (f.ex. cursor), and now we have
[lyx.git] / src / text2.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
13 #include FORMS_H_LOCATION
14
15
16 #ifdef __GNUG__
17 #pragma implementation "lyxtext.h"
18 #endif
19
20 #include "LString.h"
21 #include "lyxparagraph.h"
22 #include "insets/inseterror.h"
23 #include "insets/insetbib.h"
24 #include "insets/insetspecialchar.h"
25 #include "layout.h"
26 #include "LyXView.h"
27 #include "support/textutils.h"
28 #include "undo.h"
29 #include "minibuffer.h"
30 #include "buffer.h"
31 #include "bufferparams.h"
32 #include "lyx_gui_misc.h"
33 #include "lyxtext.h"
34 #include "gettext.h"
35 #include "BufferView.h"
36 #include "LyXView.h"
37 #include "lyxrow.h"
38 #include "CutAndPaste.h"
39 #include "Painter.h"
40 #include "font.h"
41 #include "debug.h"
42
43 //#define USE_OLD_CUT_AND_PASTE 1
44
45 using std::copy;
46 using std::endl;
47 using std::pair;
48
49 LyXText::LyXText(BufferView * bv)
50 {
51         bv_owner = bv;
52         inset_owner = 0;
53         init();
54 }
55
56
57 LyXText::LyXText(InsetText * inset)
58 {
59         inset_owner = inset;
60         bv_owner = 0;
61         init();
62 }
63
64
65 void LyXText::init()
66 {
67         firstrow = 0;
68         lastrow = 0;
69         number_of_rows = 0;
70         refresh_y = 0;
71         height = width = 0;
72         status = LyXText::UNCHANGED;
73         // set cursor at the very top position
74         selection = true;           /* these setting is necessary 
75                                        because of the delete-empty-
76                                        paragraph mechanism in
77                                        SetCursor */
78         if (bv_owner) {
79                 LyXParagraph * par = OwnerParagraph();
80                 current_font = GetFont(bv_owner->buffer(), par, 0);
81                 while (par) {
82                         InsertParagraph(bv_owner, par, lastrow);
83                         par = par->Next();
84                 }
85                 SetCursor(bv_owner, firstrow->par(), 0);
86         } else
87                 current_font = LyXFont(LyXFont::ALL_SANE);
88
89         sel_cursor = cursor;
90         selection = false;
91         mark_set = false;
92    
93         // no rebreak necessary
94         need_break_row = 0;
95    
96         undo_finished = true;
97         undo_frozen = false;
98
99         // Default layouttype for copy environment type
100         copylayouttype = 0;
101
102 #if 0
103         // Dump all rowinformation:
104         Row * tmprow = firstrow;
105         lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
106         while (tmprow) {
107                 lyxerr << tmprow->baseline() << '\t'
108                        << tmprow->par << '\t'
109                        << tmprow->pos() << '\t'
110                        << tmprow->height << '\t'
111                        << tmprow->ascent_of_text << '\t'
112                        << tmprow->fill << '\n';
113                 tmprow = tmprow->next();
114         }
115         lyxerr.flush();
116 #endif
117 }
118
119
120 void LyXText::init(BufferView * bview)
121 {
122         if (firstrow)
123                 return;
124
125         LyXParagraph * par = OwnerParagraph();
126         current_font = GetFont(bview->buffer(), par, 0);
127         while (par) {
128                 InsertParagraph(bview, par, lastrow);
129                 par = par->Next();
130         }
131         SetCursorIntern(bview, firstrow->par(), 0);
132 #if 1
133         // Dump all rowinformation:
134         Row * tmprow = firstrow;
135         lyxerr << "Width = " << width << endl;
136         lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
137         while (tmprow) {
138                 lyxerr << tmprow->baseline() << '\t'
139                        << tmprow->par() << '\t'
140                        << tmprow->pos() << '\t'
141                        << tmprow->height() << '\t'
142                        << tmprow->ascent_of_text() << '\t'
143                        << tmprow->fill() << '\n';
144                 tmprow = tmprow->next();
145         }
146         lyxerr.flush();
147 #endif
148 }
149
150 LyXText::~LyXText()
151 {
152         // Delete all rows, this does not touch the paragraphs!
153         Row * tmprow = firstrow;
154         while (firstrow) {
155                 tmprow = firstrow->next();
156                 delete firstrow;
157                 firstrow = tmprow;
158         }
159 }
160
161
162 #if 0
163 void LyXText::owner(BufferView * bv)
164 {
165         if (bv_owner && bv) lyxerr << "LyXText::bv_owner already set!" << endl;
166         bv_owner = bv;
167 }
168 #endif
169
170 // Gets the fully instantiated font at a given position in a paragraph
171 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
172 // The difference is that this one is used for displaying, and thus we
173 // are allowed to make cosmetic improvements. For instance make footnotes
174 // smaller. (Asger)
175 // If position is -1, we get the layout font of the paragraph.
176 // If position is -2, we get the font of the manual label of the paragraph.
177 LyXFont LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
178                          LyXParagraph::size_type pos) const
179 {
180         LyXLayout const & layout = 
181                 textclasslist.Style(buf->params.textclass, par->GetLayout());
182
183         char par_depth = par->GetDepth();
184         // We specialize the 95% common case:
185         if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
186                 if (pos >= 0){
187                         // 95% goes here
188                         if (layout.labeltype == LABEL_MANUAL
189                             && pos < BeginningOfMainBody(buf, par)) {
190                                 // 1% goes here
191                                 return par->GetFontSettings(buf->params, pos).
192                                         realize(layout.reslabelfont);
193                         } else
194                                 return par->GetFontSettings(buf->params, pos).
195                                         realize(layout.resfont);
196                 } else {
197                         // 5% goes here.
198                         // process layoutfont for pos == -1 and labelfont for pos < -1
199                         if (pos == -1)
200                                 return layout.resfont;
201                         else
202                                 return layout.reslabelfont;
203                 }
204         }
205
206         // The uncommon case need not be optimized as much
207
208         LyXFont layoutfont, tmpfont;
209
210         if (pos >= 0){
211                 // 95% goes here
212                 if (pos < BeginningOfMainBody(buf, par)) {
213                         // 1% goes here
214                         layoutfont = layout.labelfont;
215                 } else {
216                         // 99% goes here
217                         layoutfont = layout.font;
218                 }
219                 tmpfont = par->GetFontSettings(buf->params, pos);
220                 tmpfont.realize(layoutfont);
221         } else {
222                 // 5% goes here.
223                 // process layoutfont for pos == -1 and labelfont for pos < -1
224                 if (pos == -1)
225                         tmpfont = layout.font;
226                 else
227                         tmpfont = layout.labelfont;
228         }
229
230         // Resolve against environment font information
231         while (par && par_depth && !tmpfont.resolved()) {
232                 par = par->DepthHook(par_depth - 1);
233                 if (par) {
234                         tmpfont.realize(textclasslist.
235                                         Style(buf->params.textclass,
236                                               par->GetLayout()).font);
237                         par_depth = par->GetDepth();
238                 }
239         }
240
241         tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
242
243         // Cosmetic improvement: If this is an open footnote, make the font 
244         // smaller.
245         if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
246             && par->footnotekind == LyXParagraph::FOOTNOTE) {
247                 tmpfont.decSize();
248         }
249
250         return tmpfont;
251 }
252
253
254 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
255                           LyXParagraph::size_type pos,
256                           LyXFont const & fnt)
257 {
258         LyXFont font(fnt);
259         // Let the insets convert their font
260         if (par->GetChar(pos) == LyXParagraph::META_INSET) {
261                 if (par->GetInset(pos))
262                         font = par->GetInset(pos)->ConvertFont(font);
263         }
264
265         LyXLayout const & layout =
266                 textclasslist.Style(buf->params.textclass,
267                                     par->GetLayout());
268
269         // Get concrete layout font to reduce against
270         LyXFont layoutfont;
271
272         if (pos < BeginningOfMainBody(buf, par))
273                 layoutfont = layout.labelfont;
274         else
275                 layoutfont = layout.font;
276
277         // Realize against environment font information
278         if (par->GetDepth()){
279                 LyXParagraph * tp = par;
280                 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
281                         tp = tp->DepthHook(tp->GetDepth()-1);
282                         if (tp)
283                                 layoutfont.realize(textclasslist.
284                                                 Style(buf->params.textclass,
285                                                       tp->GetLayout()).font);
286                 }
287         }
288
289         layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
290
291         if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
292             && par->footnotekind == LyXParagraph::FOOTNOTE) {
293                 layoutfont.decSize();
294         }
295
296         // Now, reduce font against full layout font
297         font.reduce(layoutfont);
298
299         par->SetFont(pos, font);
300 }
301
302
303 /* inserts a new row behind the specified row, increments
304  * the touched counters */
305 void LyXText::InsertRow(Row * row, LyXParagraph * par,
306                         LyXParagraph::size_type pos) const
307 {
308         Row * tmprow = new Row;
309         if (!row) {
310                 tmprow->previous(0);
311                 tmprow->next(firstrow);
312                 firstrow = tmprow;
313         } else {
314                 tmprow->previous(row);
315                 tmprow->next(row->next());
316                 row->next(tmprow);
317         }
318    
319         if (tmprow->next())
320                 tmprow->next()->previous(tmprow);
321    
322         if (tmprow->previous())
323                 tmprow->previous()->next(tmprow);
324    
325    
326         tmprow->par(par);
327         tmprow->pos(pos);
328
329         if (row == lastrow)
330                 lastrow = tmprow;
331         ++number_of_rows; // one more row
332 }
333
334
335 // removes the row and reset the touched counters
336 void LyXText::RemoveRow(Row * row) const
337 {
338         /* this must not happen before the currentrow for clear reasons.
339            so the trick is just to set the current row onto the previous
340            row of this row */
341         long unused_y;
342         GetRow(row->par(), row->pos(), unused_y);
343    
344         if (row->next())
345                 row->next()->previous(row->previous());
346         if (!row->previous()) {
347                 firstrow = row->next();
348         } else  {
349                 row->previous()->next(row->next());
350         }
351         if (row == lastrow)
352                 lastrow = row->previous();
353    
354         height -= row->height(); // the text becomes smaller
355    
356         delete row;
357         --number_of_rows;       // one row less
358 }
359
360
361 // remove all following rows of the paragraph of the specified row.
362 void LyXText::RemoveParagraph(Row * row) const
363 {
364         LyXParagraph * tmppar = row->par();
365         row = row->next();
366     
367         Row * tmprow;
368         while (row && row->par() == tmppar) {
369                 tmprow = row->next();
370                 RemoveRow(row);
371                 row = tmprow;
372         }
373 }
374    
375
376 // insert the specified paragraph behind the specified row
377 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
378                               Row * row) const
379 {
380         InsertRow(row, par, 0);        /* insert a new row, starting 
381                                         * at postition 0 */
382
383         SetCounter(bview->buffer(), par);  // set the counters
384    
385         // and now append the whole paragraph behind the new row
386         if (!row) {
387                 firstrow->height(0);
388                 AppendParagraph(bview, firstrow);
389         } else {
390                 row->next()->height(0);
391                 AppendParagraph(bview, row->next());
392         }
393 }
394     
395
396 void LyXText::ToggleFootnote(BufferView * bview)
397 {
398         LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
399         if (par->next
400             && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
401                 OpenFootnote(bview);
402                 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
403         } else {
404                 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
405                 CloseFootnote(bview);
406         }
407 }
408
409
410 void LyXText::OpenStuff(BufferView * bview)
411 {
412         if (cursor.pos() == 0 && cursor.par()->bibkey){
413                 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
414         }
415         else if (cursor.pos() < cursor.par()->Last() 
416                  && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
417                  && cursor.par()->GetInset(cursor.pos())->Editable()) {
418                 bview->owner()->getMiniBuffer()
419                         ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
420                 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
421                         SetCursorParUndo(bview->buffer());
422                 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
423         } else {
424                 ToggleFootnote(bview);
425         }
426 }
427
428
429 void LyXText::CloseFootnote(BufferView * bview)
430 {
431         LyXParagraph * tmppar;
432         LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
433    
434         // if the cursor is not in an open footnote, or 
435         // there is no open footnote in this paragraph, just return.
436         if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
437       
438                 if (!par->next ||
439                     par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
440                         bview->owner()->getMiniBuffer()
441                                 ->Set(_("Nothing to do"));
442                         return;
443                 }
444    
445                 // ok, move the cursor right before the footnote
446                 // just a little faster than using CursorRight()
447                 for (cursor.pos(0);
448                      cursor.par()->ParFromPos(cursor.pos()) != par;) {
449                                 cursor.pos(cursor.pos() + 1);
450                         }
451                 
452                 // now the cursor is at the beginning of the physical par
453                 SetCursor(bview, cursor.par(),
454                           cursor.pos() +
455                           cursor.par()->ParFromPos(cursor.pos())->size());
456         } else  {
457                 /* we are in a footnote, so let us move at the beginning */ 
458                 /* this is just faster than using just CursorLeft() */ 
459        
460                 tmppar = cursor.par();
461                 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
462                         // just a little bit faster than movin the cursor
463                         tmppar = tmppar->Previous();
464                 }
465                 SetCursor(bview, tmppar, tmppar->Last());
466         }
467    
468         // the cursor must be exactly before the footnote
469         par = cursor.par()->ParFromPos(cursor.pos());
470    
471         status = LyXText::NEED_MORE_REFRESH;
472         refresh_row = cursor.row();
473         refresh_y = cursor.y() - cursor.row()->baseline();
474    
475         tmppar = cursor.par();
476         LyXParagraph * endpar = par->NextAfterFootnote()->Next();
477         Row * row = cursor.row();
478    
479         tmppar->CloseFootnote(cursor.pos());
480
481         while (tmppar != endpar) {
482                 RemoveRow(row->next());
483                 if (row->next())
484                         tmppar = row->next()->par();
485                 else
486                         tmppar = 0;
487         }
488    
489         AppendParagraph(bview, cursor.row());
490    
491         SetCursor(bview, cursor.par(), cursor.pos());
492         sel_cursor = cursor;
493    
494         // just necessary
495         if (cursor.row()->next())
496                 SetHeightOfRow(bview, cursor.row()->next());
497 }
498
499
500 /* used in setlayout */
501 // Asger is not sure we want to do this...
502 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf, LyXParagraph * par)
503 {
504    
505         LyXLayout const & layout =
506                 textclasslist.Style(buf->params.textclass, par->GetLayout());
507
508         LyXFont layoutfont, tmpfont;
509         for (LyXParagraph::size_type pos = 0;
510              pos < par->Last(); ++pos) {
511                 if (pos < BeginningOfMainBody(buf, par))
512                         layoutfont = layout.labelfont;
513                 else
514                         layoutfont = layout.font;
515       
516                 tmpfont = par->GetFontSettings(buf->params, pos);
517                 tmpfont.reduce(layoutfont);
518                 par->SetFont(pos, tmpfont);
519         }
520 }
521
522 LyXParagraph * LyXText::SetLayout(BufferView * bview,
523                                   LyXCursor & cur, LyXCursor & sstart_cur,
524                                   LyXCursor & send_cur,
525                                   LyXTextClass::size_type layout)
526 {
527         LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
528         LyXParagraph * undoendpar = endpar;
529
530         if (endpar && endpar->GetDepth()) {
531                 while (endpar && endpar->GetDepth()) {
532                         endpar = endpar->LastPhysicalPar()->Next();
533                         undoendpar = endpar;
534                 }
535         } else if (endpar) {
536                 endpar = endpar->Next(); // because of parindents etc.
537         }
538    
539         SetUndo(bview->buffer(), Undo::EDIT,
540                 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous, 
541                 undoendpar);
542
543         /* ok we have a selection. This is always between sstart_cur
544          * and sel_end cursor */ 
545         cur = sstart_cur;
546    
547         LyXLayout const & lyxlayout =
548                 textclasslist.Style(bview->buffer()->params.textclass, layout);
549    
550         while (cur.par() != send_cur.par()) {
551                 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
552                         cur.par()->SetLayout(bview->buffer()->params, layout);
553                         MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
554                         LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
555                         fppar->added_space_top = lyxlayout.fill_top ?
556                                 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
557                         fppar->added_space_bottom = lyxlayout.fill_bottom ? 
558                                 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE); 
559                         if (lyxlayout.margintype == MARGIN_MANUAL)
560                                 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
561                         if (lyxlayout.labeltype != LABEL_BIBLIO
562                             && fppar->bibkey) {
563                                 delete fppar->bibkey;
564                                 fppar->bibkey = 0;
565                         }
566                 }
567                 cur.par(cur.par()->Next());
568         }
569         if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
570                 cur.par()->SetLayout(bview->buffer()->params, layout);
571                 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
572                 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
573                 fppar->added_space_top = lyxlayout.fill_top ?
574                         VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
575                 fppar->added_space_bottom = lyxlayout.fill_bottom ? 
576                         VSpace(VSpace::VFILL) : VSpace(VSpace::NONE); 
577                 if (lyxlayout.margintype == MARGIN_MANUAL)
578                         cur.par()->SetLabelWidthString(lyxlayout.labelstring());
579                 if (lyxlayout.labeltype != LABEL_BIBLIO
580                     && fppar->bibkey) {
581                         delete fppar->bibkey;
582                         fppar->bibkey = 0;
583                 }
584         }
585         return endpar;
586 }
587
588 // set layout over selection and make a total rebreak of those paragraphs
589 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
590 {
591         LyXCursor
592                 tmpcursor = cursor;  /* store the current cursor  */
593
594 #ifdef USE_OLD_SET_LAYOUT
595         // if there is no selection just set the layout
596         // of the current paragraph  */
597         if (!selection) {
598                 sel_start_cursor = cursor;  // dummy selection
599                 sel_end_cursor = cursor;
600         }
601
602         LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
603         LyXParagraph * undoendpar = endpar;
604
605         if (endpar && endpar->GetDepth()) {
606                 while (endpar && endpar->GetDepth()) {
607                         endpar = endpar->LastPhysicalPar()->Next();
608                         undoendpar = endpar;
609                 }
610         }
611         else if (endpar) {
612                 endpar = endpar->Next(); // because of parindents etc.
613         }
614    
615         SetUndo(Undo::EDIT, 
616                 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous, 
617                 undoendpar);
618
619         /* ok we have a selection. This is always between sel_start_cursor
620          * and sel_end cursor */ 
621         cursor = sel_start_cursor;
622    
623         LyXLayout const & lyxlayout =
624                 textclasslist.Style(bview->buffer()->params.textclass, layout);
625    
626         while (cursor.par() != sel_end_cursor.par()) {
627                 if (cursor.par()->footnoteflag ==
628                     sel_start_cursor.par()->footnoteflag) {
629                         cursor.par()->SetLayout(layout);
630                         MakeFontEntriesLayoutSpecific(cursor.par());
631                         LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
632                         fppar->added_space_top = lyxlayout.fill_top ?
633                                 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
634                         fppar->added_space_bottom = lyxlayout.fill_bottom ? 
635                                 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE); 
636                         if (lyxlayout.margintype == MARGIN_MANUAL)
637                                 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
638                         if (lyxlayout.labeltype != LABEL_BIBLIO
639                             && fppar->bibkey) {
640                                 delete fppar->bibkey;
641                                 fppar->bibkey = 0;
642                         }
643                 }
644                 cursor.par() = cursor.par()->Next();
645         }
646         if (cursor.par()->footnoteflag ==
647             sel_start_cursor.par()->footnoteflag) {
648                 cursor.par()->SetLayout(layout);
649                 MakeFontEntriesLayoutSpecific(cursor.par());
650                 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
651                 fppar->added_space_top = lyxlayout.fill_top ?
652                         VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
653                 fppar->added_space_bottom = lyxlayout.fill_bottom ? 
654                         VSpace(VSpace::VFILL) : VSpace(VSpace::NONE); 
655                 if (lyxlayout.margintype == MARGIN_MANUAL)
656                         cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
657                 if (lyxlayout.labeltype != LABEL_BIBLIO
658                     && fppar->bibkey) {
659                         delete fppar->bibkey;
660                         fppar->bibkey = 0;
661                 }
662         }
663 #else
664         // if there is no selection just set the layout
665         // of the current paragraph  */
666         if (!selection) {
667                 sel_start_cursor = cursor;  // dummy selection
668                 sel_end_cursor = cursor;
669         }
670         LyXParagraph *
671                 endpar = SetLayout(bview, cursor, sel_start_cursor,
672                                    sel_end_cursor, layout);
673 #endif
674         RedoParagraphs(bview, sel_start_cursor, endpar);
675    
676         // we have to reset the selection, because the
677         // geometry could have changed */ 
678         SetCursor(bview, sel_start_cursor.par(),
679                   sel_start_cursor.pos(), false);
680         sel_cursor = cursor;
681         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
682                   false);
683         UpdateCounters(bview, cursor.row());
684         ClearSelection();
685         SetSelection();
686         SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
687 }
688
689
690 // increment depth over selection and
691 // make a total rebreak of those paragraphs
692 void  LyXText::IncDepth(BufferView * bview)
693 {
694         // If there is no selection, just use the current paragraph
695         if (!selection) {
696                 sel_start_cursor = cursor; // dummy selection
697                 sel_end_cursor = cursor;
698         }
699
700         // We end at the next paragraph with depth 0
701         LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
702         LyXParagraph * undoendpar = endpar;
703
704         if (endpar && endpar->GetDepth()) {
705                 while (endpar && endpar->GetDepth()) {
706                         endpar = endpar->LastPhysicalPar()->Next();
707                         undoendpar = endpar;
708                 }
709         }
710         else if (endpar) {
711                 endpar = endpar->Next(); // because of parindents etc.
712         }
713         
714         SetUndo(bview->buffer(), Undo::EDIT, 
715                 sel_start_cursor
716                 .par()->ParFromPos(sel_start_cursor.pos())->previous, 
717                 undoendpar);
718
719         LyXCursor tmpcursor = cursor; // store the current cursor
720
721         // ok we have a selection. This is always between sel_start_cursor
722         // and sel_end cursor
723         cursor = sel_start_cursor;
724    
725         bool anything_changed = false;
726    
727         while (true) {
728                 // NOTE: you can't change the depth of a bibliography entry
729                 if (cursor.par()->footnoteflag ==
730                     sel_start_cursor.par()->footnoteflag
731                     && textclasslist.Style(bview->buffer()->params.textclass,
732                                       cursor.par()->GetLayout()
733                                      ).labeltype != LABEL_BIBLIO) {
734                         LyXParagraph * prev =
735                                 cursor.par()->FirstPhysicalPar()->Previous();
736                         if (prev 
737                             && (prev->GetDepth() - cursor.par()->GetDepth() > 0
738                                 || (prev->GetDepth() == cursor.par()->GetDepth()
739                                     && textclasslist.Style(bview->buffer()->params.textclass,
740                                                       prev->GetLayout()).isEnvironment()))) {
741                                 cursor.par()->FirstPhysicalPar()->depth++;
742                                 anything_changed = true;
743                                 }
744                 }
745                 if (cursor.par() == sel_end_cursor.par())
746                        break;
747                 cursor.par(cursor.par()->Next());
748         }
749    
750         // if nothing changed set all depth to 0
751         if (!anything_changed) {
752                 cursor = sel_start_cursor;
753                 while (cursor.par() != sel_end_cursor.par()) {
754                         cursor.par()->FirstPhysicalPar()->depth = 0;
755                         cursor.par(cursor.par()->Next());
756                 }
757                 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
758                         cursor.par()->FirstPhysicalPar()->depth = 0;
759         }
760    
761         RedoParagraphs(bview, sel_start_cursor, endpar);
762    
763         // we have to reset the selection, because the
764         // geometry could have changed
765         SetCursor(bview, sel_start_cursor.par(),
766                   sel_start_cursor.pos());
767         sel_cursor = cursor;
768         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
769         UpdateCounters(bview, cursor.row());
770         ClearSelection();
771         SetSelection();
772         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
773 }
774
775
776 // decrement depth over selection and
777 // make a total rebreak of those paragraphs
778 void  LyXText::DecDepth(BufferView * bview)
779 {
780         // if there is no selection just set the layout
781         // of the current paragraph
782         if (!selection) {
783                 sel_start_cursor = cursor; // dummy selection
784                 sel_end_cursor = cursor;
785         }
786    
787         LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
788         LyXParagraph * undoendpar = endpar;
789
790         if (endpar && endpar->GetDepth()) {
791                 while (endpar && endpar->GetDepth()) {
792                         endpar = endpar->LastPhysicalPar()->Next();
793                         undoendpar = endpar;
794                 }
795         }
796         else if (endpar) {
797                 endpar = endpar->Next(); // because of parindents etc.
798         }
799    
800         SetUndo(bview->buffer(), Undo::EDIT, 
801                 sel_start_cursor
802                 .par()->ParFromPos(sel_start_cursor.pos())->previous, 
803                 undoendpar);
804
805         LyXCursor tmpcursor = cursor; // store the current cursor
806
807         // ok we have a selection. This is always between sel_start_cursor
808         // and sel_end cursor
809         cursor = sel_start_cursor;
810
811         while (true) {
812                 if (cursor.par()->footnoteflag ==
813                     sel_start_cursor.par()->footnoteflag) {
814                         if (cursor.par()->FirstPhysicalPar()->depth)
815                                 cursor.par()->FirstPhysicalPar()->depth--;
816                 }
817                 if (cursor.par() == sel_end_cursor.par())
818                         break;
819                 cursor.par(cursor.par()->Next());
820         }
821
822         RedoParagraphs(bview, sel_start_cursor, endpar);
823    
824         // we have to reset the selection, because the
825         // geometry could have changed
826         SetCursor(bview, sel_start_cursor.par(),
827                   sel_start_cursor.pos());
828         sel_cursor = cursor;
829         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
830         UpdateCounters(bview, cursor.row());
831         ClearSelection();
832         SetSelection();
833         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
834 }
835
836
837 // set font over selection and make a total rebreak of those paragraphs
838 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
839 {
840         // if there is no selection just set the current_font
841         if (!selection) {
842                 // Determine basis font
843                 LyXFont layoutfont;
844                 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
845                                                        cursor.par()))
846                         layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
847                 else
848                         layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
849                 // Update current font
850                 real_current_font.update(font,
851                                          bview->buffer()->params.language_info,
852                                          toggleall);
853
854                 // Reduce to implicit settings
855                 current_font = real_current_font;
856                 current_font.reduce(layoutfont);
857                 // And resolve it completely
858                 real_current_font.realize(layoutfont);
859                 return;
860         }
861
862         LyXCursor tmpcursor = cursor; // store the current cursor
863    
864         // ok we have a selection. This is always between sel_start_cursor
865         // and sel_end cursor
866    
867         SetUndo(bview->buffer(), Undo::EDIT, 
868                 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous, 
869                 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next); 
870         cursor = sel_start_cursor;
871         while (cursor.par() != sel_end_cursor.par() ||
872                (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag
873                 && cursor.pos() < sel_end_cursor.pos())) 
874         {
875                 if (cursor.pos() < cursor.par()->Last()
876                     && cursor.par()->footnoteflag
877                     == sel_start_cursor.par()->footnoteflag) {
878                         // an open footnote should behave
879                         // like a closed one
880                         LyXFont newfont = GetFont(bview->buffer(), 
881                                                   cursor.par(), cursor.pos());
882                         newfont.update(font,
883                                        bview->buffer()->params.language_info,
884                                        toggleall);
885                         SetCharFont(bview->buffer(),
886                                     cursor.par(), cursor.pos(), newfont);
887                         cursor.pos(cursor.pos() + 1);
888                 } else {
889                         cursor.pos(0);
890                         cursor.par(cursor.par()->Next());
891                 }
892         }
893    
894         RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
895    
896         // we have to reset the selection, because the
897         // geometry could have changed
898         SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
899         sel_cursor = cursor;
900         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
901         ClearSelection();
902         SetSelection();
903         SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
904                   tmpcursor.boundary());
905 }
906
907
908 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
909 {
910         Row * tmprow = cur.row();
911         long y = cur.y() - tmprow->baseline();
912
913         SetHeightOfRow(bview, tmprow);
914         LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
915         // find the first row of the paragraph
916         if (first_phys_par != tmprow->par())
917                 while (tmprow->previous()
918                        && tmprow->previous()->par() != first_phys_par) {
919                         tmprow = tmprow->previous();
920                         y -= tmprow->height();
921                         SetHeightOfRow(bview, tmprow);
922                 }
923         while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
924                 tmprow = tmprow->previous();
925                 y -= tmprow->height();
926                 SetHeightOfRow(bview, tmprow);
927         }
928         
929         // we can set the refreshing parameters now
930         status = LyXText::NEED_MORE_REFRESH;
931         refresh_y = y;
932         refresh_row = tmprow;
933         SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
934 }
935
936
937 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
938 {
939         Row * tmprow = cur.row();
940    
941         long y = cur.y() - tmprow->baseline();
942         SetHeightOfRow(bview, tmprow);
943         LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
944         // find the first row of the paragraph
945         if (first_phys_par != tmprow->par())
946                 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par)  {
947                         tmprow = tmprow->previous();
948                         y -= tmprow->height();
949                 }
950         while (tmprow->previous() && tmprow->previous()->par() == first_phys_par)  {
951                 tmprow = tmprow->previous();
952                 y -= tmprow->height();
953         }
954    
955         // we can set the refreshing parameters now
956         if (status == LyXText::UNCHANGED || y < refresh_y) {
957                 refresh_y = y;
958                 refresh_row = tmprow;
959         }
960         status = LyXText::NEED_MORE_REFRESH;
961         SetCursor(bview, cur.par(), cur.pos());
962 }
963
964
965 /* deletes and inserts again all paragaphs between the cursor
966 * and the specified par 
967 * This function is needed after SetLayout and SetFont etc. */
968 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
969                              LyXParagraph const * endpar) const
970 {
971         Row * tmprow2;
972         LyXParagraph * tmppar = 0, * first_phys_par = 0;
973    
974         Row * tmprow = cur.row();
975    
976         long y = cur.y() - tmprow->baseline();
977    
978         if (!tmprow->previous()){
979                 first_phys_par = FirstParagraph();   // a trick/hack for UNDO
980         } else {
981                 first_phys_par = tmprow->par()->FirstPhysicalPar();
982                 // find the first row of the paragraph
983                 if (first_phys_par != tmprow->par())
984                         while (tmprow->previous() &&
985                                (tmprow->previous()->par() != first_phys_par)) {
986                                 tmprow = tmprow->previous();
987                                 y -= tmprow->height();
988                         }
989                 while (tmprow->previous()
990                        && tmprow->previous()->par() == first_phys_par) {
991                         tmprow = tmprow->previous();
992                         y -= tmprow->height();
993                 }
994         }
995    
996         // we can set the refreshing parameters now
997         status = LyXText::NEED_MORE_REFRESH;
998         refresh_y = y;
999         refresh_row = tmprow->previous();        /* the real refresh row will
1000                                             be deleted, so I store
1001                                             the previous here */ 
1002         // remove it
1003         if (tmprow->next())
1004                 tmppar = tmprow->next()->par();
1005         else
1006                 tmppar = 0;
1007         while (tmppar != endpar) {
1008                 RemoveRow(tmprow->next());
1009                 if (tmprow->next())
1010                         tmppar = tmprow->next()->par();
1011                 else
1012                         tmppar = 0;
1013         }  
1014    
1015         // remove the first one
1016         tmprow2 = tmprow;     /* this is because tmprow->previous()
1017                                  can be 0 */
1018         tmprow = tmprow->previous();
1019         RemoveRow(tmprow2);
1020    
1021         tmppar = first_phys_par;
1022
1023         do {
1024                 if (tmppar) {
1025                         InsertParagraph(bview, tmppar, tmprow);
1026                         if (!tmprow)
1027                                 tmprow = firstrow;
1028                         while (tmprow->next() && tmprow->next()->par() == tmppar)
1029                                 tmprow = tmprow->next();
1030                         tmppar = tmppar->Next();
1031                 }
1032         } while (tmppar != endpar);
1033    
1034         // this is because of layout changes
1035         if (refresh_row) {
1036                 refresh_y -= refresh_row->height();
1037                 SetHeightOfRow(bview, refresh_row);   
1038         } else {
1039                 refresh_row = firstrow;
1040                 refresh_y = 0;
1041                 SetHeightOfRow(bview, refresh_row);   
1042         }
1043    
1044         if (tmprow && tmprow->next())
1045                 SetHeightOfRow(bview, tmprow->next());
1046 }
1047
1048
1049 bool LyXText::FullRebreak(BufferView * bview)
1050 {
1051         if (need_break_row) {
1052                 BreakAgain(bview, need_break_row);
1053                 need_break_row = 0;
1054                 return true;
1055         }
1056         return false;
1057 }
1058
1059
1060 /* important for the screen */
1061
1062
1063 /* the cursor set functions have a special mechanism. When they
1064  * realize, that you left an empty paragraph, they will delete it.
1065  * They also delete the corresponding row */
1066    
1067 // need the selection cursor:
1068 void LyXText::SetSelection()
1069 {
1070         if (!selection) {
1071                 last_sel_cursor = sel_cursor;
1072                 sel_start_cursor = sel_cursor;
1073                 sel_end_cursor = sel_cursor;
1074         }
1075    
1076         selection = true;
1077    
1078         // first the toggling area
1079         if (cursor.y() < last_sel_cursor.y()
1080             || (cursor.y() == last_sel_cursor.y()
1081              && cursor.x() < last_sel_cursor.x())) {
1082                 toggle_end_cursor = last_sel_cursor;
1083                 toggle_cursor = cursor;
1084         } else {
1085                 toggle_end_cursor = cursor;
1086                 toggle_cursor = last_sel_cursor;
1087         }
1088    
1089         last_sel_cursor = cursor;
1090    
1091         // and now the whole selection
1092
1093         if (sel_cursor.par() == cursor.par())
1094            if (sel_cursor.pos() < cursor.pos()) {
1095                 sel_end_cursor = cursor;
1096                 sel_start_cursor = sel_cursor;
1097         } else {
1098                 sel_end_cursor = sel_cursor; 
1099                 sel_start_cursor = cursor;
1100         }
1101         else if (sel_cursor.y() < cursor.y() ||
1102             (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1103                 sel_end_cursor = cursor;
1104                 sel_start_cursor = sel_cursor;
1105         }
1106         else {
1107                 sel_end_cursor = sel_cursor; 
1108                 sel_start_cursor = cursor;
1109         }
1110    
1111         // a selection with no contents is not a selection
1112         if (sel_start_cursor.par() == sel_end_cursor.par() && 
1113             sel_start_cursor.pos() == sel_end_cursor.pos())
1114                 selection = false;
1115 }
1116
1117
1118 string LyXText::selectionAsString(Buffer const * buffer) const
1119 {
1120         if (!selection) return string();
1121         string result;
1122         
1123         // Special handling if the whole selection is within one paragraph
1124         if (sel_start_cursor.par() == sel_end_cursor.par()) {
1125                 result += sel_start_cursor.par()->String(buffer,
1126                                                          sel_start_cursor.pos(),
1127                                                          sel_end_cursor.pos());
1128                 return result;
1129         }
1130         
1131         // The selection spans more than one paragraph
1132
1133         // First paragraph in selection
1134         result += sel_start_cursor.par()->String(buffer,
1135                                                  sel_start_cursor.pos(),
1136                                                  sel_start_cursor.par()->Last())
1137                 + "\n\n";
1138         
1139         // The paragraphs in between (if any)
1140         LyXCursor tmpcur(sel_start_cursor);
1141         tmpcur.par(tmpcur.par()->Next());
1142         while (tmpcur.par() != sel_end_cursor.par()) {
1143                 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1144                 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1145         }
1146
1147         // Last paragraph in selection
1148         result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1149         
1150         return result;
1151 }
1152
1153
1154 void LyXText::ClearSelection() const
1155 {
1156         selection = false;
1157         mark_set = false;
1158 }
1159
1160
1161 void LyXText::CursorHome(BufferView * bview) const
1162 {
1163         SetCursor(bview, cursor.par(), cursor.row()->pos());
1164 }
1165
1166
1167 void LyXText::CursorEnd(BufferView * bview) const
1168 {
1169         if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1170                 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1171         else {
1172                 if (cursor.par()->Last() && 
1173                     (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1174                      || cursor.par()->IsNewline(RowLast(cursor.row()))))
1175                         SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1176                 else
1177                         SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1178         }
1179 #ifndef NEW_TABULAR
1180         if (cursor.par()->table) {
1181                 int cell = NumberOfCell(cursor.par(), cursor.pos());
1182                 if (cursor.par()->table->RowHasContRow(cell) &&
1183                     cursor.par()->table->CellHasContRow(cell)<0) {
1184                         if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1185                                 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1186                         else {
1187                                 if (cursor.par()->Last() && 
1188                                     (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1189                                      || cursor.par()->IsNewline(RowLast(cursor.row()))))
1190                                         SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1191                                 else
1192                                         SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1193                         }
1194                 }
1195         }
1196 #endif
1197 }
1198
1199
1200 void  LyXText::CursorTop(BufferView * bview) const
1201 {
1202         while (cursor.par()->Previous())
1203                 cursor.par(cursor.par()->Previous());
1204         SetCursor(bview, cursor.par(), 0);
1205 }
1206
1207
1208 void  LyXText::CursorBottom(BufferView * bview) const
1209 {
1210         while (cursor.par()->Next())
1211                 cursor.par(cursor.par()->Next());
1212         SetCursor(bview, cursor.par(), cursor.par()->Last());
1213 }
1214    
1215    
1216 /* returns a pointer to the row near the specified y-coordinate
1217 * (relative to the whole text). y is set to the real beginning
1218 * of this row */
1219 Row * LyXText::GetRowNearY(long & y) const
1220 {
1221         Row * tmprow = firstrow;
1222         long tmpy = 0;
1223
1224         while (tmprow->next() && tmpy + tmprow->height() <= y) {
1225                 tmpy += tmprow->height();
1226                 tmprow = tmprow->next();
1227         }
1228
1229         y = tmpy;   // return the real y
1230         return tmprow;
1231 }
1232
1233
1234 void LyXText::ToggleFree(BufferView * bview, LyXFont const & font, bool toggleall)
1235 {
1236         // If the mask is completely neutral, tell user
1237         if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1238                 // Could only happen with user style
1239                 bview->owner()->getMiniBuffer()
1240                         ->Set(_("No font change defined. Use Character under"
1241                                 " the Layout menu to define font change."));
1242                 return;
1243         }
1244
1245         // Try implicit word selection
1246         // If there is a change in the language the implicit word selection 
1247         // is disabled.
1248         LyXCursor resetCursor = cursor;
1249         bool implicitSelection = (font.language() == ignore_language)
1250                 ? SelectWordWhenUnderCursor(bview) : false;
1251
1252         // Set font
1253         SetFont(bview, font, toggleall);
1254
1255         /* Implicit selections are cleared afterwards and cursor is set to the
1256            original position. */
1257         if (implicitSelection) {
1258                 ClearSelection();
1259                 cursor = resetCursor;
1260                 SetCursor(bview, cursor.par(), cursor.pos());
1261                 sel_cursor = cursor;
1262         }
1263 }
1264
1265
1266 LyXParagraph::size_type
1267 LyXText::BeginningOfMainBody(Buffer const * buf, LyXParagraph const * par) const
1268 {
1269         if (textclasslist.Style(buf->params.textclass,
1270                                 par->GetLayout()).labeltype != LABEL_MANUAL)
1271                 return 0;
1272         else
1273                 return par->BeginningOfMainBody();
1274 }
1275
1276
1277 /* if there is a selection, reset every environment you can find
1278 * in the selection, otherwise just the environment you are in */ 
1279 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1280 {
1281         LyXParagraph * tmppar, * firsttmppar;
1282    
1283         ClearSelection();
1284    
1285         /* is is only allowed, if the cursor is IN an open footnote.
1286          * Otherwise it is too dangerous */ 
1287         if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1288                 return;
1289    
1290         SetUndo(bview->buffer(), Undo::FINISH, 
1291                 cursor.par()->PreviousBeforeFootnote()->previous,
1292                 cursor.par()->NextAfterFootnote()->next);
1293
1294         /* ok, move to the beginning of the footnote. */ 
1295         while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1296                 cursor.par(cursor.par()->Previous());
1297    
1298         SetCursor(bview, cursor.par(), cursor.par()->Last());
1299         /* this is just faster than using CursorLeft(); */ 
1300    
1301         firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1302         tmppar = firsttmppar;
1303         /* tmppar is now the paragraph right before the footnote */
1304
1305         bool first_footnote_par_is_not_empty = tmppar->next->size();
1306    
1307         while (tmppar->next
1308                && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1309                 tmppar = tmppar->next;   /* I use next instead of Next(),
1310                                           * because there cannot be any
1311                                           * footnotes in a footnote
1312                                           * environment */
1313                 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1314       
1315                 /* remember the captions and empty paragraphs */
1316                 if ((textclasslist.Style(bview->buffer()->params.textclass,
1317                                          tmppar->GetLayout())
1318                      .labeltype == LABEL_SENSITIVE)
1319                     || !tmppar->Last())
1320                         tmppar->SetLayout(bview->buffer()->params, 0);
1321         }
1322    
1323         // now we will paste the ex-footnote, if the layouts allow it
1324         // first restore the layout of the paragraph right behind
1325         // the footnote
1326         if (tmppar->next) 
1327                 tmppar->next->MakeSameLayout(cursor.par());
1328
1329         // first the end
1330         if ((!tmppar->GetLayout() && !tmppar->table)
1331             || (tmppar->Next()
1332                 && (!tmppar->Next()->Last()
1333                     || tmppar->Next()->HasSameLayout(tmppar)))) {
1334                 if (tmppar->Next()->Last()
1335                     && tmppar->Next()->IsLineSeparator(0))
1336                         tmppar->Next()->Erase(0);
1337                 tmppar->PasteParagraph(bview->buffer()->params);
1338         }
1339
1340         tmppar = tmppar->Next();  /* make sure tmppar cannot be touched
1341                                    * by the pasting of the beginning */
1342
1343         /* then the beginning */ 
1344         /* if there is no space between the text and the footnote, so we insert
1345          * a blank 
1346          * (only if the previous par and the footnotepar are not empty!) */
1347         if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1348             || firsttmppar->HasSameLayout(firsttmppar->next)) {
1349                 if (firsttmppar->size()
1350                     && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1351                     && first_footnote_par_is_not_empty) {
1352                         firsttmppar->next->InsertChar(0, ' ');
1353                 }
1354                 firsttmppar->PasteParagraph(bview->buffer()->params);
1355         }
1356    
1357         /* now redo the paragaphs */
1358         RedoParagraphs(bview, cursor, tmppar);
1359    
1360         SetCursor(bview, cursor.par(), cursor.pos());
1361    
1362         /* sometimes it can happen, that there is a counter change */ 
1363         Row * row = cursor.row();
1364         while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1365                 row = row->next();
1366         UpdateCounters(bview, row);
1367    
1368    
1369         ClearSelection();
1370 }
1371
1372
1373 /* the DTP switches for paragraphs. LyX will store them in the 
1374 * first physicla paragraph. When a paragraph is broken, the top settings 
1375 * rest, the bottom settings are given to the new one. So I can make shure, 
1376 * they do not duplicate themself and you cannnot make dirty things with 
1377 * them!  */ 
1378
1379 void LyXText::SetParagraph(BufferView * bview,
1380                            bool line_top, bool line_bottom,
1381                            bool pagebreak_top, bool pagebreak_bottom,
1382                            VSpace const & space_top,
1383                            VSpace const & space_bottom,
1384                            LyXAlignment align, 
1385                            string labelwidthstring,
1386                            bool noindent) 
1387 {
1388         LyXCursor tmpcursor = cursor;
1389         if (!selection) {
1390                 sel_start_cursor = cursor;
1391                 sel_end_cursor = cursor;
1392         }
1393
1394         // make sure that the depth behind the selection are restored, too
1395         LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1396         LyXParagraph * undoendpar = endpar;
1397
1398         if (endpar && endpar->GetDepth()) {
1399                 while (endpar && endpar->GetDepth()) {
1400                         endpar = endpar->LastPhysicalPar()->Next();
1401                         undoendpar = endpar;
1402                 }
1403         }
1404         else if (endpar) {
1405                 endpar = endpar->Next(); // because of parindents etc.
1406         }
1407    
1408         SetUndo(bview->buffer(), Undo::EDIT, 
1409                 sel_start_cursor
1410                 .par()->ParFromPos(sel_start_cursor.pos())->previous, 
1411                 undoendpar);
1412
1413         
1414         LyXParagraph * tmppar = sel_end_cursor.par();
1415         while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1416                 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1417                 status = LyXText::NEED_MORE_REFRESH;
1418                 refresh_row = cursor.row();
1419                 refresh_y = cursor.y() - cursor.row()->baseline();
1420                 if (cursor.par()->footnoteflag ==
1421                     sel_start_cursor.par()->footnoteflag) {
1422                         cursor.par()->line_top = line_top;
1423                         cursor.par()->line_bottom = line_bottom;
1424                         cursor.par()->pagebreak_top = pagebreak_top;
1425                         cursor.par()->pagebreak_bottom = pagebreak_bottom;
1426                         cursor.par()->added_space_top = space_top;
1427                         cursor.par()->added_space_bottom = space_bottom;
1428                         // does the layout allow the new alignment?
1429                         if (align == LYX_ALIGN_LAYOUT)
1430                                 align = textclasslist
1431                                         .Style(bview->buffer()->params.textclass,
1432                                                cursor.par()->GetLayout()).align;
1433                         if (align & textclasslist
1434                             .Style(bview->buffer()->params.textclass,
1435                                    cursor.par()->GetLayout()).alignpossible) {
1436                                 if (align == textclasslist
1437                                     .Style(bview->buffer()->params.textclass,
1438                                            cursor.par()->GetLayout()).align)
1439                                         cursor.par()->align = LYX_ALIGN_LAYOUT;
1440                                 else
1441                                         cursor.par()->align = align;
1442                         }
1443                         cursor.par()->SetLabelWidthString(labelwidthstring);
1444                         cursor.par()->noindent = noindent;
1445                 }
1446                 
1447                 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1448         }
1449         
1450         RedoParagraphs(bview, sel_start_cursor, endpar);
1451         
1452         ClearSelection();
1453         SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1454         sel_cursor = cursor;
1455         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1456         SetSelection();
1457         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1458 }
1459
1460
1461 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1462                                    char const * width,
1463                                    char const * widthp,
1464                                    int alignment, bool hfill,
1465                                    bool start_minipage)
1466 {
1467         LyXCursor tmpcursor = cursor;
1468         LyXParagraph * tmppar;
1469         if (!selection) {
1470                 sel_start_cursor = cursor;
1471                 sel_end_cursor = cursor;
1472         }
1473
1474         // make sure that the depth behind the selection are restored, too
1475         LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1476         LyXParagraph * undoendpar = endpar;
1477
1478         if (endpar && endpar->GetDepth()) {
1479                 while (endpar && endpar->GetDepth()) {
1480                         endpar = endpar->LastPhysicalPar()->Next();
1481                         undoendpar = endpar;
1482                 }
1483         }
1484         else if (endpar) {
1485                 endpar = endpar->Next(); // because of parindents etc.
1486         }
1487    
1488         SetUndo(bview->buffer(), Undo::EDIT, 
1489                 sel_start_cursor
1490                 .par()->ParFromPos(sel_start_cursor.pos())->previous, 
1491                 undoendpar);
1492         
1493         tmppar = sel_end_cursor.par();
1494         while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1495                 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1496                 status = LyXText::NEED_MORE_REFRESH;
1497                 refresh_row = cursor.row();
1498                 refresh_y = cursor.y() - cursor.row()->baseline();
1499                 if (cursor.par()->footnoteflag ==
1500                     sel_start_cursor.par()->footnoteflag) {
1501                         if (type == LyXParagraph::PEXTRA_NONE) {
1502                                 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1503                                         cursor.par()->UnsetPExtraType(bview->buffer()->params);
1504                                         cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1505                                 }
1506                         } else {
1507                                 cursor.par()->SetPExtraType(bview->buffer()->params,
1508                                                           type, width, widthp);
1509                                 cursor.par()->pextra_hfill = hfill;
1510                                 cursor.par()->pextra_start_minipage = start_minipage;
1511                                 cursor.par()->pextra_alignment = alignment;
1512                         }
1513                 }
1514                 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1515         }
1516         RedoParagraphs(bview, sel_start_cursor, endpar);
1517         ClearSelection();
1518         SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1519         sel_cursor = cursor;
1520         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1521         SetSelection();
1522         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1523 }
1524
1525
1526 char loweralphaCounter(int n)
1527 {
1528         if (n < 1 || n > 26)
1529                 return '?';
1530         else
1531                 return 'a' + n - 1;
1532 }
1533
1534 char alphaCounter(int n)
1535 {
1536         if (n < 1 || n > 26)
1537                 return '?';
1538         else
1539                 return 'A' + n - 1;
1540 }
1541
1542 char hebrewCounter(int n)
1543 {
1544         static const char hebrew[22] = {
1545                 'à', 'á', 'â', 'ã', 'ä', 'Ã¥', 'æ', 'ç', 'è',
1546                 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö', 
1547                 '÷', 'ø', 'ù', 'ú'
1548         };
1549         if (n < 1 || n > 22)
1550                 return '?';
1551         else
1552                 return hebrew[n-1];
1553 }
1554
1555 static char const * romanCounter(int n)
1556 {
1557         static char const * roman[20] = {
1558                 "i",   "ii",  "iii", "iv", "v",
1559                 "vi",  "vii", "viii", "ix", "x",
1560                 "xi",  "xii", "xiii", "xiv", "xv",
1561                 "xvi", "xvii", "xviii", "xix", "xx"
1562         };
1563         if (n < 1 || n > 20)
1564                 return "??";
1565         else
1566                 return roman[n-1];
1567 }
1568
1569 // set the counter of a paragraph. This includes the labels
1570 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1571 {
1572         // this is only relevant for the beginning of paragraph
1573         par = par->FirstPhysicalPar();
1574
1575         LyXLayout const & layout =
1576                 textclasslist.Style(buf->params.textclass, 
1577                                     par->GetLayout());
1578
1579         LyXTextClass const & textclass =
1580                 textclasslist.TextClass(buf->params.textclass);
1581
1582         /* copy the prev-counters to this one, unless this is the start of a 
1583            footnote or of a bibliography or the very first paragraph */
1584         if (par->Previous()
1585             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1586                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1587                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1588             && !(textclasslist.Style(buf->params.textclass,
1589                                 par->Previous()->GetLayout()
1590                                 ).labeltype != LABEL_BIBLIO
1591                  && layout.labeltype == LABEL_BIBLIO)) {
1592                 for (int i = 0; i < 10; ++i) {
1593                         par->setCounter(i, par->Previous()->GetFirstCounter(i));
1594                 }
1595                 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1596                 if (!par->appendix && par->start_of_appendix){
1597                   par->appendix = true;
1598                   for (int i = 0; i < 10; ++i) {
1599                     par->setCounter(i, 0);
1600                   }  
1601                 }
1602                 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1603                 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1604         }
1605         else {
1606                 for (int i = 0; i < 10; ++i) {
1607                         par->setCounter(i, 0);
1608                 }  
1609                 par->appendix = par->start_of_appendix;
1610                 par->enumdepth = 0;
1611                 par->itemdepth = 0;
1612         }
1613
1614         // if this is an open marginnote and this is the first
1615         // entry in the marginnote and the enclosing
1616         // environment is an enum/item then correct for the
1617         // LaTeX behaviour (ARRae)
1618         if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1619            && par->footnotekind == LyXParagraph::MARGIN
1620            && par->Previous()
1621            && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1622            && (par->PreviousBeforeFootnote()
1623                && textclasslist.Style(buf->params.textclass,
1624                                  par->PreviousBeforeFootnote()->GetLayout()
1625                                  ).labeltype >= LABEL_COUNTER_ENUMI)) {
1626                 // Any itemize or enumerate environment in a marginnote
1627                 // that is embedded in an itemize or enumerate
1628                 // paragraph is seen by LaTeX as being at a deeper
1629                 // level within that enclosing itemization/enumeration
1630                 // even if there is a "standard" layout at the start of
1631                 // the marginnote.
1632                 par->enumdepth++;
1633                 par->itemdepth++;
1634         }
1635
1636         /* Maybe we have to increment the enumeration depth.
1637          * BUT, enumeration in a footnote is considered in isolation from its
1638          *      surrounding paragraph so don't increment if this is the
1639          *      first line of the footnote
1640          * AND, bibliographies can't have their depth changed ie. they
1641          *      are always of depth 0
1642          */
1643         if (par->Previous()
1644             && par->Previous()->GetDepth() < par->GetDepth()
1645             && textclasslist.Style(buf->params.textclass,
1646                               par->Previous()->GetLayout()
1647                              ).labeltype == LABEL_COUNTER_ENUMI
1648             && par->enumdepth < 3
1649             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE 
1650                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1651                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1652             && layout.labeltype != LABEL_BIBLIO) {
1653                 par->enumdepth++;
1654         }
1655
1656         /* Maybe we have to decrement the enumeration depth, see note above */
1657         if (par->Previous()
1658             && par->Previous()->GetDepth() > par->GetDepth()
1659             && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1660                     && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1661                     && par->footnotekind == LyXParagraph::FOOTNOTE)
1662             && layout.labeltype != LABEL_BIBLIO) {
1663                 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1664                 par->setCounter(6 + par->enumdepth,
1665                         par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1666                 /* reset the counters.
1667                  * A depth change is like a breaking layout
1668                  */
1669                 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1670                         par->setCounter(i, 0);
1671         }
1672    
1673         if (!par->labelstring.empty()) {
1674                 par->labelstring.erase();
1675         }
1676    
1677         if (layout.margintype == MARGIN_MANUAL) {
1678                 if (par->labelwidthstring.empty()) {
1679                         par->SetLabelWidthString(layout.labelstring());
1680                 }
1681         } else {
1682                 par->SetLabelWidthString(string());
1683         }
1684    
1685         /* is it a layout that has an automatic label ? */ 
1686         if (layout.labeltype >=  LABEL_FIRST_COUNTER) {
1687       
1688                 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1689                 if (i >= 0 && i<= buf->params.secnumdepth) {
1690                         par->incCounter(i);     // increment the counter  
1691          
1692                         // Is there a label? Useful for Chapter layout
1693                         if (!par->appendix){
1694                                 if (!layout.labelstring().empty())
1695                                         par->labelstring = layout.labelstring();
1696                                 else
1697                                         par->labelstring.erase();
1698                         } else {
1699                                 if (!layout.labelstring_appendix().empty())
1700                                         par->labelstring = layout.labelstring_appendix();
1701                                 else
1702                                         par->labelstring.erase();
1703                         }
1704
1705 #ifdef HAVE_SSTREAM
1706                         std::ostringstream s;
1707 #else
1708                         ostrstream s;
1709 #endif
1710                         if (!par->appendix) {
1711                                 switch (2 * LABEL_FIRST_COUNTER -
1712                                         textclass.maxcounter() + i) {
1713                                 case LABEL_COUNTER_CHAPTER:
1714                                         s << par->getCounter(i);
1715                                         break;
1716                                 case LABEL_COUNTER_SECTION:
1717                                         s << par->getCounter(i - 1) << '.'
1718                                            << par->getCounter(i);
1719                                         break;
1720                                 case LABEL_COUNTER_SUBSECTION:
1721                                         s << par->getCounter(i - 2) << '.'
1722                                           << par->getCounter(i - 1) << '.'
1723                                           << par->getCounter(i);
1724                                         break;
1725                                 case LABEL_COUNTER_SUBSUBSECTION:
1726                                         s << par->getCounter(i - 3) << '.'
1727                                           << par->getCounter(i - 2) << '.'
1728                                           << par->getCounter(i - 1) << '.'
1729                                           << par->getCounter(i);
1730                                         
1731                                         break;
1732                                 case LABEL_COUNTER_PARAGRAPH:
1733                                         s << par->getCounter(i - 4) << '.'
1734                                           << par->getCounter(i - 3) << '.'
1735                                           << par->getCounter(i - 2) << '.'
1736                                           << par->getCounter(i - 1) << '.'
1737                                           << par->getCounter(i);
1738                                         break;
1739                                 case LABEL_COUNTER_SUBPARAGRAPH:
1740                                         s << par->getCounter(i - 5) << '.'
1741                                           << par->getCounter(i - 4) << '.'
1742                                           << par->getCounter(i - 3) << '.'
1743                                           << par->getCounter(i - 2) << '.'
1744                                           << par->getCounter(i - 1) << '.'
1745                                           << par->getCounter(i);
1746
1747                                         break;
1748                                 default:
1749                                         s << par->getCounter(i) << '.';
1750                                         break;
1751                                 }
1752                         } else { // appendix
1753                                 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1754                                 case LABEL_COUNTER_CHAPTER:
1755                                         if (par->isRightToLeftPar(buf->params))
1756                                                 s << hebrewCounter(par->getCounter(i));
1757                                         else
1758                                                 s << alphaCounter(par->getCounter(i));
1759                                         break;
1760                                 case LABEL_COUNTER_SECTION:
1761                                         if (par->isRightToLeftPar(buf->params))
1762                                                 s << hebrewCounter(par->getCounter(i - 1));
1763                                         else
1764                                                 s << alphaCounter(par->getCounter(i - 1));
1765
1766                                         s << '.'
1767                                           << par->getCounter(i);
1768
1769                                         break;
1770                                 case LABEL_COUNTER_SUBSECTION:
1771                                         if (par->isRightToLeftPar(buf->params))
1772                                                 s << hebrewCounter(par->getCounter(i - 2));
1773                                         else
1774                                                 s << alphaCounter(par->getCounter(i - 2));
1775
1776                                         s << '.'
1777                                           << par->getCounter(i-1) << '.'
1778                                           << par->getCounter(i);
1779
1780                                         break;
1781                                 case LABEL_COUNTER_SUBSUBSECTION:
1782                                         if (par->isRightToLeftPar(buf->params))
1783                                                 s << hebrewCounter(par->getCounter(i-3));
1784                                         else
1785                                                 s << alphaCounter(par->getCounter(i-3));
1786
1787                                         s << '.'
1788                                           << par->getCounter(i-2) << '.'
1789                                           << par->getCounter(i-1) << '.'
1790                                           << par->getCounter(i);
1791
1792                                         break;
1793                                 case LABEL_COUNTER_PARAGRAPH:
1794                                         if (par->isRightToLeftPar(buf->params))
1795                                                 s << hebrewCounter(par->getCounter(i-4));
1796                                         else
1797                                                 s << alphaCounter(par->getCounter(i-4));
1798
1799                                         s << '.'
1800                                           << par->getCounter(i-3) << '.'
1801                                           << par->getCounter(i-2) << '.'
1802                                           << par->getCounter(i-1) << '.'
1803                                           << par->getCounter(i);
1804
1805                                         break;
1806                                 case LABEL_COUNTER_SUBPARAGRAPH:
1807                                         if (par->isRightToLeftPar(buf->params))
1808                                                 s << hebrewCounter(par->getCounter(i-5));
1809                                         else
1810                                                 s << alphaCounter(par->getCounter(i-5));
1811
1812                                         s << '.'
1813                                           << par->getCounter(i-4) << '.'
1814                                           << par->getCounter(i-3) << '.'
1815                                           << par->getCounter(i-2) << '.'
1816                                           << par->getCounter(i-1) << '.'
1817                                           << par->getCounter(i);
1818
1819                                         break;
1820                                 default:
1821                                         // Can this ever be reached? And in the
1822                                         // case it is, how can this be correct?
1823                                         // (Lgb)
1824                                         s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1825                                         
1826                                         break;
1827                                 }
1828                         }
1829 #ifdef HAVE_SSTREAM
1830                         par->labelstring += s.str().c_str();
1831                         // We really want to remove the c_str as soon as
1832                         // possible...
1833 #else
1834                         s << '\0';
1835                         char * tmps = s.str();
1836                         par->labelstring += tmps;
1837                         delete [] tmps;
1838 #endif
1839                         
1840                         for (i++; i < 10; ++i) {
1841                                 // reset the following counters
1842                                 par->setCounter(i, 0);
1843                         }
1844                 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1845                         for (i++; i < 10; ++i) {
1846                                 // reset the following counters
1847                                 par->setCounter(i, 0);
1848                         }
1849                 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1850                         par->incCounter(i + par->enumdepth);
1851                         int number = par->getCounter(i + par->enumdepth);
1852
1853 #ifdef HAVE_SSTREAM
1854                         std::ostringstream s;
1855 #else
1856                         ostrstream s;
1857 #endif
1858                         switch (par->enumdepth) {
1859                         case 1:
1860                                 if (par->isRightToLeftPar(buf->params))
1861                                         s << '('
1862                                           << hebrewCounter(number)
1863                                           << ')';
1864                                 else
1865                                         s << '('
1866                                           << loweralphaCounter(number)
1867                                           << ')';
1868                                 break;
1869                         case 2:
1870                                 if (par->isRightToLeftPar(buf->params))
1871                                         s << '.' << romanCounter(number);
1872                                 else
1873                                         s << romanCounter(number) << '.';
1874                                 break;
1875                         case 3:
1876                                 if (par->isRightToLeftPar(buf->params))
1877                                         s << '.'
1878                                           << alphaCounter(number);
1879                                 else
1880                                         s << alphaCounter(number)
1881                                           << '.';
1882                                 break;
1883                         default:
1884                                 if (par->isRightToLeftPar(buf->params))
1885                                         s << '.' << number;
1886                                 else
1887                                         s << number << '.';
1888                                 break;
1889                         }
1890 #ifdef HAVE_SSTREAM
1891                         par->labelstring = s.str().c_str();
1892                         // we really want to get rid of that c_str()
1893 #else
1894                         s << '\0';
1895                         char * tmps = s.str();
1896                         par->labelstring = tmps;
1897                         delete [] tmps;
1898 #endif
1899
1900                         for (i += par->enumdepth + 1; i < 10; ++i)
1901                                 par->setCounter(i, 0);  /* reset the following counters  */
1902          
1903                 } 
1904         } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1905                 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1906                 par->incCounter(i);
1907                 int number = par->getCounter(i);
1908                 if (!par->bibkey)
1909                         par->bibkey = new InsetBibKey();
1910                 par->bibkey->setCounter(number);
1911                 par->labelstring = layout.labelstring();
1912                 
1913                 // In biblio should't be following counters but...
1914         } else {
1915                 string s = layout.labelstring();
1916                 
1917                 // the caption hack:
1918       
1919                 if (layout.labeltype == LABEL_SENSITIVE) {
1920                         if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1921                             && (par->footnotekind == LyXParagraph::FIG
1922                                 || par->footnotekind == LyXParagraph::WIDE_FIG))
1923                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1924                                         ? ":øåéà" : "Figure:";
1925                         else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1926                                  && (par->footnotekind == LyXParagraph::TAB
1927                                      || par->footnotekind == LyXParagraph::WIDE_TAB))
1928                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1929                                         ? ":äìáè" : "Table:";
1930                         else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1931                                  && par->footnotekind == LyXParagraph::ALGORITHM)
1932                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1933                                         ? ":íúéøåâìà" : "Algorithm:";
1934                         else {
1935                                 /* par->SetLayout(0); 
1936                                    s = layout->labelstring;  */
1937                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1938                                         ? " :úåòîùî Ã¸Ã±Ã§" : "Senseless: ";
1939                         }
1940                 }
1941                 par->labelstring = s;
1942                 
1943                 /* reset the enumeration counter. They are always resetted
1944                  * when there is any other layout between */ 
1945                 for (int i = 6 + par->enumdepth; i < 10; ++i)
1946                         par->setCounter(i, 0);
1947         }
1948 }
1949
1950
1951 /* Updates all counters BEHIND the row. Changed paragraphs
1952 * with a dynamic left margin will be rebroken. */ 
1953 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1954 {
1955         LyXParagraph * par;
1956         if (!row) {
1957                 row = firstrow;
1958                 par = row->par();
1959         }
1960         else {
1961                 if (row->par()->next
1962                     && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1963                         par = row->par()->LastPhysicalPar()->Next();
1964                 } else {
1965                         par = row->par()->next;
1966                 }
1967         }
1968
1969         while (par) {
1970                 while (row->par() != par)
1971                         row = row->next();
1972                 
1973                 SetCounter(bview->buffer(), par);
1974                 
1975                 /* now  check for the headline layouts. remember that they
1976                  * have a dynamic left margin */ 
1977                 if (!par->IsDummy()
1978                     && ( textclasslist.Style(bview->buffer()->params.textclass,
1979                                              par->layout).margintype == MARGIN_DYNAMIC
1980                          || textclasslist.Style(bview->buffer()->params.textclass,
1981                                                 par->layout).labeltype == LABEL_SENSITIVE)
1982                         ) {
1983          
1984                         /* Rebreak the paragraph */ 
1985                         RemoveParagraph(row);
1986                         AppendParagraph(bview, row);
1987        
1988                         /* think about the damned open footnotes! */ 
1989                         while (par->Next() &&
1990                                (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1991                                 || par->Next()->IsDummy())){
1992                                 par = par->Next();
1993                                 if (par->IsDummy()) {
1994                                         while (row->par() != par)
1995                                                 row = row->next();
1996                                         RemoveParagraph(row);
1997                                         AppendParagraph(bview, row);
1998                                 }
1999                         }
2000                 }
2001      
2002                 par = par->LastPhysicalPar()->Next();
2003      
2004         }
2005 }
2006
2007
2008 /* insets an inset. */ 
2009 void LyXText::InsertInset(BufferView * bview, Inset *inset)
2010 {
2011         if (!cursor.par()->InsertInsetAllowed(inset))
2012                 return;
2013         SetUndo(bview->buffer(), Undo::INSERT, 
2014                 cursor.par()->ParFromPos(cursor.pos())->previous, 
2015                 cursor.par()->ParFromPos(cursor.pos())->next);
2016         cursor.par()->InsertChar(cursor.pos(), LyXParagraph::META_INSET);
2017         cursor.par()->InsertInset(cursor.pos(), inset);
2018         InsertChar(bview, LyXParagraph::META_INSET);  /* just to rebreak and refresh correctly.
2019                                       * The character will not be inserted a
2020                                       * second time */
2021 }
2022
2023
2024 void LyXText::copyEnvironmentType()
2025 {
2026         copylayouttype = cursor.par()->GetLayout();
2027 }
2028
2029
2030 void LyXText::pasteEnvironmentType(BufferView * bview)
2031 {
2032         SetLayout(bview, copylayouttype);
2033 }
2034
2035
2036 void LyXText::CutSelection(BufferView * bview, bool doclear)
2037 {
2038         // Stuff what we got on the clipboard. Even if there is no selection.
2039
2040         // There is a problem with having the stuffing here in that the
2041         // larger the selection the slower LyX will get. This can be
2042         // solved by running the line below only when the selection has
2043         // finished. The solution used currently just works, to make it
2044         // faster we need to be more clever and probably also have more
2045         // calls to stuffClipboard. (Lgb)
2046         bview->stuffClipboard(selectionAsString(bview->buffer()));
2047
2048         // This doesn't make sense, if there is no selection
2049         if (!selection)
2050                 return;
2051    
2052         // OK, we have a selection. This is always between sel_start_cursor
2053         // and sel_end cursor
2054         LyXParagraph * tmppar;
2055     
2056         // Check whether there are half footnotes in the selection
2057         if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2058             || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2059                 tmppar = sel_start_cursor.par();
2060                 while (tmppar != sel_end_cursor.par()){
2061                         if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2062                                 WriteAlert(_("Impossible operation"),
2063                                            _("Don't know what to do with half floats."),
2064                                            _("sorry."));
2065                                 return;
2066                         }
2067                         tmppar = tmppar->Next();
2068                 }
2069         }
2070
2071 #ifndef NEW_TABULAR
2072         /* table stuff -- begin */
2073         if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2074                 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2075                         WriteAlert(_("Impossible operation"),
2076                                    _("Don't know what to do with half tables."),
2077                                    _("sorry."));
2078                         return;
2079                 }
2080                 sel_start_cursor.par()->table->Reinit();
2081         }
2082         /* table stuff -- end */
2083 #endif
2084         // make sure that the depth behind the selection are restored, too
2085         LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2086         LyXParagraph * undoendpar = endpar;
2087     
2088         if (endpar && endpar->GetDepth()) {
2089                 while (endpar && endpar->GetDepth()) {
2090                         endpar = endpar->LastPhysicalPar()->Next();
2091                         undoendpar = endpar;
2092                 }
2093         } else if (endpar) {
2094                 endpar = endpar->Next(); // because of parindents etc.
2095         }
2096     
2097         SetUndo(bview->buffer(), Undo::DELETE, sel_start_cursor
2098                 .par()->ParFromPos(sel_start_cursor.pos())->previous, undoendpar);
2099     
2100         CutAndPaste cap;
2101
2102         // there are two cases: cut only within one paragraph or
2103         // more than one paragraph
2104         if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos()) 
2105             == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2106                 // only within one paragraph
2107                 endpar = sel_start_cursor.par();
2108                 int pos = sel_end_cursor.pos();
2109                 cap.cutSelection(sel_start_cursor.par(), &endpar,
2110                                  sel_start_cursor.pos(), pos,
2111                                  bview->buffer()->params.textclass, doclear);
2112                 sel_end_cursor.pos(pos);
2113         } else {
2114                 endpar = sel_end_cursor.par();
2115
2116                 int pos = sel_end_cursor.pos();
2117                 cap.cutSelection(sel_start_cursor.par(), &endpar,
2118                                  sel_start_cursor.pos(), pos,
2119                                  bview->buffer()->params.textclass, doclear);
2120                 cursor.par(endpar);
2121                 sel_end_cursor.par(endpar);
2122                 sel_end_cursor.pos(pos);
2123                 cursor.pos(sel_end_cursor.pos());
2124         }
2125         endpar = endpar->Next();
2126
2127         // sometimes necessary
2128         if (doclear)
2129                 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2130
2131         RedoParagraphs(bview, sel_start_cursor, endpar);
2132    
2133         ClearSelection();
2134         cursor = sel_start_cursor;
2135         SetCursor(bview, cursor.par(), cursor.pos());
2136         sel_cursor = cursor;
2137         UpdateCounters(bview, cursor.row());
2138 }
2139
2140
2141 void LyXText::CopySelection(BufferView * bview)
2142 {
2143         // Stuff what we got on the clipboard. Even if there is no selection.
2144
2145         // There is a problem with having the stuffing here in that the
2146         // larger the selection the slower LyX will get. This can be
2147         // solved by running the line below only when the selection has
2148         // finished. The solution used currently just works, to make it
2149         // faster we need to be more clever and probably also have more
2150         // calls to stuffClipboard. (Lgb)
2151         bview->stuffClipboard(selectionAsString(bview->buffer()));
2152
2153         // this doesnt make sense, if there is no selection
2154         if (!selection)
2155                 return;
2156
2157         // ok we have a selection. This is always between sel_start_cursor
2158         // and sel_end cursor
2159         LyXParagraph * tmppar;
2160    
2161         /* check wether there are half footnotes in the selection */
2162         if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2163             || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2164                 tmppar = sel_start_cursor.par();
2165                 while (tmppar != sel_end_cursor.par()) {
2166                         if (tmppar->footnoteflag !=
2167                             sel_end_cursor.par()->footnoteflag) {
2168                                 WriteAlert(_("Impossible operation"),
2169                                            _("Don't know what to do"
2170                                              " with half floats."),
2171                                            _("sorry."));
2172                                 return;
2173                         }
2174                         tmppar = tmppar->Next();
2175                 }
2176         }
2177
2178 #ifndef NEW_TABULAR
2179         /* table stuff -- begin */
2180         if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2181                 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2182                         WriteAlert(_("Impossible operation"),
2183                                    _("Don't know what to do with half tables."),
2184                                    _("sorry."));
2185                         return;
2186                 }
2187         }
2188         /* table stuff -- end */
2189 #endif
2190    
2191         // copy behind a space if there is one
2192         while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2193                && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2194                && (sel_start_cursor.par() != sel_end_cursor.par()
2195                    || sel_start_cursor.pos() < sel_end_cursor.pos()))
2196                 sel_start_cursor.pos(sel_start_cursor.pos() + 1); 
2197
2198         CutAndPaste cap;
2199
2200         cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2201                           sel_start_cursor.pos(), sel_end_cursor.pos(),
2202                           bview->buffer()->params.textclass);
2203 }
2204
2205
2206 void LyXText::PasteSelection(BufferView * bview)
2207 {
2208         CutAndPaste cap;
2209
2210         // this does not make sense, if there is nothing to paste
2211         if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2212                 return;
2213
2214         SetUndo(bview->buffer(), Undo::INSERT, 
2215                 cursor.par()->ParFromPos(cursor.pos())->previous, 
2216                 cursor.par()->ParFromPos(cursor.pos())->next); 
2217
2218         LyXParagraph * endpar;
2219         LyXParagraph * actpar = cursor.par();
2220
2221         int pos = cursor.pos();
2222         cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2223     
2224         RedoParagraphs(bview, cursor, endpar);
2225         
2226         SetCursor(bview, cursor.par(), cursor.pos());
2227         ClearSelection();
2228    
2229         sel_cursor = cursor;
2230         SetCursor(bview, actpar, pos);
2231         SetSelection();
2232         UpdateCounters(bview, cursor.row());
2233 }
2234
2235
2236 // returns a pointer to the very first LyXParagraph
2237 LyXParagraph * LyXText::FirstParagraph() const
2238 {
2239         return OwnerParagraph();
2240 }
2241
2242
2243 // returns true if the specified string is at the specified position
2244 bool LyXText::IsStringInText(LyXParagraph * par,
2245                              LyXParagraph::size_type pos,
2246                              char const * str) const
2247 {
2248         if (par) {
2249                 int i = 0;
2250                 while (pos + i < par->Last() && str[i] && 
2251                        str[i] == par->GetChar(pos + i)) {
2252                         ++i;
2253                 }
2254                 if (!str[i])
2255                         return true;
2256         }
2257         return false;
2258 }
2259
2260
2261 // sets the selection over the number of characters of string, no check!!
2262 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2263 {
2264         sel_cursor = cursor;
2265         for (int i = 0; string[i]; ++i)
2266                 CursorRight(bview);
2267         SetSelection();
2268 }
2269
2270
2271 // simple replacing. The font of the first selected character is used
2272 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2273 {
2274         SetCursorParUndo(bview->buffer());
2275         FreezeUndo();
2276
2277         if (!selection) { // create a dummy selection
2278                 sel_end_cursor = cursor;
2279                 sel_start_cursor = cursor;
2280         }
2281
2282         // Get font setting before we cut
2283         LyXParagraph::size_type pos = sel_end_cursor.pos();
2284         LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2285                                                              sel_start_cursor.pos());
2286
2287         // Insert the new string
2288         for (int i = 0; str[i]; ++i) {
2289                 sel_end_cursor.par()->InsertChar(pos, str[i]);
2290                 sel_end_cursor.par()->SetFont(pos, font);
2291                 ++pos;
2292         }
2293
2294         // Cut the selection
2295         CutSelection(bview);
2296
2297         UnFreezeUndo();
2298 }
2299
2300
2301 // if the string can be found: return true and set the cursor to
2302 // the new position
2303 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2304 {
2305         LyXParagraph * par = cursor.par();
2306         LyXParagraph::size_type pos = cursor.pos();
2307         while (par && !IsStringInText(par, pos, str)) {
2308                 if (pos < par->Last() - 1)
2309                         ++pos;
2310                 else {
2311                         pos = 0;
2312                         par = par->Next();
2313                 }
2314         }
2315         if (par) {
2316                 SetCursor(bview, par, pos);
2317                 return true;
2318         }
2319         else
2320                 return false;
2321 }
2322
2323
2324 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2325 {
2326         LyXParagraph * par = cursor.par();
2327         int pos = cursor.pos();
2328
2329         do {
2330                 if (pos > 0)
2331                         --pos;
2332                 else {
2333                         // We skip empty paragraphs (Asger)
2334                         do {
2335                                 par = par->Previous();
2336                                 if (par)
2337                                         pos = par->Last() - 1;
2338                         } while (par && pos < 0);
2339                 }
2340         } while (par && !IsStringInText(par, pos, string));
2341   
2342         if (par) {
2343                 SetCursor(bview, par, pos);
2344                 return true;
2345         } else
2346                 return false;
2347 }
2348
2349
2350 // needed to insert the selection
2351 void LyXText::InsertStringA(BufferView * bview, string const & str)
2352 {
2353         LyXParagraph * par = cursor.par();
2354         LyXParagraph::size_type pos = cursor.pos();
2355         LyXParagraph::size_type a = 0;
2356         int cell = 0;
2357         LyXParagraph * endpar = cursor.par()->Next();
2358         
2359         SetCursorParUndo(bview->buffer());
2360         
2361         bool flag =
2362                 textclasslist.Style(bview->buffer()->params.textclass, 
2363                                     cursor.par()->GetLayout()).isEnvironment();
2364         // only to be sure, should not be neccessary
2365         ClearSelection();
2366         
2367         // insert the string, don't insert doublespace
2368         string::size_type i = 0;
2369         while (i < str.length()) {
2370                 if (str[i] != '\n') {
2371                         if (str[i] == ' ' 
2372                             && i + 1 < str.length() && str[i + 1] != ' '
2373                             && pos && par->GetChar(pos - 1)!= ' ') {
2374                                 par->InsertChar(pos,' ');
2375                                 par->SetFont(pos, current_font);
2376                                 ++pos;
2377 #ifndef NEW_TABLAR
2378                         } else if (par->table) {
2379                                 if (str[i] == '\t') {
2380                                         while((pos < par->size()) &&
2381                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2382                                                 ++pos;
2383                                         if (pos < par->size())
2384                                                 ++pos;
2385                                         else // no more fields to fill skip the rest
2386                                                 break;
2387                                 } else if ((str[i] != 13) &&
2388                                            ((str[i] & 127) >= ' ')) {
2389                                         par->InsertChar(pos, str[i]);
2390                                         par->SetFont(pos, current_font);
2391                                         ++pos;
2392                                 }
2393 #endif
2394                         } else if (str[i] == ' ') {
2395                                 InsetSpecialChar * new_inset =
2396                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2397                                 if (par->InsertInsetAllowed(new_inset)) {
2398                                         par->InsertChar(pos, LyXParagraph::META_INSET);
2399                                         par->SetFont(pos, current_font);
2400                                         par->InsertInset(pos, new_inset);
2401                                 } else {
2402                                         delete new_inset;
2403                                 }
2404                                 ++pos;
2405                         } else if (str[i] == '\t') {
2406                                 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2407                                 InsetSpecialChar * new_inset =
2408                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2409                                 if (par->InsertInsetAllowed(new_inset)) {
2410                                         par->InsertChar(pos, LyXParagraph::META_INSET);
2411                                         par->SetFont(pos, current_font);
2412                                         par->InsertInset(pos, new_inset);
2413                                 } else {
2414                                         delete new_inset;
2415                                 }
2416                                 }
2417                                 pos = a;
2418                         } else if (str[i] != 13 && 
2419                                    // Ignore unprintables
2420                                    (str[i] & 127) >= ' ') {
2421                                 par->InsertChar(pos, str[i]);
2422                                 par->SetFont(pos, current_font);
2423                                 ++pos;
2424                         }
2425                 } else {
2426 #ifndef NEW_TABULAR
2427                         if (par->table) {
2428                                 if ((i + 1) >= str.length()) {
2429                                         if (pos < par->size())
2430                                                 ++pos;
2431                                         break;
2432                                 }
2433                                 while((pos < par->size()) &&
2434                                       (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2435                                         ++pos;
2436                                 ++pos;
2437                                 cell = NumberOfCell(par, pos);
2438                                 while((pos < par->size()) &&
2439                                       !(par->table->IsFirstCell(cell))) {
2440
2441                                         while((pos < par->size()) &&
2442                                               (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2443                                                 ++pos;
2444                                         ++pos;
2445                                         cell = NumberOfCell(par, pos);
2446                                 }
2447                                 if (pos >= par->size())
2448                                         // no more fields to fill skip the rest
2449                                         break;
2450                         } else {
2451 #endif
2452                                 if (!par->size()) { // par is empty
2453                                         InsetSpecialChar * new_inset =
2454                                                 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2455                                         if (par->InsertInsetAllowed(new_inset)) {
2456                                                 par->InsertChar(pos, LyXParagraph::META_INSET);
2457                                                 par->SetFont(pos, current_font);
2458                                                 par->InsertInset(pos, new_inset);
2459                                         } else {
2460                                                 delete new_inset;
2461                                         }
2462                                         ++pos;
2463                                 }
2464                                 par->BreakParagraph(bview->buffer()->params, pos, flag);
2465                                 par = par->Next();
2466                                 pos = 0;
2467 #ifndef NEW_TABULAR
2468                         }
2469 #endif
2470                 }
2471                 ++i;
2472         }
2473         
2474         RedoParagraphs(bview, cursor, endpar);
2475         SetCursor(bview, cursor.par(), cursor.pos());
2476         sel_cursor = cursor;
2477         SetCursor(bview, par, pos);
2478         SetSelection();
2479 }
2480
2481
2482 /* turns double-CR to single CR, others where converted into one blank and 13s 
2483  * that are ignored .Double spaces are also converted into one. Spaces at
2484  * the beginning of a paragraph are forbidden. tabs are converted into one
2485  * space. then InsertStringA is called */ 
2486 void LyXText::InsertStringB(BufferView * bview, string const & s)
2487 {
2488         string str(s);
2489         LyXParagraph * par = cursor.par();
2490         string::size_type i = 1;
2491         while (i < str.length()) {
2492                 if (str[i] == '\t' && !par->table)
2493                         str[i] = ' ';
2494                 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2495                         str[i] = 13;
2496                 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2497                         if (str[i + 1] != '\n') {
2498                                 if (str[i - 1] != ' ')
2499                                         str[i] = ' ';
2500                                 else
2501                                         str[i] = 13;
2502                         }
2503                         while (i + 1 < str.length() 
2504                                && (str[i + 1] == ' ' 
2505                                    || str[i + 1] == '\t'
2506                                    || str[i + 1] == '\n' 
2507                                    || str[i + 1] == 13)) {
2508                                 str[i + 1] = 13;
2509                                 ++i;
2510                         }
2511                 }
2512                 ++i;
2513         }
2514         InsertStringA(bview, str);
2515 }
2516
2517
2518 bool LyXText::GotoNextError(BufferView * bview) const
2519 {
2520         LyXCursor res = cursor;
2521         do {
2522                 if (res.pos() < res.par()->Last() - 1) {
2523                         res.pos(res.pos() + 1);
2524                 } else  {
2525                         res.par(res.par()->Next());
2526                         res.pos(0);
2527                 }
2528       
2529         } while (res.par() && 
2530                  !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2531                    && res.par()->GetInset(res.pos())->AutoDelete()));
2532    
2533         if (res.par()) {
2534                 SetCursor(bview, res.par(), res.pos());
2535                 return true;
2536         }
2537         return false;
2538 }
2539
2540
2541 bool LyXText::GotoNextNote(BufferView * bview) const
2542 {
2543         LyXCursor res = cursor;
2544         do {
2545                 if (res.pos() < res.par()->Last() - 1) {
2546                         res.pos(res.pos() + 1);
2547                 } else  {
2548                         res.par(res.par()->Next());
2549                         res.pos(0);
2550                 }
2551       
2552         } while (res.par() && 
2553                  !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2554                    && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2555    
2556         if (res.par()) {
2557                 SetCursor(bview, res.par(), res.pos());
2558                 return true;
2559         }
2560         return false;
2561 }
2562
2563
2564 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2565                              LyXParagraph::size_type pos)
2566 {
2567         LyXCursor tmpcursor;                    
2568
2569 #ifndef NEW_TABULAR
2570         /* table stuff -- begin*/
2571    
2572         if (par->table) {
2573                 CheckParagraphInTable(bview, par, pos);
2574         }
2575         else {
2576 #endif
2577                 /* table stuff -- end*/
2578      
2579                 long y = 0;
2580                 LyXParagraph::size_type z;
2581                 Row * row = GetRow(par, pos, y);
2582      
2583                 // is there a break one row above
2584                 if (row->previous() && row->previous()->par() == row->par()) {
2585                         z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2586                         if ( z >= row->pos()) {
2587                                 // set the dimensions of the row above
2588                                 y -= row->previous()->height();
2589                                 refresh_y = y;
2590                                 refresh_row = row->previous();
2591                                 status = LyXText::NEED_MORE_REFRESH;
2592        
2593                                 BreakAgain(bview, row->previous());
2594
2595                                 // set the cursor again. Otherwise
2596                                 // dangling pointers are possible
2597                                 SetCursor(bview, cursor.par(), cursor.pos());
2598                                 sel_cursor = cursor;
2599                                 return;
2600                         }
2601                 }
2602
2603                 int tmpheight = row->height();
2604                 LyXParagraph::size_type tmplast = RowLast(row);
2605                 refresh_y = y;
2606                 refresh_row = row;
2607
2608                 BreakAgain(bview, row);
2609                 if (row->height() == tmpheight && RowLast(row) == tmplast)
2610                         status = LyXText::NEED_VERY_LITTLE_REFRESH;
2611                 else
2612                         status = LyXText::NEED_MORE_REFRESH; 
2613    
2614                 // check the special right address boxes
2615                 if (textclasslist.Style(bview->buffer()->params.textclass,
2616                                         par->GetLayout()).margintype
2617                     == MARGIN_RIGHT_ADDRESS_BOX) {
2618                         tmpcursor.par(par);
2619                         tmpcursor.row(row);
2620                         tmpcursor.y(y);
2621                         tmpcursor.x(0);
2622                         tmpcursor.x_fix(0);
2623                         tmpcursor.pos(pos);
2624                         RedoDrawingOfParagraph(bview, tmpcursor); 
2625                 }
2626 #ifndef NEW_TABULAR
2627         }
2628 #endif
2629
2630         // set the cursor again. Otherwise dangling pointers are possible
2631         // also set the selection
2632    
2633         if (selection) {
2634                 tmpcursor = cursor;
2635                 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2636                 sel_cursor = cursor; 
2637                 SetCursorIntern(bview, sel_start_cursor.par(),
2638                                 sel_start_cursor.pos());
2639                 sel_start_cursor = cursor; 
2640                 SetCursorIntern(bview, sel_end_cursor.par(),
2641                                 sel_end_cursor.pos());
2642                 sel_end_cursor = cursor; 
2643                 SetCursorIntern(bview, last_sel_cursor.par(),
2644                                 last_sel_cursor.pos());
2645                 last_sel_cursor = cursor; 
2646                 cursor = tmpcursor;
2647         }
2648         SetCursorIntern(bview, cursor.par(), cursor.pos());
2649 }
2650
2651
2652 // returns 0 if inset wasn't found
2653 int LyXText::UpdateInset(BufferView * bview, Inset * inset)
2654 {
2655         // first check the current paragraph
2656         int pos = cursor.par()->GetPositionOfInset(inset);
2657         if (pos != -1){
2658                 CheckParagraph(bview, cursor.par(), pos);
2659                 return 1;
2660         }
2661   
2662         // check every paragraph
2663   
2664         LyXParagraph * par = FirstParagraph();
2665         do {
2666                 // make sure the paragraph is open
2667                 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2668                         pos = par->GetPositionOfInset(inset);
2669                         if (pos != -1){
2670                                 CheckParagraph(bview, par, pos);
2671                                 return 1;
2672                         }
2673                 }
2674                 par = par->Next();
2675         } while (par);
2676   
2677         return 0;
2678 }
2679
2680
2681 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2682                         LyXParagraph::size_type pos, 
2683                         bool setfont, bool boundary) const
2684 {
2685         LyXCursor old_cursor = cursor;
2686         SetCursorIntern(bview, par, pos, setfont, boundary);
2687         DeleteEmptyParagraphMechanism(bview, old_cursor);
2688 }
2689
2690
2691 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2692                         LyXParagraph::size_type pos, bool boundary) const
2693 {
2694         // correct the cursor position if impossible
2695         if (pos > par->Last()){
2696                 LyXParagraph * tmppar = par->ParFromPos(pos);
2697                 pos = par->PositionInParFromPos(pos);
2698                 par = tmppar;
2699         }
2700         if (par->IsDummy() && par->previous &&
2701             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2702                 while (par->previous &&
2703                        ((par->previous->IsDummy() &&
2704                          (par->previous->previous->footnoteflag ==
2705                           LyXParagraph::CLOSED_FOOTNOTE)) ||
2706                         (par->previous->footnoteflag ==
2707                          LyXParagraph::CLOSED_FOOTNOTE))) {
2708                         par = par->previous ;
2709                         if (par->IsDummy() &&
2710                             (par->previous->footnoteflag ==
2711                              LyXParagraph::CLOSED_FOOTNOTE))
2712                                 pos += par->size() + 1;
2713                 }
2714                 if (par->previous) {
2715                         par = par->previous;
2716                 }
2717                 pos += par->size() + 1;
2718         }
2719
2720         cur.par(par);
2721         cur.pos(pos);
2722         cur.boundary(boundary);
2723
2724         /* get the cursor y position in text  */
2725         long y = 0;
2726         Row * row = GetRow(par, pos, y);
2727         /* y is now the beginning of the cursor row */ 
2728         y += row->baseline();
2729         /* y is now the cursor baseline */ 
2730         cur.y(y);
2731    
2732         /* now get the cursors x position */
2733         float x;
2734         float fill_separator, fill_hfill, fill_label_hfill;
2735         PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2736                        fill_label_hfill);
2737         LyXParagraph::size_type cursor_vpos = 0;
2738         LyXParagraph::size_type last = RowLastPrintable(row);
2739
2740         if (pos > last + 1)   // This shouldn't happen.
2741                 pos = last + 1;
2742         else if (pos < row->pos())
2743                 pos = row->pos();
2744
2745         if (last < row->pos())
2746                 cursor_vpos = row->pos();
2747         else if (pos > last && !boundary)
2748                 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2749                         ? row->pos() : last + 1; 
2750         else if (pos > row->pos() &&
2751                  (pos > last || boundary || 
2752                   (row->par()->table && row->par()->IsNewline(pos))))
2753                 /// Place cursor after char at (logical) position pos - 1
2754                 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2755                         ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2756         else
2757                 /// Place cursor before char at (logical) position pos
2758                 cursor_vpos = (bidi_level(pos) % 2 == 0)
2759                         ? log2vis(pos) : log2vis(pos) + 1;
2760
2761 #ifndef NEW_TABULAR
2762         /* table stuff -- begin*/
2763         if (row->par()->table) {
2764                 int cell = NumberOfCell(row->par(), row->pos());
2765                 float x_old = x;
2766                 x += row->par()->table->GetBeginningOfTextInCell(cell);
2767                 for (LyXParagraph::size_type vpos = row->pos();
2768                      vpos < cursor_vpos; ++vpos) {
2769                         pos = vis2log(vpos);
2770                         if (row->par()->IsNewline(pos)) {
2771                                 x = x_old + row->par()->table->WidthOfColumn(cell);
2772                                 x_old = x;
2773                                 ++cell;
2774                                 x += row->par()->table->GetBeginningOfTextInCell(cell);
2775                         } else {
2776                                 x += SingleWidth(bview, row->par(), pos);
2777                         }
2778                 }
2779         } else {
2780                 /* table stuff -- end*/
2781 #endif
2782                 LyXParagraph::size_type main_body =
2783                         BeginningOfMainBody(bview->buffer(), row->par());
2784                 if ((main_body > 0) &&
2785                     ((main_body-1 > last) || 
2786                      !row->par()->IsLineSeparator(main_body-1)))
2787                         main_body = 0;
2788
2789                 for (LyXParagraph::size_type vpos = row->pos();
2790                      vpos < cursor_vpos; ++vpos) {
2791                         pos = vis2log(vpos);
2792                         if (main_body > 0 && pos == main_body-1) {
2793                                 x += fill_label_hfill +
2794                                         lyxfont::width(textclasslist.Style(
2795                                                 bview->buffer()->params.textclass,
2796                                                 row->par()->GetLayout())
2797                                                        .labelsep,
2798                                                        GetFont(bview->buffer(), row->par(), -2));
2799                                 if (row->par()->IsLineSeparator(main_body-1))
2800                                         x -= SingleWidth(bview, row->par(),main_body-1);
2801                         }
2802                         if (HfillExpansion(bview->buffer(), row, pos)) {
2803                                 x += SingleWidth(bview, row->par(), pos);
2804                                 if (pos >= main_body)
2805                                         x += fill_hfill;
2806                                 else 
2807                                         x += fill_label_hfill;
2808                         } else if (row->par()->IsSeparator(pos)) {
2809                                 x += SingleWidth(bview, row->par(), pos);
2810                                 if (pos >= main_body)
2811                                         x += fill_separator;
2812                         } else
2813                                 x += SingleWidth(bview, row->par(), pos);
2814                 }
2815 #ifndef NEW_TABULAR
2816         }
2817 #endif
2818    
2819         cur.x(int(x));
2820         cur.x_fix(cur.x());
2821         cur.row(row);
2822 }
2823
2824
2825 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2826                               LyXParagraph::size_type pos,
2827                               bool setfont, bool boundary) const
2828 {
2829         SetCursor(bview, cursor, par, pos, boundary);
2830 // #warning Remove this when verified working (Jug 20000413)
2831 #if 0
2832         // correct the cursor position if impossible
2833         if (pos > par->Last()){
2834                 LyXParagraph * tmppar = par->ParFromPos(pos);
2835                 pos = par->PositionInParFromPos(pos);
2836                 par = tmppar;
2837         }
2838         if (par->IsDummy() && par->previous &&
2839             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2840                 while (par->previous &&
2841                        ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
2842                         (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
2843                         par = par->previous ;
2844                         if (par->IsDummy() &&
2845                             par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
2846                                 pos += par->size() + 1;
2847                 }
2848                 if (par->previous) {
2849                         par = par->previous;
2850                 }
2851                 pos += par->size() + 1;
2852         }
2853
2854         cursor.par() = par;
2855         cursor.pos() = pos;
2856
2857         /* get the cursor y position in text  */
2858         long y = 0;
2859         Row * row = GetRow(par, pos, y);
2860         /* y is now the beginning of the cursor row */ 
2861         y += row->baseline();
2862         /* y is now the cursor baseline */ 
2863         cursor.y() = y;
2864    
2865         /* now get the cursors x position */
2866         float x;
2867         float fill_separator, fill_hfill, fill_label_hfill;
2868         PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
2869         LyXParagraph::size_type cursor_vpos;
2870         LyXParagraph::size_type last = RowLastPrintable(row);
2871
2872         if (pos > last + 1)   // This shouldn't happen.
2873                 pos = last+1;
2874
2875         if (last < row->pos())
2876                 cursor_vpos = 0;
2877         else if (pos > last ||
2878             (pos - 1 >= row->pos() &&
2879              (row->par()->IsSeparator(pos) ||
2880               (row->par()->table && row->par()->IsNewline(pos))
2881               )))
2882                 /// Place cursor after char at (logical) position pos-1
2883                 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
2884                         ? log2vis(pos-1) + 1 : log2vis(pos-1);
2885         else
2886                 /// Place cursor before char at (logical) position pos
2887                 cursor_vpos = (bidi_level(pos) % 2 == 0)
2888                         ? log2vis(pos) : log2vis(pos) + 1;
2889
2890 #ifndef NEW_TABULAR
2891         /* table stuff -- begin*/
2892         if (row->par()->table) {
2893                 int cell = NumberOfCell(row->par(), row->pos());
2894                 float x_old = x;
2895                 x += row->par()->table->GetBeginningOfTextInCell(cell);
2896                 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos)  {
2897                         pos = vis2log(vpos);
2898                         if (row->par()->IsNewline(pos)) {
2899                                 x = x_old + row->par()->table->WidthOfColumn(cell);
2900                                 x_old = x;
2901                                 ++cell;
2902                                 x += row->par()->table->GetBeginningOfTextInCell(cell);
2903                         } else {
2904                                 x += SingleWidth(row->par(), pos);
2905                         }
2906                 }
2907         } else {
2908                 /* table stuff -- end*/
2909 #endif
2910                 LyXParagraph::size_type main_body =
2911                         BeginningOfMainBody(row->par());
2912                 if (main_body > 0 &&
2913                     (main_body-1 > last || 
2914                      !row->par()->IsLineSeparator(main_body-1)))
2915                         main_body = 0;
2916
2917                 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos)  {
2918                         pos = vis2log(vpos);
2919                         if (main_body > 0 && pos == main_body-1) {
2920                                 x += fill_label_hfill +
2921                                         lyxfont::width(textclasslist
2922                                                        .Style(bview->buffer()->params.textclass,
2923                                                               row->par()->GetLayout())
2924                                                        .labelsep,
2925                                                        GetFont(row->par(), -2));
2926                                 if (row->par()->IsLineSeparator(main_body-1))
2927                                         x -= SingleWidth(row->par(), main_body-1);
2928                         }
2929                         if (HfillExpansion(row, pos)) {
2930                                 x += SingleWidth(row->par(), pos);
2931                                 if (pos >= main_body)
2932                                         x += fill_hfill;
2933                                 else 
2934                                         x += fill_label_hfill;
2935                         }
2936                         else if (row->par()->IsSeparator(pos)) {
2937                                 x += SingleWidth(row->par(), pos);
2938                                 if (pos >= main_body)
2939                                         x += fill_separator;
2940                         } else
2941                                 x += SingleWidth(row->par(), pos);
2942                 }
2943 #ifndef NEW_TABULAR
2944         }
2945 #endif
2946         cursor.x = int(x);
2947    
2948         cursor.x_fix = cursor.x;
2949         cursor.row() = row;
2950 #endif
2951         if (setfont)
2952                 SetCurrentFont(bview);
2953 }
2954
2955 void LyXText::SetCurrentFont(BufferView * bview) const
2956 {
2957         LyXParagraph::size_type pos = cursor.pos();
2958         if (cursor.boundary() && pos > 0)
2959                 --pos;
2960
2961         if (pos > 0) {
2962                 if (pos == cursor.par()->Last() ||
2963                     (cursor.par()->table && cursor.par()->IsNewline(pos)))
2964                         --pos;
2965                 else if (cursor.par()->IsSeparator(pos)) {
2966                         if (pos > cursor.row()->pos() &&
2967                             bidi_level(pos) % 2 == 
2968                             bidi_level(pos - 1) % 2)
2969                                 --pos;
2970                         else if (pos + 1 < cursor.par()->Last())
2971                                 ++pos;
2972                 }
2973         }
2974
2975         current_font = cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2976         real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2977 }
2978
2979
2980 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
2981 {
2982         LyXCursor old_cursor = cursor;
2983    
2984         /* get the row first */ 
2985    
2986         Row * row = GetRowNearY(y);
2987         cursor.par(row->par());
2988
2989         bool bound = false;
2990         int column = GetColumnNearX(bview, row, x, bound);
2991         cursor.pos(row->pos() + column);
2992         cursor.x(x);
2993         cursor.y(y + row->baseline());
2994         cursor.row(row);
2995         cursor.boundary(bound);
2996         SetCurrentFont(bview);
2997         DeleteEmptyParagraphMechanism(bview, old_cursor);
2998 }
2999
3000
3001 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3002                                        int x, long y) const
3003 {
3004         /* get the row first */ 
3005    
3006         Row * row = GetRowNearY(y);
3007         bool bound = false;
3008         int column = GetColumnNearX(bview, row, x, bound);
3009    
3010         cur.par(row->par());
3011         cur.pos(row->pos() + column);
3012         cur.x(x);
3013         cur.y(y + row->baseline());
3014         cur.row(row);
3015         cur.boundary(bound);
3016 }
3017
3018
3019 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3020 {
3021         CursorLeftIntern(bview, internal);
3022 #ifndef NEW_TABULAR
3023         if (cursor.par()->table) {
3024                 int cell = NumberOfCell(cursor.par(), cursor.pos());
3025                 if (cursor.par()->table->IsContRow(cell)
3026                     && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3027                         CursorUp(bview);
3028                 }
3029         }
3030 #endif
3031 }
3032
3033
3034 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3035 {
3036         if (cursor.pos() > 0) {
3037                 bool boundary = cursor.boundary();
3038                 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3039                 if (!internal && !boundary &&
3040                     IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3041                         SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3042         } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3043                 LyXParagraph * par = cursor.par()->Previous();
3044                 LyXParagraph::size_type pos = par->Last();
3045                 SetCursor(bview, par, pos);
3046                 if (IsBoundary(bview->buffer(), par, pos))
3047                         SetCursor(bview, par, pos, false, true);
3048         }
3049 }
3050
3051
3052 void LyXText::CursorRight(BufferView * bview, bool internal) const
3053 {
3054         CursorRightIntern(bview, internal);
3055 #ifndef NEW_TABULAR
3056         if (cursor.par()->table) {
3057                 int cell = NumberOfCell(cursor.par(), cursor.pos());
3058                 if (cursor.par()->table->IsContRow(cell) &&
3059                     cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3060                         CursorUp(bview);
3061                 }
3062         }
3063 #endif
3064 }
3065
3066
3067 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3068 {
3069         if (cursor.pos() < cursor.par()->Last()) {
3070                 if (!internal && cursor.boundary() &&
3071                     (!cursor.par()->table || !cursor.par()->IsNewline(cursor.pos())))
3072                         SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3073                 else {
3074                         SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3075                         if (!internal && IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3076                                 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3077                 }
3078         } else if (cursor.par()->Next())
3079                 SetCursor(bview, cursor.par()->Next(), 0);
3080 }
3081
3082
3083 void LyXText::CursorUp(BufferView * bview) const
3084 {
3085         SetCursorFromCoordinates(bview, cursor.x_fix(), 
3086                                  cursor.y() - cursor.row()->baseline() - 1);
3087 #ifndef NEW_TABULAR
3088         if (cursor.par()->table) {
3089                 int cell = NumberOfCell(cursor.par(), cursor.pos());
3090                 if (cursor.par()->table->IsContRow(cell) &&
3091                     cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3092                         CursorUp(bview);
3093                 }
3094         }
3095 #endif
3096 }
3097
3098
3099 void LyXText::CursorDown(BufferView * bview) const
3100 {
3101 #ifndef NEW_TABULAR
3102         if (cursor.par()->table &&
3103             cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3104             !cursor.par()->next)
3105                 return;
3106 #endif
3107         
3108         SetCursorFromCoordinates(bview, cursor.x_fix(), 
3109                                  cursor.y() - cursor.row()->baseline()
3110                                  + cursor.row()->height() + 1);
3111 #ifndef NEW_TABULAR
3112         if (cursor.par()->table) {
3113                 int cell = NumberOfCell(cursor.par(), cursor.pos());
3114                 int cell_above = cursor.par()->table->GetCellAbove(cell);
3115                 while(cursor.par()->table &&
3116                       cursor.par()->table->IsContRow(cell) &&
3117                       (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3118                     SetCursorFromCoordinates(bview, cursor.x_fix(), 
3119                                              cursor.y() - cursor.row()->baseline()
3120                                              + cursor.row()->height() + 1);
3121                     if (cursor.par()->table) {
3122                         cell = NumberOfCell(cursor.par(), cursor.pos());
3123                         cell_above = cursor.par()->table->GetCellAbove(cell);
3124                     }
3125                 }
3126         }
3127 #endif
3128 }
3129
3130
3131 void LyXText::CursorUpParagraph(BufferView * bview) const
3132 {
3133         if (cursor.pos() > 0) {
3134                 SetCursor(bview, cursor.par(), 0);
3135         }
3136         else if (cursor.par()->Previous()) {
3137                 SetCursor(bview, cursor.par()->Previous(), 0);
3138         }
3139 }
3140
3141
3142 void LyXText::CursorDownParagraph(BufferView * bview) const
3143 {
3144         if (cursor.par()->Next()) {
3145                 SetCursor(bview, cursor.par()->Next(), 0);
3146         } else {
3147                 SetCursor(bview, cursor.par(), cursor.par()->Last());
3148         }
3149 }
3150
3151
3152 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3153                                             LyXCursor const & old_cursor) const
3154 {
3155         // Would be wrong to delete anything if we have a selection.
3156         if (selection) return;
3157
3158         // We allow all kinds of "mumbo-jumbo" when freespacing.
3159         if (textclasslist.Style(bview->buffer()->params.textclass,
3160                                 old_cursor.par()->GetLayout()).free_spacing)
3161                 return;
3162
3163         bool deleted = false;
3164         
3165         /* Ok I'll put some comments here about what is missing.
3166            I have fixed BackSpace (and thus Delete) to not delete
3167            double-spaces automagically. I have also changed Cut,
3168            Copy and Paste to hopefully do some sensible things.
3169            There are still some small problems that can lead to
3170            double spaces stored in the document file or space at
3171            the beginning of paragraphs. This happens if you have
3172            the cursor betwenn to spaces and then save. Or if you
3173            cut and paste and the selection have a space at the
3174            beginning and then save right after the paste. I am
3175            sure none of these are very hard to fix, but I will
3176            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3177            that I can get some feedback. (Lgb)
3178         */
3179
3180         // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3181         // delete the LineSeparator.
3182         // MISSING
3183
3184         // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3185         // delete the LineSeparator.
3186         // MISSING
3187
3188         // If the pos around the old_cursor were spaces, delete one of them.
3189         if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) { 
3190                 // Only if the cursor has really moved
3191                 
3192                 if (old_cursor.pos() > 0
3193                     && old_cursor.pos() < old_cursor.par()->Last()
3194                     && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3195                     && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3196                         old_cursor.par()->Erase(old_cursor.pos() - 1);
3197                         RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3198                         // correct cursor
3199                         if (old_cursor.par() == cursor.par() &&
3200                             cursor.pos() > old_cursor.pos()) {
3201                                 SetCursorIntern(bview, cursor.par(),
3202                                                 cursor.pos() - 1);
3203                         } else
3204                                 SetCursorIntern(bview, cursor.par(),
3205                                                 cursor.pos());
3206                         return;
3207                 }
3208         }
3209
3210         // Do not delete empty paragraphs with keepempty set.
3211         if ((textclasslist.Style(bview->buffer()->params.textclass,
3212                                  old_cursor.par()->GetLayout())).keepempty)
3213                 return;
3214
3215         LyXCursor tmpcursor;
3216
3217         if (old_cursor.par() != cursor.par()) {
3218                 if ( (old_cursor.par()->Last() == 0
3219                       || (old_cursor.par()->Last() == 1
3220                           && old_cursor.par()->IsLineSeparator(0)))
3221                      && old_cursor.par()->FirstPhysicalPar()
3222                      == old_cursor.par()->LastPhysicalPar()) {
3223                         // ok, we will delete anything
3224                         
3225                         // make sure that you do not delete any environments
3226                         if ((old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3227                              !(old_cursor.row()->previous() 
3228                                && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3229                              && !(old_cursor.row()->next() 
3230                                   && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3231                             || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3232                                 && ((old_cursor.row()->previous() 
3233                                      && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3234                                     || (old_cursor.row()->next()
3235                                         && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3236                                     )) {
3237                                 status = LyXText::NEED_MORE_REFRESH;
3238                                 deleted = true;
3239                                 
3240                                 if (old_cursor.row()->previous()) {
3241                                         refresh_row = old_cursor.row()->previous();
3242                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3243                                         tmpcursor = cursor;
3244                                         cursor = old_cursor; // that undo can restore the right cursor position
3245                                         LyXParagraph * endpar = old_cursor.par()->next;
3246                                         if (endpar && endpar->GetDepth()) {
3247                                                 while (endpar && endpar->GetDepth()) {
3248                                                         endpar = endpar->LastPhysicalPar()->Next();
3249                                                 }
3250                                         }
3251                                         SetUndo(bview->buffer(), Undo::DELETE,
3252                                                 old_cursor.par()->previous,
3253                                                 endpar);
3254                                         cursor = tmpcursor;
3255
3256                                         // delete old row
3257                                         RemoveRow(old_cursor.row());
3258                                         if (OwnerParagraph() == old_cursor.par()) {
3259                                                 OwnerParagraph(OwnerParagraph()->next);
3260                                         }
3261                                         // delete old par
3262                                         delete old_cursor.par();
3263                                         
3264                                         /* Breakagain the next par. Needed
3265                                          * because of the parindent that
3266                                          * can occur or dissappear. The
3267                                          * next row can change its height,
3268                                          * if there is another layout before */
3269                                         if (refresh_row->next()) {
3270                                                 BreakAgain(bview, refresh_row->next());
3271                                                 UpdateCounters(bview, refresh_row);
3272                                         }
3273                                         SetHeightOfRow(bview, refresh_row);
3274                                 } else {
3275                                         refresh_row = old_cursor.row()->next();
3276                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3277                                         
3278                                         tmpcursor = cursor;
3279                                         cursor = old_cursor; // that undo can restore the right cursor position
3280                                         LyXParagraph * endpar = old_cursor.par()->next;
3281                                         if (endpar && endpar->GetDepth()) {
3282                                                 while (endpar && endpar->GetDepth()) {
3283                                                         endpar = endpar->LastPhysicalPar()->Next();
3284                                                 }
3285                                         }
3286                                         SetUndo(bview->buffer(), Undo::DELETE,
3287                                                 old_cursor.par()->previous,
3288                                                 endpar);
3289                                         cursor = tmpcursor;
3290
3291                                         // delete old row
3292                                         RemoveRow(old_cursor.row());
3293                                         // delete old par
3294                                         if (OwnerParagraph() == old_cursor.par()) {
3295                                                 OwnerParagraph(OwnerParagraph()->next);
3296                                         }
3297                                         delete old_cursor.par();
3298                                         
3299                                         /* Breakagain the next par. Needed
3300                                            because of the parindent that can
3301                                            occur or dissappear.
3302                                            The next row can change its height,
3303                                            if there is another layout before
3304                                         */ 
3305                                         if (refresh_row) {
3306                                                 BreakAgain(bview, refresh_row);
3307                                                 UpdateCounters(bview, refresh_row->previous());
3308                                         }
3309                                 }
3310                                 
3311                                 // correct cursor y
3312
3313                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
3314
3315                                 if (sel_cursor.par()  == old_cursor.par()
3316                                     && sel_cursor.pos() == sel_cursor.pos()) {
3317                                         // correct selection
3318                                         sel_cursor = cursor;
3319                                 }
3320                         }
3321                 }
3322                 if (!deleted) {
3323                         if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3324                                 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3325                                 // correct cursor y
3326                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
3327                                 sel_cursor = cursor;
3328                         }
3329                 }
3330         }
3331 }
3332
3333
3334 LyXParagraph * LyXText::GetParFromID(int id)
3335 {
3336         LyXParagraph * result = FirstParagraph();
3337         while (result && result->id() != id)
3338                 result = result->next;
3339         return result;
3340 }
3341
3342
3343 // undo functions
3344 bool LyXText::TextUndo(BufferView * bview)
3345 {
3346         if (inset_owner)
3347                 return false;
3348         // returns false if no undo possible
3349         Undo * undo = bview->buffer()->undostack.pop();
3350         if (undo) {
3351                 FinishUndo();
3352                 if (!undo_frozen)
3353                         bview->buffer()->redostack
3354                                 .push(CreateUndo(bview->buffer(), undo->kind, 
3355                                                  GetParFromID(undo->number_of_before_par),
3356                                                  GetParFromID(undo->number_of_behind_par)));
3357         }
3358         return TextHandleUndo(bview, undo);
3359 }
3360
3361
3362 bool LyXText::TextRedo(BufferView * bview)
3363 {
3364         if (inset_owner)
3365                 return false;
3366         // returns false if no redo possible
3367         Undo * undo = bview->buffer()->redostack.pop();
3368         if (undo) {
3369                 FinishUndo();
3370                 if (!undo_frozen)
3371                         bview->buffer()->undostack
3372                                 .push(CreateUndo(bview->buffer(), undo->kind, 
3373                                                  GetParFromID(undo->number_of_before_par),
3374                                                  GetParFromID(undo->number_of_behind_par)));
3375         }
3376         return TextHandleUndo(bview, undo);
3377 }
3378
3379
3380 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3381 {
3382         if (inset_owner)
3383                 return false;
3384         // returns false if no undo possible
3385         bool result = false;
3386         if (undo) {
3387                 LyXParagraph * before =
3388                         GetParFromID(undo->number_of_before_par); 
3389                 LyXParagraph * behind =
3390                         GetParFromID(undo->number_of_behind_par); 
3391                 LyXParagraph * tmppar;
3392                 LyXParagraph * tmppar2;
3393                 LyXParagraph * endpar;
3394                 LyXParagraph * tmppar5;
3395     
3396                 // if there's no before take the beginning
3397                 // of the document for redoing
3398                 if (!before)
3399                         SetCursorIntern(bview, FirstParagraph(), 0);
3400
3401                 // replace the paragraphs with the undo informations
3402
3403                 LyXParagraph * tmppar3 = undo->par;
3404                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3405                 LyXParagraph * tmppar4 = tmppar3;
3406                 if (tmppar4){
3407                         while (tmppar4->next)
3408                                 tmppar4 = tmppar4->next;
3409                 } // get last undo par
3410     
3411                 // now remove the old text if there is any
3412                 if (before != behind || (!behind && !before)){
3413                         if (before)
3414                                 tmppar5 = before->next;
3415                         else
3416                                 tmppar5 = OwnerParagraph();
3417                         tmppar2 = tmppar3;
3418                         while (tmppar5 && tmppar5 != behind){
3419                                 tmppar = tmppar5;
3420                                 tmppar5 = tmppar5->next;
3421                                 // a memory optimization for edit: Only layout information
3422                                 // is stored in the undo. So restore the text informations.
3423                                 if (undo->kind == Undo::EDIT) {
3424                                         tmppar2->setContentsFromPar(tmppar);
3425                                         tmppar->clearContents();
3426                                         tmppar2 = tmppar2->next;
3427                                 }
3428                         }
3429                 }
3430     
3431                 // put the new stuff in the list if there is one
3432                 if (tmppar3){
3433                         if (before)
3434                                 before->next = tmppar3;
3435                         else
3436                                 OwnerParagraph(tmppar3);
3437                         tmppar3->previous = before;
3438                 }
3439                 else {
3440                         if (!before)
3441                                 OwnerParagraph(behind);
3442                 }
3443                 if (tmppar4) {
3444                         tmppar4->next = behind;
3445                         if (behind)
3446                                 behind->previous = tmppar4;
3447                 }
3448     
3449     
3450                 // Set the cursor for redoing
3451                 if (before) {
3452                         SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3453                         // check wether before points to a closed float and open it if necessary
3454                         if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3455                             && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3456                                 tmppar4 = before;
3457                                 while (tmppar4->previous && 
3458                                        tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3459                                         tmppar4 = tmppar4->previous;
3460                                 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3461                                         tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3462                                         tmppar4 = tmppar4->next;
3463                                 }
3464                         }
3465                 }
3466     
3467                 // open a cosed footnote at the end if necessary
3468                 if (behind && behind->previous && 
3469                     behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3470                     behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3471                         while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3472                                 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3473                                 behind = behind->next;
3474                         }
3475                 }
3476     
3477                 // calculate the endpar for redoing the paragraphs.
3478                 if (behind) {
3479                         if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3480                                 endpar = behind->LastPhysicalPar()->Next();
3481                         else
3482                                 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3483                 } else
3484                         endpar = behind;
3485     
3486                 tmppar = GetParFromID(undo->number_of_cursor_par);
3487                 RedoParagraphs(bview, cursor, endpar); 
3488                 if (tmppar){
3489                         SetCursorIntern(bview, tmppar, undo->cursor_pos);
3490                         UpdateCounters(bview, cursor.row());
3491                 }
3492                 result = true;
3493                 delete undo;
3494         }
3495         FinishUndo();
3496         return result;
3497 }
3498
3499
3500 void LyXText::FinishUndo()
3501 {
3502         if (inset_owner)
3503                 return;
3504         // makes sure the next operation will be stored
3505         undo_finished = true;
3506 }
3507
3508
3509 void LyXText::FreezeUndo()
3510 {
3511         if (inset_owner)
3512                 return;
3513         // this is dangerous and for internal use only
3514         undo_frozen = true;
3515 }
3516
3517
3518 void LyXText::UnFreezeUndo()
3519 {
3520         if (inset_owner)
3521                 return;
3522         // this is dangerous and for internal use only
3523         undo_frozen = false;
3524 }
3525
3526
3527 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3528                       LyXParagraph const * before,
3529                       LyXParagraph const * behind) const
3530 {
3531         if (inset_owner)
3532                 return;
3533         if (!undo_frozen)
3534                 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3535         buf->redostack.clear();
3536 }
3537
3538
3539 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3540                       LyXParagraph const * before, LyXParagraph const * behind)
3541 {
3542         if (inset_owner)
3543                 return;
3544         buf->redostack.push(CreateUndo(buf, kind, before, behind));
3545 }
3546
3547
3548 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3549                            LyXParagraph const * before,
3550                            LyXParagraph const * behind) const
3551 {
3552         if (inset_owner)
3553                 return 0;
3554
3555         int before_number = -1;
3556         int behind_number = -1;
3557         if (before)
3558                 before_number = before->id();
3559         if (behind)
3560                 behind_number = behind->id();
3561         // Undo::EDIT  and Undo::FINISH are
3562         // always finished. (no overlapping there)
3563         // overlapping only with insert and delete inside one paragraph: 
3564         // Nobody wants all removed  character
3565         // appear one by one when undoing. 
3566         // EDIT is special since only layout information, not the
3567         // contents of a paragaph are stored.
3568         if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3569                 // check wether storing is needed
3570                 if (!buf->undostack.empty() && 
3571                     buf->undostack.top()->kind == kind &&
3572                     buf->undostack.top()->number_of_before_par ==  before_number &&
3573                     buf->undostack.top()->number_of_behind_par ==  behind_number ){
3574                         // no undo needed
3575                         return 0;
3576                 }
3577         }
3578         // create a new Undo
3579         LyXParagraph * undopar;
3580         LyXParagraph * tmppar;
3581         LyXParagraph * tmppar2;
3582
3583         LyXParagraph * start = 0;
3584         LyXParagraph * end = 0;
3585   
3586         if (before)
3587                 start = before->next;
3588         else
3589                 start = FirstParagraph();
3590         if (behind)
3591                 end = behind->previous;
3592         else {
3593                 end = FirstParagraph();
3594                 while (end->next)
3595                         end = end->next;
3596         }
3597
3598         if (start && end
3599             && start != end->next
3600             && (before != behind || (!before && !behind))) {
3601                 tmppar = start;
3602                 tmppar2 = tmppar->Clone();
3603                 tmppar2->id(tmppar->id());
3604
3605                 // a memory optimization: Just store the layout information
3606                 // when only edit
3607                 if (kind == Undo::EDIT){
3608                         //tmppar2->text.clear();
3609                         tmppar2->clearContents();
3610                 }
3611
3612                 undopar = tmppar2;
3613   
3614                 while (tmppar != end && tmppar->next) {
3615                         tmppar = tmppar->next;
3616                         tmppar2->next = tmppar->Clone();
3617                         tmppar2->next->id(tmppar->id());
3618                         // a memory optimization: Just store the layout
3619                         // information when only edit
3620                         if (kind == Undo::EDIT){
3621                                 //tmppar2->next->text.clear();
3622                                 tmppar2->clearContents();
3623                         }
3624                         tmppar2->next->previous = tmppar2;
3625                         tmppar2 = tmppar2->next;
3626                 }
3627                 tmppar2->next = 0;
3628         } else
3629                 undopar = 0; // nothing to replace (undo of delete maybe)
3630   
3631         int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3632         int cursor_pos =  cursor.par()->PositionInParFromPos(cursor.pos());
3633
3634         Undo * undo = new Undo(kind, 
3635                                before_number, behind_number,  
3636                                cursor_par, cursor_pos, 
3637                                undopar);
3638   
3639         undo_finished = false;
3640         return undo;
3641 }
3642
3643
3644 void LyXText::SetCursorParUndo(Buffer * buf)
3645 {
3646         if (inset_owner)
3647                 return;
3648         SetUndo(buf, Undo::FINISH, 
3649                 cursor.par()->ParFromPos(cursor.pos())->previous, 
3650                 cursor.par()->ParFromPos(cursor.pos())->next); 
3651 }
3652
3653
3654 #ifndef NEW_TABULAR
3655 void LyXText::RemoveTableRow(LyXCursor & cur) const
3656 {
3657         int cell = -1;
3658         int cell_org = 0;
3659         int ocell = 0;
3660     
3661         // move to the previous row
3662         int cell_act = NumberOfCell(cur.par(), cur.pos());
3663         if (cell < 0)
3664                 cell = cell_act;
3665         while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3666                 cur.pos(cur.pos() - 1);
3667         while (cur.pos() && 
3668                !cur.par()->table->IsFirstCell(cell_act)) {
3669                 cur.pos(cur.pos() - 1);
3670                 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3671                         cur.pos(cur.pos() - 1);
3672                 --cell;
3673                 --cell_act;
3674         }
3675         // now we have to pay attention if the actual table is the
3676         //   main row of TableContRows and if yes to delete all of them
3677         if (!cell_org)
3678                 cell_org = cell;
3679         do {
3680                 ocell = cell;
3681                 // delete up to the next row
3682                 while (cur.pos() < cur.par()->Last() && 
3683                        (cell_act == ocell
3684                         || !cur.par()->table->IsFirstCell(cell_act))) {
3685                         while (cur.pos() < cur.par()->Last() &&
3686                                !cur.par()->IsNewline(cur.pos()))
3687                                 cur.par()->Erase(cur.pos());
3688                         ++cell;
3689                         ++cell_act;
3690                         if (cur.pos() < cur.par()->Last())
3691                                 cur.par()->Erase(cur.pos());
3692                 }
3693                 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3694                         cur.pos(cur.pos() - 1);
3695                         cur.par()->Erase(cur.pos()); // no newline at very end!
3696                 }
3697         } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3698                  !cur.par()->table->IsContRow(cell_org) &&
3699                  cur.par()->table->IsContRow(cell));
3700         cur.par()->table->DeleteRow(cell_org);
3701         return;
3702 }
3703 #endif
3704
3705
3706 #ifndef NEW_TABULAR
3707 bool LyXText::IsEmptyTableCell() const
3708 {
3709         LyXParagraph::size_type pos = cursor.pos() - 1;
3710         while (pos >= 0 && pos < cursor.par()->Last()
3711                && !cursor.par()->IsNewline(pos))
3712                 --pos;
3713         return cursor.par()->IsNewline(pos + 1);
3714 }
3715 #endif
3716
3717
3718 void LyXText::toggleAppendix(BufferView * bview)
3719 {
3720         LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3721         bool start = !par->start_of_appendix;
3722
3723         // ensure that we have only one start_of_appendix in this document
3724         LyXParagraph * tmp = FirstParagraph();
3725         for (; tmp; tmp = tmp->next)
3726                 tmp->start_of_appendix = 0;
3727         par->start_of_appendix = start;
3728
3729         // we can set the refreshing parameters now
3730         status = LyXText::NEED_MORE_REFRESH;
3731         refresh_y = 0;
3732         refresh_row = 0; // not needed for full update
3733         UpdateCounters(bview, 0);
3734         SetCursor(bview, cursor.par(), cursor.pos());
3735 }
3736
3737 LyXParagraph * LyXText::OwnerParagraph() const
3738 {
3739         if (inset_owner)
3740                 return inset_owner->par;
3741
3742         return bv_owner->buffer()->paragraph;
3743 }
3744
3745
3746 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3747 {
3748         if (inset_owner)
3749                 inset_owner->par = p;
3750         else
3751                 bv_owner->buffer()->paragraph = p;
3752         return 0;
3753 }