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