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