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