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