]> git.lyx.org Git - lyx.git/blob - src/text2.C
572e1778df32d66d15056375b4e9856079ec3df7
[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 "lyxtext.h"
21 #include "LString.h"
22 #include "lyxparagraph.h"
23 #include "insets/inseterror.h"
24 #include "insets/insetbib.h"
25 #include "insets/insetspecialchar.h"
26 #include "insets/insettext.h"
27 #include "insets/insetfloat.h"
28 #include "layout.h"
29 #include "LyXView.h"
30 #include "support/textutils.h"
31 #include "undo.h"
32 #include "buffer.h"
33 #include "bufferparams.h"
34 #include "lyx_gui_misc.h"
35 #include "gettext.h"
36 #include "BufferView.h"
37 #include "LyXView.h"
38 #include "CutAndPaste.h"
39 #include "Painter.h"
40 #include "font.h"
41 #include "debug.h"
42 #include "lyxrc.h"
43 #include "FloatList.h"
44 #include "language.h"
45
46 using std::copy;
47 using std::find;
48 using std::endl;
49 using std::find;
50 using std::pair;
51
52
53 LyXText::LyXText(BufferView * bv)
54 {
55         bv_owner = bv;
56         inset_owner = 0;
57         init();
58 }
59
60
61 LyXText::LyXText(InsetText * inset)
62 {
63         inset_owner = inset;
64         bv_owner = 0;
65         init();
66 }
67
68
69 void LyXText::init()
70 {
71         the_locking_inset = 0;
72         firstrow = 0;
73         lastrow = 0;
74         number_of_rows = 0;
75         refresh_y = 0;
76         height = 0;
77         width = 0;
78         first = 0;
79         status = LyXText::UNCHANGED;
80         // set cursor at the very top position
81         selection = true;           /* these setting is necessary 
82                                        because of the delete-empty-
83                                        paragraph mechanism in
84                                        SetCursor */
85         if (bv_owner) {
86                 LyXParagraph * par = OwnerParagraph();
87                 current_font = GetFont(bv_owner->buffer(), par, 0);
88                 while (par) {
89                         InsertParagraph(bv_owner, par, lastrow);
90                         par = par->next();
91                 }
92                 SetCursor(bv_owner, firstrow->par(), 0);
93         } else
94                 current_font = LyXFont(LyXFont::ALL_SANE);
95
96         sel_cursor = cursor;
97         selection = false;
98         mark_set = false;
99    
100         // no rebreak necessary
101         need_break_row = 0;
102    
103         undo_finished = true;
104         undo_frozen = false;
105
106         // Default layouttype for copy environment type
107         copylayouttype = 0;
108
109 #if 0
110         // Dump all rowinformation:
111         Row * tmprow = firstrow;
112         lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
113         while (tmprow) {
114                 lyxerr << tmprow->baseline() << '\t'
115                        << tmprow->par << '\t'
116                        << tmprow->pos() << '\t'
117                        << tmprow->height << '\t'
118                        << tmprow->ascent_of_text << '\t'
119                        << tmprow->fill << '\n';
120                 tmprow = tmprow->next();
121         }
122         lyxerr.flush();
123 #endif
124 }
125
126
127 void LyXText::init(BufferView * bview)
128 {
129         if (firstrow)
130                 return;
131
132         LyXParagraph * par = OwnerParagraph();
133         current_font = GetFont(bview->buffer(), par, 0);
134         while (par) {
135                 InsertParagraph(bview, par, lastrow);
136                 par = par->next();
137         }
138         SetCursorIntern(bview, firstrow->par(), 0);
139         sel_cursor = cursor;
140 #if 0
141         // Dump all rowinformation:
142         Row * tmprow = firstrow;
143         lyxerr << "Width = " << width << endl;
144         lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
145         while (tmprow) {
146                 lyxerr << tmprow->baseline() << '\t'
147                        << tmprow->par() << '\t'
148                        << tmprow->pos() << '\t'
149                        << tmprow->height() << '\t'
150                        << tmprow->ascent_of_text() << '\t'
151                        << tmprow->fill() << '\n';
152                 tmprow = tmprow->next();
153         }
154         lyxerr.flush();
155 #endif
156 }
157
158 LyXText::~LyXText()
159 {
160         // Delete all rows, this does not touch the paragraphs!
161         Row * tmprow = firstrow;
162         while (firstrow) {
163                 tmprow = firstrow->next();
164                 delete firstrow;
165                 firstrow = tmprow;
166         }
167 }
168
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 const 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_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                                 LyXFont f = par->GetFontSettings(buf->params,
192                                                                  pos);
193                                 return f.realize(layout.reslabelfont);
194                         } else {
195                                 LyXFont f = par->GetFontSettings(buf->params, pos);
196                                 return f.realize(layout.resfont);
197                         }
198                         
199                 } else {
200                         // 5% goes here.
201                         // process layoutfont for pos == -1 and labelfont for pos < -1
202                         if (pos == -1)
203                                 return layout.resfont;
204                         else
205                                 return layout.reslabelfont;
206                 }
207         }
208
209         // The uncommon case need not be optimized as much
210
211         LyXFont layoutfont, tmpfont;
212
213         if (pos >= 0){
214                 // 95% goes here
215                 if (pos < BeginningOfMainBody(buf, par)) {
216                         // 1% goes here
217                         layoutfont = layout.labelfont;
218                 } else {
219                         // 99% goes here
220                         layoutfont = layout.font;
221                 }
222                 tmpfont = par->GetFontSettings(buf->params, pos);
223                 tmpfont.realize(layoutfont);
224         } else {
225                 // 5% goes here.
226                 // process layoutfont for pos == -1 and labelfont for pos < -1
227                 if (pos == -1)
228                         tmpfont = layout.font;
229                 else
230                         tmpfont = layout.labelfont;
231         }
232
233         // Resolve against environment font information
234         while (par && par_depth && !tmpfont.resolved()) {
235                 par = par->DepthHook(par_depth - 1);
236                 if (par) {
237                         tmpfont.realize(textclasslist.
238                                         Style(buf->params.textclass,
239                                               par->GetLayout()).font);
240                         par_depth = par->GetDepth();
241                 }
242         }
243
244         tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
245
246         return tmpfont;
247 }
248
249
250 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
251                           LyXParagraph::size_type pos,
252                           LyXFont const & fnt)
253 {
254         LyXFont font(fnt);
255         // Let the insets convert their font
256         if (par->GetChar(pos) == LyXParagraph::META_INSET) {
257                 if (par->GetInset(pos))
258                         font = par->GetInset(pos)->ConvertFont(font);
259         }
260
261         LyXLayout const & layout =
262                 textclasslist.Style(buf->params.textclass,
263                                     par->GetLayout());
264
265         // Get concrete layout font to reduce against
266         LyXFont layoutfont;
267
268         if (pos < BeginningOfMainBody(buf, par))
269                 layoutfont = layout.labelfont;
270         else
271                 layoutfont = layout.font;
272
273         // Realize against environment font information
274         if (par->GetDepth()){
275                 LyXParagraph * tp = par;
276                 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
277                         tp = tp->DepthHook(tp->GetDepth()-1);
278                         if (tp)
279                                 layoutfont.realize(textclasslist.
280                                                 Style(buf->params.textclass,
281                                                       tp->GetLayout()).font);
282                 }
283         }
284
285         layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
286
287         // Now, reduce font against full layout font
288         font.reduce(layoutfont);
289
290         par->SetFont(pos, font);
291 }
292
293
294 /* inserts a new row behind the specified row, increments
295  * the touched counters */
296 void LyXText::InsertRow(Row * row, LyXParagraph * par,
297                         LyXParagraph::size_type pos) const
298 {
299         Row * tmprow = new Row;
300         if (!row) {
301                 tmprow->previous(0);
302                 tmprow->next(firstrow);
303                 firstrow = tmprow;
304         } else {
305                 tmprow->previous(row);
306                 tmprow->next(row->next());
307                 row->next(tmprow);
308         }
309    
310         if (tmprow->next())
311                 tmprow->next()->previous(tmprow);
312    
313         if (tmprow->previous())
314                 tmprow->previous()->next(tmprow);
315    
316    
317         tmprow->par(par);
318         tmprow->pos(pos);
319
320         if (row == lastrow)
321                 lastrow = tmprow;
322         ++number_of_rows; // one more row
323 }
324
325
326 // removes the row and reset the touched counters
327 void LyXText::RemoveRow(Row * row) const
328 {
329         /* this must not happen before the currentrow for clear reasons.
330            so the trick is just to set the current row onto the previous
331            row of this row */
332         int unused_y;
333         GetRow(row->par(), row->pos(), unused_y);
334    
335         if (row->next())
336                 row->next()->previous(row->previous());
337         if (!row->previous()) {
338                 firstrow = row->next();
339         } else  {
340                 row->previous()->next(row->next());
341         }
342         if (row == lastrow)
343                 lastrow = row->previous();
344    
345         height -= row->height(); // the text becomes smaller
346    
347         delete row;
348         --number_of_rows;       // one row less
349 }
350
351
352 // remove all following rows of the paragraph of the specified row.
353 void LyXText::RemoveParagraph(Row * row) const
354 {
355         LyXParagraph * tmppar = row->par();
356         row = row->next();
357     
358         Row * tmprow;
359         while (row && row->par() == tmppar) {
360                 tmprow = row->next();
361                 RemoveRow(row);
362                 row = tmprow;
363         }
364 }
365    
366
367 // insert the specified paragraph behind the specified row
368 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
369                               Row * row) const
370 {
371         InsertRow(row, par, 0);        /* insert a new row, starting 
372                                         * at postition 0 */
373
374         SetCounter(bview->buffer(), par);  // set the counters
375    
376         // and now append the whole paragraph behind the new row
377         if (!row) {
378                 firstrow->height(0);
379                 AppendParagraph(bview, firstrow);
380         } else {
381                 row->next()->height(0);
382                 AppendParagraph(bview, row->next());
383         }
384 }
385
386
387 /* used in setlayout */
388 // Asger is not sure we want to do this...
389 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
390                                             LyXParagraph * par)
391 {
392    
393         LyXLayout const & layout =
394                 textclasslist.Style(buf->params.textclass, par->GetLayout());
395
396         LyXFont layoutfont, tmpfont;
397         for (LyXParagraph::size_type pos = 0;
398              pos < par->size(); ++pos) {
399                 if (pos < BeginningOfMainBody(buf, par))
400                         layoutfont = layout.labelfont;
401                 else
402                         layoutfont = layout.font;
403       
404                 tmpfont = par->GetFontSettings(buf->params, pos);
405                 tmpfont.reduce(layoutfont);
406                 par->SetFont(pos, tmpfont);
407         }
408 }
409
410
411 LyXParagraph * LyXText::SetLayout(BufferView * bview,
412                                   LyXCursor & cur, LyXCursor & sstart_cur,
413                                   LyXCursor & send_cur,
414                                   LyXTextClass::size_type layout)
415 {
416         LyXParagraph * endpar = send_cur.par()->next();
417         LyXParagraph * undoendpar = endpar;
418         
419         if (endpar && endpar->GetDepth()) {
420                 while (endpar && endpar->GetDepth()) {
421                         endpar = endpar->next();
422                         undoendpar = endpar;
423                 }
424         } else if (endpar) {
425                 endpar = endpar->next(); // because of parindents etc.
426         }
427         
428         SetUndo(bview->buffer(), Undo::EDIT,
429                 sstart_cur.par()->previous(),
430                 undoendpar);
431         
432         /* ok we have a selection. This is always between sstart_cur
433          * and sel_end cursor */ 
434         cur = sstart_cur;
435         
436         LyXLayout const & lyxlayout =
437                 textclasslist.Style(bview->buffer()->params.textclass, layout);
438         
439         while (cur.par() != send_cur.par()) {
440                 cur.par()->SetLayout(layout);
441                 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
442                 LyXParagraph * fppar = cur.par();
443                 fppar->params.spaceTop(lyxlayout.fill_top ?
444                                        VSpace(VSpace::VFILL)
445                                        : VSpace(VSpace::NONE));
446                 fppar->params.spaceBottom(lyxlayout.fill_bottom ? 
447                                           VSpace(VSpace::VFILL)
448                                           : VSpace(VSpace::NONE));
449                 if (lyxlayout.margintype == MARGIN_MANUAL)
450                         cur.par()->SetLabelWidthString(lyxlayout.labelstring());
451                 if (lyxlayout.labeltype != LABEL_BIBLIO
452                     && fppar->bibkey) {
453                         delete fppar->bibkey;
454                         fppar->bibkey = 0;
455                 }
456                 cur.par(cur.par()->next());
457         }
458         cur.par()->SetLayout(layout);
459         MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
460         LyXParagraph * fppar = cur.par();
461         fppar->params.spaceTop(lyxlayout.fill_top ?
462                                VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
463         fppar->params.spaceBottom(lyxlayout.fill_bottom ? 
464                                   VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
465         if (lyxlayout.margintype == MARGIN_MANUAL)
466                 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
467         if (lyxlayout.labeltype != LABEL_BIBLIO
468             && fppar->bibkey) {
469                 delete fppar->bibkey;
470                 fppar->bibkey = 0;
471         }
472         return endpar;
473 }
474
475
476 // set layout over selection and make a total rebreak of those paragraphs
477 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
478 {
479         LyXCursor tmpcursor = cursor;  /* store the current cursor  */
480
481         // if there is no selection just set the layout
482         // of the current paragraph  */
483         if (!selection) {
484                 sel_start_cursor = cursor;  // dummy selection
485                 sel_end_cursor = cursor;
486         }
487         LyXParagraph *
488                 endpar = SetLayout(bview, cursor, sel_start_cursor,
489                                    sel_end_cursor, layout);
490         RedoParagraphs(bview, sel_start_cursor, endpar);
491    
492         // we have to reset the selection, because the
493         // geometry could have changed
494         SetCursor(bview, sel_start_cursor.par(),
495                   sel_start_cursor.pos(), false);
496         sel_cursor = cursor;
497         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
498                   false);
499         UpdateCounters(bview, cursor.row());
500         ClearSelection(bview);
501         SetSelection(bview);
502         SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
503 }
504
505
506 // increment depth over selection and
507 // make a total rebreak of those paragraphs
508 void  LyXText::IncDepth(BufferView * bview)
509 {
510         // If there is no selection, just use the current paragraph
511         if (!selection) {
512                 sel_start_cursor = cursor; // dummy selection
513                 sel_end_cursor = cursor;
514         }
515
516         // We end at the next paragraph with depth 0
517         LyXParagraph * endpar = sel_end_cursor.par()->next();
518
519         LyXParagraph * undoendpar = endpar;
520
521         if (endpar && endpar->GetDepth()) {
522                 while (endpar && endpar->GetDepth()) {
523                         endpar = endpar->next();
524                         undoendpar = endpar;
525                 }
526         }
527         else if (endpar) {
528                 endpar = endpar->next(); // because of parindents etc.
529         }
530         
531         SetUndo(bview->buffer(), Undo::EDIT,
532                 sel_start_cursor.par()->previous(),
533                 undoendpar);
534
535         LyXCursor tmpcursor = cursor; // store the current cursor
536
537         // ok we have a selection. This is always between sel_start_cursor
538         // and sel_end cursor
539         cursor = sel_start_cursor;
540    
541         bool anything_changed = false;
542    
543         while (true) {
544                 // NOTE: you can't change the depth of a bibliography entry
545                 if (
546                     textclasslist.Style(bview->buffer()->params.textclass,
547                                       cursor.par()->GetLayout()
548                                      ).labeltype != LABEL_BIBLIO) {
549                         LyXParagraph * prev = cursor.par()->previous();
550
551                         if (prev 
552                             && (prev->GetDepth() - cursor.par()->GetDepth() > 0
553                                 || (prev->GetDepth() == cursor.par()->GetDepth()
554                                     && textclasslist.Style(bview->buffer()->params.textclass,
555                                                       prev->GetLayout()).isEnvironment()))) {
556                                 cursor.par()->params.depth(cursor.par()->params.depth() + 1);
557                                 anything_changed = true;
558                                 }
559                 }
560                 if (cursor.par() == sel_end_cursor.par())
561                        break;
562                 cursor.par(cursor.par()->next());
563         }
564    
565         // if nothing changed set all depth to 0
566         if (!anything_changed) {
567                 cursor = sel_start_cursor;
568                 while (cursor.par() != sel_end_cursor.par()) {
569                         cursor.par()->params.depth(0);
570                         cursor.par(cursor.par()->next());
571                 }
572                 cursor.par()->params.depth(0);
573         }
574    
575         RedoParagraphs(bview, sel_start_cursor, endpar);
576    
577         // we have to reset the selection, because the
578         // geometry could have changed
579         SetCursor(bview, sel_start_cursor.par(),
580                   sel_start_cursor.pos());
581         sel_cursor = cursor;
582         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
583         UpdateCounters(bview, cursor.row());
584         ClearSelection(bview);
585         SetSelection(bview);
586         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
587 }
588
589
590 // decrement depth over selection and
591 // make a total rebreak of those paragraphs
592 void  LyXText::DecDepth(BufferView * bview)
593 {
594         // if there is no selection just set the layout
595         // of the current paragraph
596         if (!selection) {
597                 sel_start_cursor = cursor; // dummy selection
598                 sel_end_cursor = cursor;
599         }
600         LyXParagraph * endpar = sel_end_cursor.par()->next();
601         LyXParagraph * undoendpar = endpar;
602
603         if (endpar && endpar->GetDepth()) {
604                 while (endpar && endpar->GetDepth()) {
605                         endpar = endpar->next();
606                         undoendpar = endpar;
607                 }
608         }
609         else if (endpar) {
610                 endpar = endpar->next(); // because of parindents etc.
611         }
612    
613         SetUndo(bview->buffer(), Undo::EDIT,
614                 sel_start_cursor.par()->previous(),
615                 undoendpar);
616
617         LyXCursor tmpcursor = cursor; // store the current cursor
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         while (true) {
624                 if (cursor.par()->params.depth())
625                         cursor.par()->params.depth(cursor.par()->params.depth() - 1);
626                 if (cursor.par() == sel_end_cursor.par())
627                         break;
628                 cursor.par(cursor.par()->next());
629         }
630
631         RedoParagraphs(bview, sel_start_cursor, endpar);
632    
633         // we have to reset the selection, because the
634         // geometry could have changed
635         SetCursor(bview, sel_start_cursor.par(),
636                   sel_start_cursor.pos());
637         sel_cursor = cursor;
638         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
639         UpdateCounters(bview, cursor.row());
640         ClearSelection(bview);
641         SetSelection(bview);
642         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
643 }
644
645
646 // set font over selection and make a total rebreak of those paragraphs
647 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
648 {
649         // if there is no selection just set the current_font
650         if (!selection) {
651                 // Determine basis font
652                 LyXFont layoutfont;
653                 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
654                                                        cursor.par()))
655                         layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
656                 else
657                         layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
658                 // Update current font
659                 real_current_font.update(font,
660                                          bview->buffer()->params.language,
661                                          toggleall);
662
663                 // Reduce to implicit settings
664                 current_font = real_current_font;
665                 current_font.reduce(layoutfont);
666                 // And resolve it completely
667                 real_current_font.realize(layoutfont);
668                 return;
669         }
670
671         LyXCursor tmpcursor = cursor; // store the current cursor
672    
673         // ok we have a selection. This is always between sel_start_cursor
674         // and sel_end cursor
675    
676         SetUndo(bview->buffer(), Undo::EDIT,
677                 sel_start_cursor.par()->previous(),
678                 sel_end_cursor.par()->next()); 
679         cursor = sel_start_cursor;
680         while (cursor.par() != sel_end_cursor.par() ||
681                (cursor.pos() < sel_end_cursor.pos())) {
682                 if (cursor.pos() < cursor.par()->size()) {
683                         // an open footnote should behave
684                         // like a closed one
685                         LyXFont newfont = GetFont(bview->buffer(), 
686                                                   cursor.par(), cursor.pos());
687                         newfont.update(font,
688                                        bview->buffer()->params.language,
689                                        toggleall);
690                         SetCharFont(bview->buffer(),
691                                     cursor.par(), cursor.pos(), newfont);
692                         cursor.pos(cursor.pos() + 1);
693                 } else {
694                         cursor.pos(0);
695                         cursor.par(cursor.par()->next());
696                 }
697         }
698    
699         RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->next());
700    
701         // we have to reset the selection, because the
702         // geometry could have changed
703         SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
704         sel_cursor = cursor;
705         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
706         ClearSelection(bview);
707         SetSelection(bview);
708         SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
709                   tmpcursor.boundary());
710 }
711
712
713 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
714 {
715         Row * tmprow = cur.row();
716         int y = cur.y() - tmprow->baseline();
717
718         SetHeightOfRow(bview, tmprow);
719         LyXParagraph * first_phys_par = tmprow->par();
720
721         // find the first row of the paragraph
722         if (first_phys_par != tmprow->par())
723                 while (tmprow->previous()
724                        && tmprow->previous()->par() != first_phys_par) {
725                         tmprow = tmprow->previous();
726                         y -= tmprow->height();
727                         SetHeightOfRow(bview, tmprow);
728                 }
729         while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
730                 tmprow = tmprow->previous();
731                 y -= tmprow->height();
732                 SetHeightOfRow(bview, tmprow);
733         }
734         
735         // we can set the refreshing parameters now
736         status = LyXText::NEED_MORE_REFRESH;
737         refresh_y = y;
738         refresh_row = tmprow;
739         SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
740 }
741
742
743 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
744 {
745         Row * tmprow = cur.row();
746    
747         int y = cur.y() - tmprow->baseline();
748         SetHeightOfRow(bview, tmprow);
749         LyXParagraph * first_phys_par = tmprow->par();
750
751         // find the first row of the paragraph
752         if (first_phys_par != tmprow->par())
753                 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par)  {
754                         tmprow = tmprow->previous();
755                         y -= tmprow->height();
756                 }
757         while (tmprow->previous() && tmprow->previous()->par() == first_phys_par)  {
758                 tmprow = tmprow->previous();
759                 y -= tmprow->height();
760         }
761    
762         // we can set the refreshing parameters now
763         if (status == LyXText::UNCHANGED || y < refresh_y) {
764                 refresh_y = y;
765                 refresh_row = tmprow;
766         }
767         status = LyXText::NEED_MORE_REFRESH;
768         SetCursor(bview, cur.par(), cur.pos());
769 }
770
771
772 /* deletes and inserts again all paragaphs between the cursor
773 * and the specified par 
774 * This function is needed after SetLayout and SetFont etc. */
775 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
776                              LyXParagraph const * endpar) const
777 {
778         Row * tmprow2;
779         LyXParagraph * tmppar = 0, * first_phys_par = 0;
780    
781         Row * tmprow = cur.row();
782    
783         int y = cur.y() - tmprow->baseline();
784    
785         if (!tmprow->previous()){
786                 first_phys_par = FirstParagraph();   // a trick/hack for UNDO
787         } else {
788                 first_phys_par = tmprow->par();
789                 // find the first row of the paragraph
790                 if (first_phys_par != tmprow->par())
791                         while (tmprow->previous() &&
792                                (tmprow->previous()->par() != first_phys_par)) {
793                                 tmprow = tmprow->previous();
794                                 y -= tmprow->height();
795                         }
796                 while (tmprow->previous()
797                        && tmprow->previous()->par() == first_phys_par) {
798                         tmprow = tmprow->previous();
799                         y -= tmprow->height();
800                 }
801         }
802    
803         // we can set the refreshing parameters now
804         status = LyXText::NEED_MORE_REFRESH;
805         refresh_y = y;
806         refresh_row = tmprow->previous();        /* the real refresh row will
807                                             be deleted, so I store
808                                             the previous here */ 
809         // remove it
810         if (tmprow->next())
811                 tmppar = tmprow->next()->par();
812         else
813                 tmppar = 0;
814         while (tmppar != endpar) {
815                 RemoveRow(tmprow->next());
816                 if (tmprow->next())
817                         tmppar = tmprow->next()->par();
818                 else
819                         tmppar = 0;
820         }  
821    
822         // remove the first one
823         tmprow2 = tmprow;     /* this is because tmprow->previous()
824                                  can be 0 */
825         tmprow = tmprow->previous();
826         RemoveRow(tmprow2);
827    
828         tmppar = first_phys_par;
829
830         do {
831                 if (tmppar) {
832                         InsertParagraph(bview, tmppar, tmprow);
833                         if (!tmprow)
834                                 tmprow = firstrow;
835                         while (tmprow->next() && tmprow->next()->par() == tmppar)
836                                 tmprow = tmprow->next();
837                         tmppar = tmppar->next();
838                 }
839         } while (tmppar != endpar);
840    
841         // this is because of layout changes
842         if (refresh_row) {
843                 refresh_y -= refresh_row->height();
844                 SetHeightOfRow(bview, refresh_row);   
845         } else {
846                 refresh_row = firstrow;
847                 refresh_y = 0;
848                 SetHeightOfRow(bview, refresh_row);   
849         }
850    
851         if (tmprow && tmprow->next())
852                 SetHeightOfRow(bview, tmprow->next());
853 }
854
855
856 bool LyXText::FullRebreak(BufferView * bview)
857 {
858         if (!firstrow) {
859                 init(bview);
860                 return true;
861         }
862         if (need_break_row) {
863                 BreakAgain(bview, need_break_row);
864                 need_break_row = 0;
865                 return true;
866         }
867         return false;
868 }
869
870
871 /* important for the screen */
872
873
874 /* the cursor set functions have a special mechanism. When they
875  * realize, that you left an empty paragraph, they will delete it.
876  * They also delete the corresponding row */
877    
878 // need the selection cursor:
879 void LyXText::SetSelection(BufferView * bview)
880 {
881         const bool lsel = selection;
882
883         if (!selection) {
884                 last_sel_cursor = sel_cursor;
885                 sel_start_cursor = sel_cursor;
886                 sel_end_cursor = sel_cursor;
887         }
888    
889         selection = true;
890    
891         // first the toggling area
892         if (cursor.y() < last_sel_cursor.y()
893             || (cursor.y() == last_sel_cursor.y()
894              && cursor.x() < last_sel_cursor.x())) {
895                 toggle_end_cursor = last_sel_cursor;
896                 toggle_cursor = cursor;
897         } else {
898                 toggle_end_cursor = cursor;
899                 toggle_cursor = last_sel_cursor;
900         }
901    
902         last_sel_cursor = cursor;
903    
904         // and now the whole selection
905
906         if (sel_cursor.par() == cursor.par())
907            if (sel_cursor.pos() < cursor.pos()) {
908                 sel_end_cursor = cursor;
909                 sel_start_cursor = sel_cursor;
910         } else {
911                 sel_end_cursor = sel_cursor; 
912                 sel_start_cursor = cursor;
913         }
914         else if (sel_cursor.y() < cursor.y() ||
915             (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
916                 sel_end_cursor = cursor;
917                 sel_start_cursor = sel_cursor;
918         }
919         else {
920                 sel_end_cursor = sel_cursor; 
921                 sel_start_cursor = cursor;
922         }
923    
924         // a selection with no contents is not a selection
925         if (sel_start_cursor.par() == sel_end_cursor.par() && 
926             sel_start_cursor.pos() == sel_end_cursor.pos())
927                 selection = false;
928
929         if (inset_owner && (selection || lsel))
930                 inset_owner->SetUpdateStatus(bview, InsetText::SELECTION);
931 }
932
933
934 string const LyXText::selectionAsString(Buffer const * buffer) const
935 {
936         if (!selection) return string();
937         string result;
938         
939         // Special handling if the whole selection is within one paragraph
940         if (sel_start_cursor.par() == sel_end_cursor.par()) {
941                 result += sel_start_cursor.par()->String(buffer,
942                                                          sel_start_cursor.pos(),
943                                                          sel_end_cursor.pos());
944                 return result;
945         }
946         
947         // The selection spans more than one paragraph
948
949         // First paragraph in selection
950         result += sel_start_cursor.par()->String(buffer,
951                                                  sel_start_cursor.pos(),
952                                                  sel_start_cursor.par()->size())
953                 + "\n\n";
954         
955         // The paragraphs in between (if any)
956         LyXCursor tmpcur(sel_start_cursor);
957         tmpcur.par(tmpcur.par()->next());
958         while (tmpcur.par() != sel_end_cursor.par()) {
959                 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->size()) + "\n\n";
960                 tmpcur.par(tmpcur.par()->next()); // Or NextAfterFootnote??
961         }
962
963         // Last paragraph in selection
964         result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
965         
966         return result;
967 }
968
969
970 void LyXText::ClearSelection(BufferView * /*bview*/) const
971 {
972         selection = false;
973         mark_set = false;
974 }
975
976
977 void LyXText::CursorHome(BufferView * bview) const
978 {
979         SetCursor(bview, cursor.par(), cursor.row()->pos());
980 }
981
982
983 void LyXText::CursorEnd(BufferView * bview) const
984 {
985         if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
986                 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
987         else {
988                 if (cursor.par()->size() &&
989                     (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
990                      || cursor.par()->IsNewline(RowLast(cursor.row()))))
991                         SetCursor(bview, cursor.par(), RowLast(cursor.row()));
992                 else
993                         SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
994         }
995 }
996
997
998 void LyXText::CursorTop(BufferView * bview) const
999 {
1000         while (cursor.par()->previous())
1001                 cursor.par(cursor.par()->previous());
1002         SetCursor(bview, cursor.par(), 0);
1003 }
1004
1005
1006 void LyXText::CursorBottom(BufferView * bview) const
1007 {
1008         while (cursor.par()->next())
1009                 cursor.par(cursor.par()->next());
1010         SetCursor(bview, cursor.par(), cursor.par()->size());
1011 }
1012    
1013    
1014 void LyXText::ToggleFree(BufferView * bview,
1015                          LyXFont const & font, bool toggleall)
1016 {
1017         // If the mask is completely neutral, tell user
1018         if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1019                 // Could only happen with user style
1020                 bview->owner()->message(_("No font change defined. Use Character under the Layout menu to define font change."));
1021                 return;
1022         }
1023
1024         // Try implicit word selection
1025         // If there is a change in the language the implicit word selection 
1026         // is disabled.
1027         LyXCursor resetCursor = cursor;
1028         bool implicitSelection = (font.language() == ignore_language
1029                                   && font.number() == LyXFont::IGNORE)
1030                 ? SelectWordWhenUnderCursor(bview) : false;
1031
1032         // Set font
1033         SetFont(bview, font, toggleall);
1034
1035         /* Implicit selections are cleared afterwards and cursor is set to the
1036            original position. */
1037         if (implicitSelection) {
1038                 ClearSelection(bview);
1039                 cursor = resetCursor;
1040                 SetCursor(bview, cursor.par(), cursor.pos());
1041                 sel_cursor = cursor;
1042         }
1043         if (inset_owner)
1044                 inset_owner->SetUpdateStatus(bview, InsetText::CURSOR_PAR);
1045 }
1046
1047
1048 LyXParagraph::size_type
1049 LyXText::BeginningOfMainBody(Buffer const * buf,
1050                              LyXParagraph const * par) const
1051 {
1052         if (textclasslist.Style(buf->params.textclass,
1053                                 par->GetLayout()).labeltype != LABEL_MANUAL)
1054                 return 0;
1055         else
1056                 return par->BeginningOfMainBody();
1057 }
1058
1059
1060 /* the DTP switches for paragraphs. LyX will store them in the 
1061 * first physicla paragraph. When a paragraph is broken, the top settings 
1062 * rest, the bottom settings are given to the new one. So I can make shure, 
1063 * they do not duplicate themself and you cannnot make dirty things with 
1064 * them!  */ 
1065
1066 void LyXText::SetParagraph(BufferView * bview,
1067                            bool line_top, bool line_bottom,
1068                            bool pagebreak_top, bool pagebreak_bottom,
1069                            VSpace const & space_top,
1070                            VSpace const & space_bottom,
1071                            LyXAlignment align, 
1072                            string labelwidthstring,
1073                            bool noindent) 
1074 {
1075         LyXCursor tmpcursor = cursor;
1076         if (!selection) {
1077                 sel_start_cursor = cursor;
1078                 sel_end_cursor = cursor;
1079         }
1080
1081         // make sure that the depth behind the selection are restored, too
1082         LyXParagraph * endpar = sel_end_cursor.par()->next();
1083         LyXParagraph * undoendpar = endpar;
1084
1085         if (endpar && endpar->GetDepth()) {
1086                 while (endpar && endpar->GetDepth()) {
1087                         endpar = endpar->next();
1088                         undoendpar = endpar;
1089                 }
1090         }
1091         else if (endpar) {
1092                 endpar = endpar->next(); // because of parindents etc.
1093         }
1094    
1095         SetUndo(bview->buffer(), Undo::EDIT,
1096                 sel_start_cursor.par()->previous(),
1097                 undoendpar);
1098
1099         
1100         LyXParagraph * tmppar = sel_end_cursor.par();
1101         while (tmppar != sel_start_cursor.par()->previous()) {
1102                 SetCursor(bview, tmppar, 0);
1103                 status = LyXText::NEED_MORE_REFRESH;
1104                 refresh_row = cursor.row();
1105                 refresh_y = cursor.y() - cursor.row()->baseline();
1106                         cursor.par()->params.lineTop(line_top);
1107                         cursor.par()->params.lineBottom(line_bottom);
1108                         cursor.par()->params.pagebreakTop(pagebreak_top);
1109                         cursor.par()->params.pagebreakBottom(pagebreak_bottom);
1110                         cursor.par()->params.spaceTop(space_top);
1111                         cursor.par()->params.spaceBottom(space_bottom);
1112                         // does the layout allow the new alignment?
1113                         if (align == LYX_ALIGN_LAYOUT)
1114                                 align = textclasslist
1115                                         .Style(bview->buffer()->params.textclass,
1116                                                cursor.par()->GetLayout()).align;
1117                         if (align & textclasslist
1118                             .Style(bview->buffer()->params.textclass,
1119                                    cursor.par()->GetLayout()).alignpossible) {
1120                                 if (align == textclasslist
1121                                     .Style(bview->buffer()->params.textclass,
1122                                            cursor.par()->GetLayout()).align)
1123                                         cursor.par()->params.align(LYX_ALIGN_LAYOUT);
1124                                 else
1125                                         cursor.par()->params.align(align);
1126                         }
1127                         cursor.par()->SetLabelWidthString(labelwidthstring);
1128                         cursor.par()->params.noindent(noindent);
1129                 tmppar = cursor.par()->previous();
1130         }
1131         
1132         RedoParagraphs(bview, sel_start_cursor, endpar);
1133         
1134         ClearSelection(bview);
1135         SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1136         sel_cursor = cursor;
1137         SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1138         SetSelection(bview);
1139         SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1140         if (inset_owner)
1141             bview->updateInset(inset_owner, true);
1142 }
1143
1144
1145 char loweralphaCounter(int n)
1146 {
1147         if (n < 1 || n > 26)
1148                 return '?';
1149         else
1150                 return 'a' + n - 1;
1151 }
1152
1153
1154 namespace {
1155
1156 inline
1157 char alphaCounter(int n)
1158 {
1159         if (n < 1 || n > 26)
1160                 return '?';
1161         else
1162                 return 'A' + n - 1;
1163 }
1164
1165
1166 inline
1167 char hebrewCounter(int n)
1168 {
1169         static const char hebrew[22] = {
1170                 'à', 'á', 'â', 'ã', 'ä', 'Ã¥', 'æ', 'ç', 'è',
1171                 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö', 
1172                 '÷', 'ø', 'ù', 'ú'
1173         };
1174         if (n < 1 || n > 22)
1175                 return '?';
1176         else
1177                 return hebrew[n-1];
1178 }
1179
1180
1181 inline
1182 string const romanCounter(int n)
1183 {
1184         static char const * roman[20] = {
1185                 "i",   "ii",  "iii", "iv", "v",
1186                 "vi",  "vii", "viii", "ix", "x",
1187                 "xi",  "xii", "xiii", "xiv", "xv",
1188                 "xvi", "xvii", "xviii", "xix", "xx"
1189         };
1190         if (n < 1 || n > 20)
1191                 return "??";
1192         else
1193                 return roman[n-1];
1194 }
1195
1196 } // namespace anon
1197
1198
1199 // set the counter of a paragraph. This includes the labels
1200 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1201 {
1202         LyXLayout const & layout =
1203                 textclasslist.Style(buf->params.textclass, 
1204                                     par->GetLayout());
1205
1206         LyXTextClass const & textclass =
1207                 textclasslist.TextClass(buf->params.textclass);
1208
1209         /* copy the prev-counters to this one, unless this is the start of a 
1210            footnote or of a bibliography or the very first paragraph */
1211         if (par->previous()
1212             && !(textclasslist.Style(buf->params.textclass,
1213                                 par->previous()->GetLayout()
1214                                 ).labeltype != LABEL_BIBLIO
1215                  && layout.labeltype == LABEL_BIBLIO)) {
1216                 for (int i = 0; i < 10; ++i) {
1217                         par->setCounter(i, par->previous()->GetFirstCounter(i));
1218                 }
1219                 par->params.appendix(par->previous()->params.appendix());
1220                 if (!par->params.appendix() && par->params.startOfAppendix()) {
1221                   par->params.appendix(true);
1222                   for (int i = 0; i < 10; ++i) {
1223                     par->setCounter(i, 0);
1224                   }  
1225                 }
1226                 par->enumdepth = par->previous()->enumdepth;
1227                 par->itemdepth = par->previous()->itemdepth;
1228         } else {
1229                 for (int i = 0; i < 10; ++i) {
1230                         par->setCounter(i, 0);
1231                 }  
1232                 par->params.appendix(par->params.startOfAppendix());
1233                 par->enumdepth = 0;
1234                 par->itemdepth = 0;
1235         }
1236
1237         /* Maybe we have to increment the enumeration depth.
1238          * BUT, enumeration in a footnote is considered in isolation from its
1239          *      surrounding paragraph so don't increment if this is the
1240          *      first line of the footnote
1241          * AND, bibliographies can't have their depth changed ie. they
1242          *      are always of depth 0
1243          */
1244         if (par->previous()
1245             && par->previous()->GetDepth() < par->GetDepth()
1246             && textclasslist.Style(buf->params.textclass,
1247                               par->previous()->GetLayout()
1248                              ).labeltype == LABEL_COUNTER_ENUMI
1249             && par->enumdepth < 3
1250             && layout.labeltype != LABEL_BIBLIO) {
1251                 par->enumdepth++;
1252         }
1253
1254         /* Maybe we have to decrement the enumeration depth, see note above */
1255         if (par->previous()
1256             && par->previous()->GetDepth() > par->GetDepth()
1257             && layout.labeltype != LABEL_BIBLIO) {
1258                 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1259                 par->setCounter(6 + par->enumdepth,
1260                         par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1261                 /* reset the counters.
1262                  * A depth change is like a breaking layout
1263                  */
1264                 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1265                         par->setCounter(i, 0);
1266         }
1267    
1268         if (!par->params.labelString().empty()) {
1269                 par->params.labelString(string());
1270         }
1271    
1272         if (layout.margintype == MARGIN_MANUAL) {
1273                 if (par->params.labelWidthString().empty()) {
1274                         par->SetLabelWidthString(layout.labelstring());
1275                 }
1276         } else {
1277                 par->SetLabelWidthString(string());
1278         }
1279    
1280         /* is it a layout that has an automatic label ? */ 
1281         if (layout.labeltype >=  LABEL_COUNTER_CHAPTER) {
1282       
1283                 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1284                 if (i >= 0 && i<= buf->params.secnumdepth) {
1285                         par->incCounter(i);     // increment the counter  
1286          
1287                         // Is there a label? Useful for Chapter layout
1288                         if (!par->params.appendix()) {
1289                                 if (!layout.labelstring().empty())
1290                                         par->params.labelString(layout.labelstring());
1291                                 else
1292                                         par->params.labelString(string());
1293                         } else {
1294                                 if (!layout.labelstring_appendix().empty())
1295                                         par->params.labelString(layout.labelstring_appendix());
1296                                 else
1297                                         par->params.labelString(string());
1298                         }
1299
1300                         std::ostringstream s;
1301
1302                         if (!par->params.appendix()) {
1303                                 switch (2 * LABEL_COUNTER_CHAPTER -
1304                                         textclass.maxcounter() + i) {
1305                                 case LABEL_COUNTER_CHAPTER:
1306                                         s << par->getCounter(i);
1307                                         break;
1308                                 case LABEL_COUNTER_SECTION:
1309                                         s << par->getCounter(i - 1) << '.'
1310                                            << par->getCounter(i);
1311                                         break;
1312                                 case LABEL_COUNTER_SUBSECTION:
1313                                         s << par->getCounter(i - 2) << '.'
1314                                           << par->getCounter(i - 1) << '.'
1315                                           << par->getCounter(i);
1316                                         break;
1317                                 case LABEL_COUNTER_SUBSUBSECTION:
1318                                         s << par->getCounter(i - 3) << '.'
1319                                           << par->getCounter(i - 2) << '.'
1320                                           << par->getCounter(i - 1) << '.'
1321                                           << par->getCounter(i);
1322                                         
1323                                         break;
1324                                 case LABEL_COUNTER_PARAGRAPH:
1325                                         s << par->getCounter(i - 4) << '.'
1326                                           << par->getCounter(i - 3) << '.'
1327                                           << par->getCounter(i - 2) << '.'
1328                                           << par->getCounter(i - 1) << '.'
1329                                           << par->getCounter(i);
1330                                         break;
1331                                 case LABEL_COUNTER_SUBPARAGRAPH:
1332                                         s << par->getCounter(i - 5) << '.'
1333                                           << par->getCounter(i - 4) << '.'
1334                                           << par->getCounter(i - 3) << '.'
1335                                           << par->getCounter(i - 2) << '.'
1336                                           << par->getCounter(i - 1) << '.'
1337                                           << par->getCounter(i);
1338
1339                                         break;
1340                                 default:
1341                                         // Can this ever be reached? And in the
1342                                         // case it is, how can this be correct?
1343                                         // (Lgb)
1344                                         s << par->getCounter(i) << '.';
1345                                         break;
1346                                 }
1347                         } else { // appendix
1348                                 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1349                                 case LABEL_COUNTER_CHAPTER:
1350                                         if (par->isRightToLeftPar(buf->params))
1351                                                 s << hebrewCounter(par->getCounter(i));
1352                                         else
1353                                                 s << alphaCounter(par->getCounter(i));
1354                                         break;
1355                                 case LABEL_COUNTER_SECTION:
1356                                         if (par->isRightToLeftPar(buf->params))
1357                                                 s << hebrewCounter(par->getCounter(i - 1));
1358                                         else
1359                                                 s << alphaCounter(par->getCounter(i - 1));
1360
1361                                         s << '.'
1362                                           << par->getCounter(i);
1363
1364                                         break;
1365                                 case LABEL_COUNTER_SUBSECTION:
1366                                         if (par->isRightToLeftPar(buf->params))
1367                                                 s << hebrewCounter(par->getCounter(i - 2));
1368                                         else
1369                                                 s << alphaCounter(par->getCounter(i - 2));
1370
1371                                         s << '.'
1372                                           << par->getCounter(i-1) << '.'
1373                                           << par->getCounter(i);
1374
1375                                         break;
1376                                 case LABEL_COUNTER_SUBSUBSECTION:
1377                                         if (par->isRightToLeftPar(buf->params))
1378                                                 s << hebrewCounter(par->getCounter(i-3));
1379                                         else
1380                                                 s << alphaCounter(par->getCounter(i-3));
1381
1382                                         s << '.'
1383                                           << par->getCounter(i-2) << '.'
1384                                           << par->getCounter(i-1) << '.'
1385                                           << par->getCounter(i);
1386
1387                                         break;
1388                                 case LABEL_COUNTER_PARAGRAPH:
1389                                         if (par->isRightToLeftPar(buf->params))
1390                                                 s << hebrewCounter(par->getCounter(i-4));
1391                                         else
1392                                                 s << alphaCounter(par->getCounter(i-4));
1393
1394                                         s << '.'
1395                                           << par->getCounter(i-3) << '.'
1396                                           << par->getCounter(i-2) << '.'
1397                                           << par->getCounter(i-1) << '.'
1398                                           << par->getCounter(i);
1399
1400                                         break;
1401                                 case LABEL_COUNTER_SUBPARAGRAPH:
1402                                         if (par->isRightToLeftPar(buf->params))
1403                                                 s << hebrewCounter(par->getCounter(i-5));
1404                                         else
1405                                                 s << alphaCounter(par->getCounter(i-5));
1406
1407                                         s << '.'
1408                                           << par->getCounter(i-4) << '.'
1409                                           << par->getCounter(i-3) << '.'
1410                                           << par->getCounter(i-2) << '.'
1411                                           << par->getCounter(i-1) << '.'
1412                                           << par->getCounter(i);
1413
1414                                         break;
1415                                 default:
1416                                         // Can this ever be reached? And in the
1417                                         // case it is, how can this be correct?
1418                                         // (Lgb)
1419                                         s << par->getCounter(i) << '.';
1420                                         
1421                                         break;
1422                                 }
1423                         }
1424
1425                         par->params.labelString(par->params.labelString() +s.str().c_str());
1426                         // We really want to remove the c_str as soon as
1427                         // possible...
1428                         
1429                         for (i++; i < 10; ++i) {
1430                                 // reset the following counters
1431                                 par->setCounter(i, 0);
1432                         }
1433                 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1434                         for (i++; i < 10; ++i) {
1435                                 // reset the following counters
1436                                 par->setCounter(i, 0);
1437                         }
1438                 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1439                         par->incCounter(i + par->enumdepth);
1440                         int number = par->getCounter(i + par->enumdepth);
1441
1442                         std::ostringstream s;
1443
1444                         switch (par->enumdepth) {
1445                         case 1:
1446                                 if (par->isRightToLeftPar(buf->params))
1447                                         s << '('
1448                                           << hebrewCounter(number)
1449                                           << ')';
1450                                 else
1451                                         s << '('
1452                                           << loweralphaCounter(number)
1453                                           << ')';
1454                                 break;
1455                         case 2:
1456                                 if (par->isRightToLeftPar(buf->params))
1457                                         s << '.' << romanCounter(number);
1458                                 else
1459                                         s << romanCounter(number) << '.';
1460                                 break;
1461                         case 3:
1462                                 if (par->isRightToLeftPar(buf->params))
1463                                         s << '.'
1464                                           << alphaCounter(number);
1465                                 else
1466                                         s << alphaCounter(number)
1467                                           << '.';
1468                                 break;
1469                         default:
1470                                 if (par->isRightToLeftPar(buf->params))
1471                                         s << '.' << number;
1472                                 else
1473                                         s << number << '.';
1474                                 break;
1475                         }
1476
1477                         par->params.labelString(s.str().c_str());
1478                         // we really want to get rid of that c_str()
1479
1480                         for (i += par->enumdepth + 1; i < 10; ++i)
1481                                 par->setCounter(i, 0);  /* reset the following counters  */
1482          
1483                 } 
1484         } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1485                 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1486                 par->incCounter(i);
1487                 int number = par->getCounter(i);
1488                 if (!par->bibkey) {
1489                         InsetCommandParams p( "bibitem" );
1490                         par->bibkey = new InsetBibKey(p);
1491                 }
1492                 par->bibkey->setCounter(number);
1493                 par->params.labelString(layout.labelstring());
1494                 
1495                 // In biblio should't be following counters but...
1496         } else {
1497                 string s = layout.labelstring();
1498                 
1499                 // the caption hack:
1500                 if (layout.labeltype == LABEL_SENSITIVE) {
1501                         bool isOK (par->InInset() && par->InInset()->owner() &&
1502                                    (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
1503                         if (isOK) {
1504                                 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
1505                                 Floating const & fl
1506                                         = floatList.getType(tmp->type());
1507                                 // We should get the correct number here too.
1508                                 s = fl.name() + " #:";
1509                         } else {
1510                                 /* par->SetLayout(0); 
1511                                    s = layout->labelstring;  */
1512                                 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1513                                         ? " :úåòîùî Ã¸Ã±Ã§" : "Senseless: ";
1514                         }
1515                 }
1516                 par->params.labelString(s);
1517                 
1518                 /* reset the enumeration counter. They are always resetted
1519                  * when there is any other layout between */ 
1520                 for (int i = 6 + par->enumdepth; i < 10; ++i)
1521                         par->setCounter(i, 0);
1522         }
1523 }
1524
1525
1526 /* Updates all counters BEHIND the row. Changed paragraphs
1527 * with a dynamic left margin will be rebroken. */ 
1528 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1529 {
1530         LyXParagraph * par;
1531
1532         if (!row) {
1533                 row = firstrow;
1534                 par = row->par();
1535         } else {
1536                 par = row->par()->next();
1537         }
1538
1539         while (par) {
1540                 while (row->par() != par)
1541                         row = row->next();
1542                 
1543                 SetCounter(bview->buffer(), par);
1544                 
1545                 /* now  check for the headline layouts. remember that they
1546                  * have a dynamic left margin */ 
1547                 if ((textclasslist.Style(bview->buffer()->params.textclass,
1548                                          par->layout).margintype == MARGIN_DYNAMIC
1549                      || textclasslist.Style(bview->buffer()->params.textclass,
1550                                             par->layout).labeltype == LABEL_SENSITIVE)) {
1551                         
1552                         /* Rebreak the paragraph */ 
1553                         RemoveParagraph(row);
1554                         AppendParagraph(bview, row);
1555                 }
1556                 par = par->next();
1557         }
1558 }
1559
1560
1561 /* insets an inset. */ 
1562 void LyXText::InsertInset(BufferView * bview, Inset * inset)
1563 {
1564         if (!cursor.par()->InsertInsetAllowed(inset))
1565                 return;
1566         SetUndo(bview->buffer(), Undo::INSERT,
1567                 cursor.par()->previous(),
1568                 cursor.par()->next());
1569         cursor.par()->InsertInset(cursor.pos(), inset);
1570         InsertChar(bview, LyXParagraph::META_INSET);  /* just to rebreak and refresh correctly.
1571                                       * The character will not be inserted a
1572                                       * second time */
1573 #if 1
1574         // If we enter a highly editable inset the cursor should be to before
1575         // the inset. This couldn't happen before as Undo was not handled inside
1576         // inset now after the Undo LyX tries to call inset->Edit(...) again
1577         // and cannot do this as the cursor is behind the inset and GetInset
1578         // does not return the inset!
1579         if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
1580                 CursorLeft(bview, true);
1581         }
1582 #endif
1583 }
1584
1585
1586 void LyXText::copyEnvironmentType()
1587 {
1588         copylayouttype = cursor.par()->GetLayout();
1589 }
1590
1591
1592 void LyXText::pasteEnvironmentType(BufferView * bview)
1593 {
1594         SetLayout(bview, copylayouttype);
1595 }
1596
1597
1598 void LyXText::CutSelection(BufferView * bview, bool doclear)
1599 {
1600         // Stuff what we got on the clipboard. Even if there is no selection.
1601
1602         // There is a problem with having the stuffing here in that the
1603         // larger the selection the slower LyX will get. This can be
1604         // solved by running the line below only when the selection has
1605         // finished. The solution used currently just works, to make it
1606         // faster we need to be more clever and probably also have more
1607         // calls to stuffClipboard. (Lgb)
1608         bview->stuffClipboard(selectionAsString(bview->buffer()));
1609
1610         // This doesn't make sense, if there is no selection
1611         if (!selection)
1612                 return;
1613    
1614         // OK, we have a selection. This is always between sel_start_cursor
1615         // and sel_end_cursor
1616
1617         // make sure that the depth behind the selection are restored, too
1618         LyXParagraph * endpar = sel_end_cursor.par()->next();
1619         LyXParagraph * undoendpar = endpar;
1620     
1621         if (endpar && endpar->GetDepth()) {
1622                 while (endpar && endpar->GetDepth()) {
1623                         endpar = endpar->next();
1624                         undoendpar = endpar;
1625                 }
1626         } else if (endpar) {
1627                 endpar = endpar->next(); // because of parindents etc.
1628         }
1629     
1630         SetUndo(bview->buffer(), Undo::DELETE,
1631                 sel_start_cursor.par()->previous(),
1632                 undoendpar);
1633     
1634         CutAndPaste cap;
1635
1636         // there are two cases: cut only within one paragraph or
1637         // more than one paragraph
1638         if (sel_start_cursor.par() == sel_end_cursor.par()) {
1639                 // only within one paragraph
1640                 endpar = sel_start_cursor.par();
1641                 int pos = sel_end_cursor.pos();
1642                 cap.cutSelection(sel_start_cursor.par(), &endpar,
1643                                  sel_start_cursor.pos(), pos,
1644                                  bview->buffer()->params.textclass, doclear);
1645                 sel_end_cursor.pos(pos);
1646         } else {
1647                 endpar = sel_end_cursor.par();
1648
1649                 int pos = sel_end_cursor.pos();
1650                 cap.cutSelection(sel_start_cursor.par(), &endpar,
1651                                  sel_start_cursor.pos(), pos,
1652                                  bview->buffer()->params.textclass, doclear);
1653                 cursor.par(endpar);
1654                 sel_end_cursor.par(endpar);
1655                 sel_end_cursor.pos(pos);
1656                 cursor.pos(sel_end_cursor.pos());
1657         }
1658         endpar = endpar->next();
1659
1660         // sometimes necessary
1661         if (doclear)
1662                 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
1663
1664         RedoParagraphs(bview, sel_start_cursor, endpar);
1665    
1666         ClearSelection(bview);
1667         cursor = sel_start_cursor;
1668         SetCursor(bview, cursor.par(), cursor.pos());
1669         sel_cursor = cursor;
1670         UpdateCounters(bview, cursor.row());
1671 }
1672
1673
1674 void LyXText::CopySelection(BufferView * bview)
1675 {
1676         // Stuff what we got on the clipboard. Even if there is no selection.
1677
1678         // There is a problem with having the stuffing here in that the
1679         // larger the selection the slower LyX will get. This can be
1680         // solved by running the line below only when the selection has
1681         // finished. The solution used currently just works, to make it
1682         // faster we need to be more clever and probably also have more
1683         // calls to stuffClipboard. (Lgb)
1684         bview->stuffClipboard(selectionAsString(bview->buffer()));
1685
1686         // this doesnt make sense, if there is no selection
1687         if (!selection)
1688                 return;
1689
1690         // ok we have a selection. This is always between sel_start_cursor
1691         // and sel_end cursor
1692
1693         // copy behind a space if there is one
1694         while (sel_start_cursor.par()->size() > sel_start_cursor.pos()
1695                && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
1696                && (sel_start_cursor.par() != sel_end_cursor.par()
1697                    || sel_start_cursor.pos() < sel_end_cursor.pos()))
1698                 sel_start_cursor.pos(sel_start_cursor.pos() + 1); 
1699
1700         CutAndPaste cap;
1701
1702         cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
1703                           sel_start_cursor.pos(), sel_end_cursor.pos(),
1704                           bview->buffer()->params.textclass);
1705 }
1706
1707
1708 void LyXText::PasteSelection(BufferView * bview)
1709 {
1710         CutAndPaste cap;
1711
1712         // this does not make sense, if there is nothing to paste
1713         if (!cap.checkPastePossible(cursor.par()))
1714                 return;
1715
1716         SetUndo(bview->buffer(), Undo::INSERT,
1717                 cursor.par()->previous(),
1718                 cursor.par()->next()); 
1719
1720         LyXParagraph * endpar;
1721         LyXParagraph * actpar = cursor.par();
1722
1723         int pos = cursor.pos();
1724         cap.pasteSelection(&actpar, &endpar, pos,
1725                            bview->buffer()->params.textclass);
1726     
1727         RedoParagraphs(bview, cursor, endpar);
1728         
1729         SetCursor(bview, cursor.par(), cursor.pos());
1730         ClearSelection(bview);
1731    
1732         sel_cursor = cursor;
1733         SetCursor(bview, actpar, pos);
1734         SetSelection(bview);
1735         UpdateCounters(bview, cursor.row());
1736 }
1737
1738
1739 // returns a pointer to the very first LyXParagraph
1740 LyXParagraph * LyXText::FirstParagraph() const
1741 {
1742         return OwnerParagraph();
1743 }
1744
1745
1746 // sets the selection over the number of characters of string, no check!!
1747 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
1748 {
1749         sel_cursor = cursor;
1750         for (int i = 0; str[i]; ++i)
1751                 CursorRight(bview);
1752         SetSelection(bview);
1753 }
1754
1755
1756 // simple replacing. The font of the first selected character is used
1757 void LyXText::ReplaceSelectionWithString(BufferView * bview,
1758                                          string const & str)
1759 {
1760         SetCursorParUndo(bview->buffer());
1761         FreezeUndo();
1762
1763         if (!selection) { // create a dummy selection
1764                 sel_end_cursor = cursor;
1765                 sel_start_cursor = cursor;
1766         }
1767
1768         // Get font setting before we cut
1769         LyXParagraph::size_type pos = sel_end_cursor.pos();
1770         LyXFont const font = sel_start_cursor.par()
1771                 ->GetFontSettings(bview->buffer()->params,
1772                                   sel_start_cursor.pos());
1773
1774         // Insert the new string
1775         for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
1776                 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
1777                 ++pos;
1778         }
1779         
1780         // Cut the selection
1781         CutSelection(bview);
1782
1783         UnFreezeUndo();
1784 }
1785
1786
1787 // needed to insert the selection
1788 void LyXText::InsertStringA(BufferView * bview, string const & str)
1789 {
1790         LyXParagraph * par = cursor.par();
1791         LyXParagraph::size_type pos = cursor.pos();
1792         LyXParagraph::size_type a = 0;
1793         LyXParagraph * endpar = cursor.par()->next();
1794         
1795         SetCursorParUndo(bview->buffer());
1796         
1797         bool flag =
1798                 textclasslist.Style(bview->buffer()->params.textclass, 
1799                                     cursor.par()->GetLayout()).isEnvironment();
1800         // only to be sure, should not be neccessary
1801         ClearSelection(bview);
1802         
1803         // insert the string, don't insert doublespace
1804         string::size_type i = 0;
1805         while (i < str.length()) {
1806                 if (str[i] != '\n') {
1807                         if (str[i] == ' ' 
1808                             && i + 1 < str.length() && str[i + 1] != ' '
1809                             && pos && par->GetChar(pos - 1)!= ' ') {
1810                                 par->InsertChar(pos, ' ', current_font);
1811                                 ++pos;
1812                         } else if (str[i] == ' ') {
1813                                 InsetSpecialChar * new_inset =
1814                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1815                                 if (par->InsertInsetAllowed(new_inset)) {
1816                                         par->InsertInset(pos, new_inset,
1817                                                          current_font);
1818                                 } else {
1819                                         delete new_inset;
1820                                 }
1821                                 ++pos;
1822                         } else if (str[i] == '\t') {
1823                                 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
1824                                 InsetSpecialChar * new_inset =
1825                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1826                                 if (par->InsertInsetAllowed(new_inset)) {
1827                                         par->InsertInset(pos, new_inset,
1828                                                          current_font);
1829                                 } else {
1830                                         delete new_inset;
1831                                 }
1832                                 }
1833                                 pos = a;
1834                         } else if (str[i] != 13 && 
1835                                    // Ignore unprintables
1836                                    (str[i] & 127) >= ' ') {
1837                                 par->InsertChar(pos, str[i], current_font);
1838                                 ++pos;
1839                         }
1840                 } else {
1841                         if (!par->size()) { // par is empty
1842                                 InsetSpecialChar * new_inset =
1843                                         new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1844                                 if (par->InsertInsetAllowed(new_inset)) {
1845                                         par->InsertInset(pos,
1846                                                          new_inset,
1847                                                          current_font);
1848                                 } else {
1849                                         delete new_inset;
1850                                 }
1851                                 ++pos;
1852                         }
1853                         par->BreakParagraph(bview->buffer()->params, pos, flag);
1854                         par = par->next();
1855                         pos = 0;
1856                 }
1857                 ++i;
1858         }
1859         
1860         RedoParagraphs(bview, cursor, endpar);
1861         SetCursor(bview, cursor.par(), cursor.pos());
1862         sel_cursor = cursor;
1863         SetCursor(bview, par, pos);
1864         SetSelection(bview);
1865 }
1866
1867
1868 /* turns double-CR to single CR, others where converted into one blank and 13s 
1869  * that are ignored .Double spaces are also converted into one. Spaces at
1870  * the beginning of a paragraph are forbidden. tabs are converted into one
1871  * space. then InsertStringA is called */ 
1872 void LyXText::InsertStringB(BufferView * bview, string const & s)
1873 {
1874         string str(s);
1875         string::size_type i = 1;
1876         while (i < str.length()) {
1877                 if (str[i] == '\t')
1878                         str[i] = ' ';
1879                 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
1880                         str[i] = 13;
1881                 if (str[i] == '\n' && i + 1 < str.length()) {
1882                         if (str[i + 1] != '\n') {
1883                                 if (str[i - 1] != ' ')
1884                                         str[i] = ' ';
1885                                 else
1886                                         str[i] = 13;
1887                         }
1888                         while (i + 1 < str.length() 
1889                                && (str[i + 1] == ' ' 
1890                                    || str[i + 1] == '\t'
1891                                    || str[i + 1] == '\n' 
1892                                    || str[i + 1] == 13)) {
1893                                 str[i + 1] = 13;
1894                                 ++i;
1895                         }
1896                 }
1897                 ++i;
1898         }
1899         InsertStringA(bview, str);
1900 }
1901
1902
1903 bool LyXText::GotoNextInset(BufferView * bview,
1904                             std::vector<Inset::Code> const & codes,
1905                             string const & contents) const
1906 {
1907         LyXCursor res = cursor;
1908         Inset * inset;
1909         do {
1910                 if (res.pos() < res.par()->size() - 1) {
1911                         res.pos(res.pos() + 1);
1912                 } else  {
1913                         res.par(res.par()->next());
1914                         res.pos(0);
1915                 }
1916       
1917         } while (res.par() && 
1918                  !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
1919                    && (inset = res.par()->GetInset(res.pos())) != 0
1920                    && find(codes.begin(), codes.end(), inset->LyxCode())
1921                       != codes.end()
1922                    && (contents.empty() ||
1923                        static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
1924                        == contents)));
1925
1926         if (res.par()) {
1927                 SetCursor(bview, res.par(), res.pos());
1928                 return true;
1929         }
1930         return false;
1931 }
1932
1933
1934 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
1935                              LyXParagraph::size_type pos)
1936 {
1937         LyXCursor tmpcursor;                    
1938
1939         int y = 0;
1940         LyXParagraph::size_type z;
1941         Row * row = GetRow(par, pos, y);
1942         
1943         // is there a break one row above
1944         if (row->previous() && row->previous()->par() == row->par()) {
1945                 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
1946                 if (z >= row->pos()) {
1947                         // set the dimensions of the row above
1948                         y -= row->previous()->height();
1949                         refresh_y = y;
1950                         refresh_row = row->previous();
1951                         status = LyXText::NEED_MORE_REFRESH;
1952                         
1953                         BreakAgain(bview, row->previous());
1954                         
1955                         // set the cursor again. Otherwise
1956                         // dangling pointers are possible
1957                         SetCursor(bview, cursor.par(), cursor.pos(),
1958                                   false, cursor.boundary());
1959                         sel_cursor = cursor;
1960                         return;
1961                 }
1962         }
1963
1964         int const tmpheight = row->height();
1965         LyXParagraph::size_type const tmplast = RowLast(row);
1966         refresh_y = y;
1967         refresh_row = row;
1968         
1969         BreakAgain(bview, row);
1970         if (row->height() == tmpheight && RowLast(row) == tmplast)
1971                 status = LyXText::NEED_VERY_LITTLE_REFRESH;
1972         else
1973                 status = LyXText::NEED_MORE_REFRESH; 
1974         
1975         // check the special right address boxes
1976         if (textclasslist.Style(bview->buffer()->params.textclass,
1977                                 par->GetLayout()).margintype
1978             == MARGIN_RIGHT_ADDRESS_BOX) {
1979                 tmpcursor.par(par);
1980                 tmpcursor.row(row);
1981                 tmpcursor.y(y);
1982                 tmpcursor.x(0);
1983                 tmpcursor.x_fix(0);
1984                 tmpcursor.pos(pos);
1985                 RedoDrawingOfParagraph(bview, tmpcursor); 
1986         }
1987
1988         // set the cursor again. Otherwise dangling pointers are possible
1989         // also set the selection
1990    
1991         if (selection) {
1992                 tmpcursor = cursor;
1993                 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
1994                                 false, sel_cursor.boundary());
1995                 sel_cursor = cursor; 
1996                 SetCursorIntern(bview, sel_start_cursor.par(),
1997                                 sel_start_cursor.pos(),
1998                                 false, sel_start_cursor.boundary());
1999                 sel_start_cursor = cursor; 
2000                 SetCursorIntern(bview, sel_end_cursor.par(),
2001                                 sel_end_cursor.pos(),
2002                                 false, sel_end_cursor.boundary());
2003                 sel_end_cursor = cursor; 
2004                 SetCursorIntern(bview, last_sel_cursor.par(),
2005                                 last_sel_cursor.pos(),
2006                                 false, last_sel_cursor.boundary());
2007                 last_sel_cursor = cursor; 
2008                 cursor = tmpcursor;
2009         }
2010         SetCursorIntern(bview, cursor.par(), cursor.pos(),
2011                         false, cursor.boundary());
2012 }
2013
2014
2015 // returns false if inset wasn't found
2016 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2017 {
2018         // first check the current paragraph
2019         int pos = cursor.par()->GetPositionOfInset(inset);
2020         if (pos != -1){
2021                 CheckParagraph(bview, cursor.par(), pos);
2022                 return true;
2023         }
2024   
2025         // check every paragraph
2026   
2027         LyXParagraph * par = FirstParagraph();
2028         do {
2029                         pos = par->GetPositionOfInset(inset);
2030                         if (pos != -1){
2031                                 CheckParagraph(bview, par, pos);
2032                                 return true;
2033                         }
2034                 par = par->next();
2035         } while (par);
2036   
2037         return false;
2038 }
2039
2040
2041 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2042                         LyXParagraph::size_type pos, 
2043                         bool setfont, bool boundary) const
2044 {
2045         LyXCursor old_cursor = cursor;
2046         SetCursorIntern(bview, par, pos, setfont, boundary);
2047         DeleteEmptyParagraphMechanism(bview, old_cursor);
2048 }
2049
2050
2051 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2052                         LyXParagraph::size_type pos, bool boundary) const
2053 {
2054         cur.par(par);
2055         cur.pos(pos);
2056         cur.boundary(boundary);
2057
2058         /* get the cursor y position in text  */
2059         int y = 0;
2060         Row * row = GetRow(par, pos, y);
2061         /* y is now the beginning of the cursor row */ 
2062         y += row->baseline();
2063         /* y is now the cursor baseline */ 
2064         cur.y(y);
2065    
2066         /* now get the cursors x position */
2067         float x;
2068         float fill_separator, fill_hfill, fill_label_hfill;
2069         PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2070                        fill_label_hfill);
2071         LyXParagraph::size_type cursor_vpos = 0;
2072         LyXParagraph::size_type last = RowLastPrintable(row);
2073
2074         if (pos > last + 1)   // This shouldn't happen.
2075                 pos = last + 1;
2076         else if (pos < row->pos())
2077                 pos = row->pos();
2078
2079         if (last < row->pos())
2080                 cursor_vpos = row->pos();
2081         else if (pos > last && !boundary)
2082                 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2083                         ? row->pos() : last + 1; 
2084         else if (pos > row->pos() &&
2085                  (pos > last || boundary))
2086                 /// Place cursor after char at (logical) position pos - 1
2087                 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2088                         ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2089         else
2090                 /// Place cursor before char at (logical) position pos
2091                 cursor_vpos = (bidi_level(pos) % 2 == 0)
2092                         ? log2vis(pos) : log2vis(pos) + 1;
2093         
2094         LyXParagraph::size_type main_body =
2095                 BeginningOfMainBody(bview->buffer(), row->par());
2096         if ((main_body > 0) &&
2097             ((main_body-1 > last) || 
2098              !row->par()->IsLineSeparator(main_body-1)))
2099                 main_body = 0;
2100         
2101         for (LyXParagraph::size_type vpos = row->pos();
2102              vpos < cursor_vpos; ++vpos) {
2103                 pos = vis2log(vpos);
2104                 if (main_body > 0 && pos == main_body - 1) {
2105                         x += fill_label_hfill +
2106                                 lyxfont::width(textclasslist.Style(
2107                                         bview->buffer()->params.textclass,
2108                                         row->par()->GetLayout())
2109                                                .labelsep,
2110                                                GetFont(bview->buffer(), row->par(), -2));
2111                         if (row->par()->IsLineSeparator(main_body-1))
2112                                 x -= SingleWidth(bview, row->par(),main_body-1);
2113                 }
2114                 if (HfillExpansion(bview->buffer(), row, pos)) {
2115                         x += SingleWidth(bview, row->par(), pos);
2116                         if (pos >= main_body)
2117                                 x += fill_hfill;
2118                         else 
2119                                 x += fill_label_hfill;
2120                 } else if (row->par()->IsSeparator(pos)) {
2121                         x += SingleWidth(bview, row->par(), pos);
2122                         if (pos >= main_body)
2123                                 x += fill_separator;
2124                 } else
2125                         x += SingleWidth(bview, row->par(), pos);
2126         }
2127         
2128         cur.x(int(x));
2129         cur.x_fix(cur.x());
2130         cur.row(row);
2131 }
2132
2133
2134 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2135                               LyXParagraph::size_type pos,
2136                               bool setfont, bool boundary) const
2137 {
2138         SetCursor(bview, cursor, par, pos, boundary);
2139         if (setfont)
2140                 SetCurrentFont(bview);
2141 }
2142
2143
2144 void LyXText::SetCurrentFont(BufferView * bview) const
2145 {
2146         LyXParagraph::size_type pos = cursor.pos();
2147         if (cursor.boundary() && pos > 0)
2148                 --pos;
2149
2150         if (pos > 0) {
2151                 if (pos == cursor.par()->size())
2152                         --pos;
2153                 else if (cursor.par()->IsSeparator(pos)) {
2154                         if (pos > cursor.row()->pos() &&
2155                             bidi_level(pos) % 2 == 
2156                             bidi_level(pos - 1) % 2)
2157                                 --pos;
2158                         else if (pos + 1 < cursor.par()->size())
2159                                 ++pos;
2160                 }
2161         }
2162
2163         current_font =
2164                 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2165         real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2166
2167         if (cursor.pos() == cursor.par()->size() &&
2168             IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2169             !cursor.boundary()) {
2170                 Language const * lang =
2171                         cursor.par()->getParLanguage(bview->buffer()->params);
2172                 current_font.setLanguage(lang);
2173                 current_font.setNumber(LyXFont::OFF);
2174                 real_current_font.setLanguage(lang);
2175                 real_current_font.setNumber(LyXFont::OFF);
2176         }
2177 }
2178
2179
2180 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2181 {
2182         LyXCursor old_cursor = cursor;
2183    
2184         /* get the row first */ 
2185    
2186         Row * row = GetRowNearY(y);
2187         cursor.par(row->par());
2188
2189         bool bound = false;
2190         int column = GetColumnNearX(bview, row, x, bound);
2191         cursor.pos(row->pos() + column);
2192         cursor.x(x);
2193         cursor.y(y + row->baseline());
2194         cursor.row(row);
2195         cursor.boundary(bound);
2196         SetCurrentFont(bview);
2197         DeleteEmptyParagraphMechanism(bview, old_cursor);
2198 }
2199
2200
2201 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2202                                        int x, int y) const
2203 {
2204         /* get the row first */ 
2205    
2206         Row * row = GetRowNearY(y);
2207         bool bound = false;
2208         int column = GetColumnNearX(bview, row, x, bound);
2209    
2210         cur.par(row->par());
2211         cur.pos(row->pos() + column);
2212         cur.x(x);
2213         cur.y(y + row->baseline());
2214         cur.row(row);
2215         cur.boundary(bound);
2216 }
2217
2218
2219 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2220 {
2221         if (cursor.pos() > 0) {
2222                 bool boundary = cursor.boundary();
2223                 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2224                 if (!internal && !boundary &&
2225                     IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2226                         SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2227         } else if (cursor.par()->previous()) { // steps into the above paragraph.
2228                 LyXParagraph * par = cursor.par()->previous();
2229                 SetCursor(bview, par, par->size());
2230         }
2231 }
2232
2233
2234 void LyXText::CursorRight(BufferView * bview, bool internal) const
2235 {
2236         if (!internal && cursor.boundary() &&
2237             !cursor.par()->IsNewline(cursor.pos()))
2238                 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2239         else if (cursor.pos() < cursor.par()->size()) {
2240                 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2241                 if (!internal &&
2242                     IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2243                         SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2244         } else if (cursor.par()->next())
2245                 SetCursor(bview, cursor.par()->next(), 0);
2246 }
2247
2248
2249 void LyXText::CursorUp(BufferView * bview) const
2250 {
2251         SetCursorFromCoordinates(bview, cursor.x_fix(), 
2252                                  cursor.y() - cursor.row()->baseline() - 1);
2253 }
2254
2255
2256 void LyXText::CursorDown(BufferView * bview) const
2257 {
2258         SetCursorFromCoordinates(bview, cursor.x_fix(), 
2259                                  cursor.y() - cursor.row()->baseline()
2260                                  + cursor.row()->height() + 1);
2261 }
2262
2263
2264 void LyXText::CursorUpParagraph(BufferView * bview) const
2265 {
2266         if (cursor.pos() > 0) {
2267                 SetCursor(bview, cursor.par(), 0);
2268         }
2269         else if (cursor.par()->previous()) {
2270                 SetCursor(bview, cursor.par()->previous(), 0);
2271         }
2272 }
2273
2274
2275 void LyXText::CursorDownParagraph(BufferView * bview) const
2276 {
2277         if (cursor.par()->next()) {
2278                 SetCursor(bview, cursor.par()->next(), 0);
2279         } else {
2280                 SetCursor(bview, cursor.par(), cursor.par()->size());
2281         }
2282 }
2283
2284
2285 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
2286                                             LyXCursor const & old_cursor) const
2287 {
2288         // Would be wrong to delete anything if we have a selection.
2289         if (selection) return;
2290
2291         // We allow all kinds of "mumbo-jumbo" when freespacing.
2292         if (textclasslist.Style(bview->buffer()->params.textclass,
2293                                 old_cursor.par()->GetLayout()).free_spacing)
2294                 return;
2295
2296         bool deleted = false;
2297         
2298         /* Ok I'll put some comments here about what is missing.
2299            I have fixed BackSpace (and thus Delete) to not delete
2300            double-spaces automagically. I have also changed Cut,
2301            Copy and Paste to hopefully do some sensible things.
2302            There are still some small problems that can lead to
2303            double spaces stored in the document file or space at
2304            the beginning of paragraphs. This happens if you have
2305            the cursor betwenn to spaces and then save. Or if you
2306            cut and paste and the selection have a space at the
2307            beginning and then save right after the paste. I am
2308            sure none of these are very hard to fix, but I will
2309            put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2310            that I can get some feedback. (Lgb)
2311         */
2312
2313         // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2314         // delete the LineSeparator.
2315         // MISSING
2316
2317         // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2318         // delete the LineSeparator.
2319         // MISSING
2320
2321         // If the pos around the old_cursor were spaces, delete one of them.
2322         if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) { 
2323                 // Only if the cursor has really moved
2324                 
2325                 if (old_cursor.pos() > 0
2326                     && old_cursor.pos() < old_cursor.par()->size()
2327                     && old_cursor.par()->IsLineSeparator(old_cursor.pos())
2328                     && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
2329                         old_cursor.par()->Erase(old_cursor.pos() - 1);
2330                         RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
2331                         // correct cursor
2332                         if (old_cursor.par() == cursor.par() &&
2333                             cursor.pos() > old_cursor.pos()) {
2334                                 SetCursorIntern(bview, cursor.par(),
2335                                                 cursor.pos() - 1);
2336                         } else
2337                                 SetCursorIntern(bview, cursor.par(),
2338                                                 cursor.pos());
2339                         return;
2340                 }
2341         }
2342
2343         // Do not delete empty paragraphs with keepempty set.
2344         if ((textclasslist.Style(bview->buffer()->params.textclass,
2345                                  old_cursor.par()->GetLayout())).keepempty)
2346                 return;
2347
2348         LyXCursor tmpcursor;
2349
2350         if (old_cursor.par() != cursor.par()) {
2351                 if ((old_cursor.par()->size() == 0
2352                       || (old_cursor.par()->size() == 1
2353                           && old_cursor.par()->IsLineSeparator(0)))) {
2354                         // ok, we will delete anything
2355                         
2356                         // make sure that you do not delete any environments
2357                                 status = LyXText::NEED_MORE_REFRESH;
2358                                 deleted = true;
2359                                 
2360                                 if (old_cursor.row()->previous()) {
2361                                         refresh_row = old_cursor.row()->previous();
2362                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2363                                         tmpcursor = cursor;
2364                                         cursor = old_cursor; // that undo can restore the right cursor position
2365                                         LyXParagraph * endpar = old_cursor.par()->next();
2366                                         if (endpar && endpar->GetDepth()) {
2367                                                 while (endpar && endpar->GetDepth()) {
2368                                                         endpar = endpar->next();
2369                                                 }
2370                                         }
2371                                         SetUndo(bview->buffer(), Undo::DELETE,
2372                                                 old_cursor.par()->previous(),
2373                                                 endpar);
2374                                         cursor = tmpcursor;
2375
2376                                         // delete old row
2377                                         RemoveRow(old_cursor.row());
2378                                         if (OwnerParagraph() == old_cursor.par()) {
2379                                                 OwnerParagraph(OwnerParagraph()->next());
2380                                         }
2381                                         // delete old par
2382                                         delete old_cursor.par();
2383                                         
2384                                         /* Breakagain the next par. Needed
2385                                          * because of the parindent that
2386                                          * can occur or dissappear. The
2387                                          * next row can change its height,
2388                                          * if there is another layout before */
2389                                         if (refresh_row->next()) {
2390                                                 BreakAgain(bview, refresh_row->next());
2391                                                 UpdateCounters(bview, refresh_row);
2392                                         }
2393                                         SetHeightOfRow(bview, refresh_row);
2394                                 } else {
2395                                         refresh_row = old_cursor.row()->next();
2396                                         refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2397                                         
2398                                         tmpcursor = cursor;
2399                                         cursor = old_cursor; // that undo can restore the right cursor position
2400                                         LyXParagraph * endpar = old_cursor.par()->next();
2401                                         if (endpar && endpar->GetDepth()) {
2402                                                 while (endpar && endpar->GetDepth()) {
2403                                                         endpar = endpar->next();
2404                                                 }
2405                                         }
2406                                         SetUndo(bview->buffer(), Undo::DELETE,
2407                                                 old_cursor.par()->previous(),
2408                                                 endpar);
2409                                         cursor = tmpcursor;
2410
2411                                         // delete old row
2412                                         RemoveRow(old_cursor.row());
2413                                         // delete old par
2414                                         if (OwnerParagraph() == old_cursor.par()) {
2415                                                 OwnerParagraph(OwnerParagraph()->next());
2416                                         }
2417
2418                                         delete old_cursor.par();
2419                                         
2420                                         /* Breakagain the next par. Needed
2421                                            because of the parindent that can
2422                                            occur or dissappear.
2423                                            The next row can change its height,
2424                                            if there is another layout before
2425                                         */ 
2426                                         if (refresh_row) {
2427                                                 BreakAgain(bview, refresh_row);
2428                                                 UpdateCounters(bview, refresh_row->previous());
2429                                         }
2430                                 }
2431                                 
2432                                 // correct cursor y
2433
2434                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
2435
2436                                 if (sel_cursor.par()  == old_cursor.par()
2437                                     && sel_cursor.pos() == sel_cursor.pos()) {
2438                                         // correct selection
2439                                         sel_cursor = cursor;
2440                                 }
2441                 }
2442                 if (!deleted) {
2443                         if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
2444                                 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
2445                                 // correct cursor y
2446                                 SetCursorIntern(bview, cursor.par(), cursor.pos());
2447                                 sel_cursor = cursor;
2448                         }
2449                 }
2450         }
2451 }
2452
2453
2454 LyXParagraph * LyXText::GetParFromID(int id)
2455 {
2456         LyXParagraph * result = FirstParagraph();
2457         while (result && result->id() != id)
2458                 result = result->next();
2459         return result;
2460 }
2461
2462
2463 // undo functions
2464 bool LyXText::TextUndo(BufferView * bview)
2465 {
2466         if (inset_owner)
2467                 return false;
2468         // returns false if no undo possible
2469         Undo * undo = bview->buffer()->undostack.pop();
2470         if (undo) {
2471                 FinishUndo();
2472                 if (!undo_frozen)
2473                         bview->buffer()->redostack
2474                                 .push(CreateUndo(bview->buffer(), undo->kind, 
2475                                                  GetParFromID(undo->number_of_before_par),
2476                                                  GetParFromID(undo->number_of_behind_par)));
2477         }
2478         return TextHandleUndo(bview, undo);
2479 }
2480
2481
2482 bool LyXText::TextRedo(BufferView * bview)
2483 {
2484         if (inset_owner)
2485                 return false;
2486         // returns false if no redo possible
2487         Undo * undo = bview->buffer()->redostack.pop();
2488         if (undo) {
2489                 FinishUndo();
2490                 if (!undo_frozen)
2491                         bview->buffer()->undostack
2492                                 .push(CreateUndo(bview->buffer(), undo->kind, 
2493                                                  GetParFromID(undo->number_of_before_par),
2494                                                  GetParFromID(undo->number_of_behind_par)));
2495         }
2496         return TextHandleUndo(bview, undo);
2497 }
2498
2499
2500 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
2501 {
2502         if (inset_owner)
2503                 return false;
2504         // returns false if no undo possible
2505         bool result = false;
2506         if (undo) {
2507                 LyXParagraph * before =
2508                         GetParFromID(undo->number_of_before_par); 
2509                 LyXParagraph * behind =
2510                         GetParFromID(undo->number_of_behind_par); 
2511                 LyXParagraph * tmppar;
2512                 LyXParagraph * tmppar2;
2513                 LyXParagraph * endpar;
2514                 LyXParagraph * tmppar5;
2515     
2516                 // if there's no before take the beginning
2517                 // of the document for redoing
2518                 if (!before)
2519                         SetCursorIntern(bview, FirstParagraph(), 0);
2520
2521                 // replace the paragraphs with the undo informations
2522
2523                 LyXParagraph * tmppar3 = undo->par;
2524                 undo->par = 0; // otherwise the undo destructor would delete the paragraph
2525                 LyXParagraph * tmppar4 = tmppar3;
2526
2527                 if (tmppar4) {
2528                         while (tmppar4->next())
2529                                 tmppar4 = tmppar4->next();
2530                 } // get last undo par
2531     
2532                 // now remove the old text if there is any
2533                 if (before != behind || (!behind && !before)) {
2534                         if (before)
2535                                 tmppar5 = before->next();
2536                         else
2537                                 tmppar5 = OwnerParagraph();
2538                         tmppar2 = tmppar3;
2539                         while (tmppar5 && tmppar5 != behind) {
2540                                 tmppar = tmppar5;
2541                                 tmppar5 = tmppar5->next();
2542                                 // a memory optimization for edit: Only layout information
2543                                 // is stored in the undo. So restore the text informations.
2544                                 if (undo->kind == Undo::EDIT) {
2545                                         tmppar2->setContentsFromPar(tmppar);
2546                                         tmppar->clearContents();
2547                                         tmppar2 = tmppar2->next();
2548                                 }
2549                         }
2550                 }
2551     
2552                 // put the new stuff in the list if there is one
2553                 if (tmppar3){
2554                         if (before)
2555                                 before->next(tmppar3);
2556                         else
2557                                 OwnerParagraph(tmppar3);
2558                         tmppar3->previous(before);
2559                 } else {
2560                         if (!before)
2561                                 OwnerParagraph(behind);
2562                 }
2563                 if (tmppar4) {
2564                         tmppar4->next(behind);
2565                         if (behind)
2566                                 behind->previous(tmppar4);
2567                 }
2568     
2569     
2570                 // Set the cursor for redoing
2571                 if (before) {
2572                         SetCursorIntern(bview, before, 0);
2573                 }
2574
2575                 // calculate the endpar for redoing the paragraphs.
2576                 if (behind) {
2577                                 endpar = behind->next();
2578                 } else
2579                         endpar = behind;
2580     
2581                 tmppar = GetParFromID(undo->number_of_cursor_par);
2582                 RedoParagraphs(bview, cursor, endpar); 
2583                 if (tmppar){
2584                         SetCursorIntern(bview, tmppar, undo->cursor_pos);
2585                         UpdateCounters(bview, cursor.row());
2586                 }
2587                 result = true;
2588                 delete undo;
2589         }
2590         FinishUndo();
2591         return result;
2592 }
2593
2594
2595 void LyXText::FinishUndo()
2596 {
2597         if (inset_owner)
2598                 return;
2599         // makes sure the next operation will be stored
2600         undo_finished = true;
2601 }
2602
2603
2604 void LyXText::FreezeUndo()
2605 {
2606         if (inset_owner)
2607                 return;
2608         // this is dangerous and for internal use only
2609         undo_frozen = true;
2610 }
2611
2612
2613 void LyXText::UnFreezeUndo()
2614 {
2615         if (inset_owner)
2616                 return;
2617         // this is dangerous and for internal use only
2618         undo_frozen = false;
2619 }
2620
2621
2622 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
2623                       LyXParagraph const * before,
2624                       LyXParagraph const * behind) const
2625 {
2626         if (inset_owner)
2627                 return;
2628         if (!undo_frozen)
2629                 buf->undostack.push(CreateUndo(buf, kind, before, behind));
2630         buf->redostack.clear();
2631 }
2632
2633
2634 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
2635                       LyXParagraph const * before, LyXParagraph const * behind)
2636 {
2637         if (inset_owner)
2638                 return;
2639         buf->redostack.push(CreateUndo(buf, kind, before, behind));
2640 }
2641
2642
2643 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
2644                            LyXParagraph const * before,
2645                            LyXParagraph const * behind) const
2646 {
2647         if (inset_owner)
2648                 return 0;
2649
2650         int before_number = -1;
2651         int behind_number = -1;
2652         if (before)
2653                 before_number = before->id();
2654         if (behind)
2655                 behind_number = behind->id();
2656         // Undo::EDIT  and Undo::FINISH are
2657         // always finished. (no overlapping there)
2658         // overlapping only with insert and delete inside one paragraph: 
2659         // Nobody wants all removed  character
2660         // appear one by one when undoing. 
2661         // EDIT is special since only layout information, not the
2662         // contents of a paragaph are stored.
2663         if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
2664                 // check wether storing is needed
2665                 if (!buf->undostack.empty() && 
2666                     buf->undostack.top()->kind == kind &&
2667                     buf->undostack.top()->number_of_before_par ==  before_number &&
2668                     buf->undostack.top()->number_of_behind_par ==  behind_number ){
2669                         // no undo needed
2670                         return 0;
2671                 }
2672         }
2673         // create a new Undo
2674         LyXParagraph * undopar;
2675
2676         LyXParagraph * start = 0;
2677         LyXParagraph * end = 0;
2678
2679         if (before)
2680                 start = const_cast<LyXParagraph*>(before->next());
2681         else
2682                 start = FirstParagraph();
2683         if (behind)
2684                 end = const_cast<LyXParagraph*>(behind->previous());
2685         else {
2686                 end = FirstParagraph();
2687                 while (end->next())
2688                         end = end->next();
2689         }
2690         if (start && end && (start != end->next()) &&
2691             ((before != behind) || (!before && !behind))) {
2692                 LyXParagraph * tmppar = start;
2693                 LyXParagraph * tmppar2 = new LyXParagraph(*tmppar);
2694                 tmppar2->id(tmppar->id());
2695
2696                 // a memory optimization: Just store the layout information
2697                 // when only edit
2698                 if (kind == Undo::EDIT){
2699                         //tmppar2->text.clear();
2700                         tmppar2->clearContents();
2701                 }
2702
2703                 undopar = tmppar2;
2704   
2705                 while (tmppar != end && tmppar->next()) {
2706                         tmppar = tmppar->next();
2707                         tmppar2->next(new LyXParagraph(*tmppar));
2708                         tmppar2->next()->id(tmppar->id());
2709                         // a memory optimization: Just store the layout
2710                         // information when only edit
2711                         if (kind == Undo::EDIT){
2712                                 //tmppar2->next->text.clear();
2713                                 tmppar2->clearContents();
2714                         }
2715                         tmppar2->next()->previous(tmppar2);
2716                         tmppar2 = tmppar2->next();
2717                 }
2718                 tmppar2->next(0);
2719         } else
2720                 undopar = 0; // nothing to replace (undo of delete maybe)
2721
2722         int cursor_par = cursor.par()->id();
2723         int cursor_pos =  cursor.pos();
2724         
2725         Undo * undo = new Undo(kind, 
2726                                before_number, behind_number,  
2727                                cursor_par, cursor_pos, 
2728                                undopar);
2729   
2730         undo_finished = false;
2731         return undo;
2732 }
2733
2734
2735 void LyXText::SetCursorParUndo(Buffer * buf)
2736 {
2737         if (inset_owner)
2738                 return;
2739         SetUndo(buf, Undo::FINISH,
2740                 cursor.par()->previous(),
2741                 cursor.par()->next()); 
2742 }
2743
2744
2745 void LyXText::toggleAppendix(BufferView * bview)
2746 {
2747         LyXParagraph * par = cursor.par();
2748         bool start = !par->params.startOfAppendix();
2749
2750         // ensure that we have only one start_of_appendix in this document
2751         LyXParagraph * tmp = FirstParagraph();
2752         for (; tmp; tmp = tmp->next())
2753                 tmp->params.startOfAppendix(false);
2754
2755         par->params.startOfAppendix(start);
2756
2757         // we can set the refreshing parameters now
2758         status = LyXText::NEED_MORE_REFRESH;
2759         refresh_y = 0;
2760         refresh_row = 0; // not needed for full update
2761         UpdateCounters(bview, 0);
2762         SetCursor(bview, cursor.par(), cursor.pos());
2763 }
2764
2765
2766 LyXParagraph * LyXText::OwnerParagraph() const
2767 {
2768         if (inset_owner)
2769                 return inset_owner->par;
2770
2771         return bv_owner->buffer()->paragraph;
2772 }
2773
2774
2775 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
2776 {
2777         if (inset_owner)
2778                 inset_owner->par = p;
2779         else
2780                 bv_owner->buffer()->paragraph = p;
2781         return 0;
2782 }