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