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