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