1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2000 The LyX Team.
9 * ====================================================== */
13 #include FORMS_H_LOCATION
17 #pragma implementation "lyxtext.h"
21 #include "lyxparagraph.h"
22 #include "insets/inseterror.h"
23 #include "insets/insetbib.h"
24 #include "insets/insetspecialchar.h"
25 #include "insets/insettext.h"
26 #include "insets/insetfloat.h"
29 #include "support/textutils.h"
31 #include "minibuffer.h"
33 #include "bufferparams.h"
34 #include "lyx_gui_misc.h"
37 #include "BufferView.h"
40 #include "CutAndPaste.h"
45 #include "FloatList.h"
52 LyXText::LyXText(BufferView * bv)
60 LyXText::LyXText(InsetText * inset)
77 status = LyXText::UNCHANGED;
78 // set cursor at the very top position
79 selection = true; /* these setting is necessary
80 because of the delete-empty-
81 paragraph mechanism in
84 LyXParagraph * par = OwnerParagraph();
85 current_font = GetFont(bv_owner->buffer(), par, 0);
87 InsertParagraph(bv_owner, par, lastrow);
90 SetCursor(bv_owner, firstrow->par(), 0);
92 current_font = LyXFont(LyXFont::ALL_SANE);
98 // no rebreak necessary
101 undo_finished = true;
104 // Default layouttype for copy environment type
108 // Dump all rowinformation:
109 Row * tmprow = firstrow;
110 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
112 lyxerr << tmprow->baseline() << '\t'
113 << tmprow->par << '\t'
114 << tmprow->pos() << '\t'
115 << tmprow->height << '\t'
116 << tmprow->ascent_of_text << '\t'
117 << tmprow->fill << '\n';
118 tmprow = tmprow->next();
125 void LyXText::init(BufferView * bview)
130 LyXParagraph * par = OwnerParagraph();
131 current_font = GetFont(bview->buffer(), par, 0);
133 InsertParagraph(bview, par, lastrow);
136 SetCursorIntern(bview, firstrow->par(), 0);
139 // Dump all rowinformation:
140 Row * tmprow = firstrow;
141 lyxerr << "Width = " << width << endl;
142 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
144 lyxerr << tmprow->baseline() << '\t'
145 << tmprow->par() << '\t'
146 << tmprow->pos() << '\t'
147 << tmprow->height() << '\t'
148 << tmprow->ascent_of_text() << '\t'
149 << tmprow->fill() << '\n';
150 tmprow = tmprow->next();
158 // Delete all rows, this does not touch the paragraphs!
159 Row * tmprow = firstrow;
161 tmprow = firstrow->next();
168 // Gets the fully instantiated font at a given position in a paragraph
169 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
170 // The difference is that this one is used for displaying, and thus we
171 // are allowed to make cosmetic improvements. For instance make footnotes
173 // If position is -1, we get the layout font of the paragraph.
174 // If position is -2, we get the font of the manual label of the paragraph.
175 LyXFont LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
176 LyXParagraph::size_type pos) const
178 LyXLayout const & layout =
179 textclasslist.Style(buf->params.textclass, par->GetLayout());
181 char par_depth = par->GetDepth();
182 // We specialize the 95% common case:
185 par->footnoteflag == LyXParagraph::NO_FOOTNOTE &&
190 if (layout.labeltype == LABEL_MANUAL
191 && pos < BeginningOfMainBody(buf, par)) {
193 return par->GetFontSettings(buf->params, pos).
194 realize(layout.reslabelfont);
196 return par->GetFontSettings(buf->params, pos).
197 realize(layout.resfont);
200 // process layoutfont for pos == -1 and labelfont for pos < -1
202 return layout.resfont;
204 return layout.reslabelfont;
208 // The uncommon case need not be optimized as much
210 LyXFont layoutfont, tmpfont;
214 if (pos < BeginningOfMainBody(buf, par)) {
216 layoutfont = layout.labelfont;
219 layoutfont = layout.font;
221 tmpfont = par->GetFontSettings(buf->params, pos);
222 tmpfont.realize(layoutfont);
225 // process layoutfont for pos == -1 and labelfont for pos < -1
227 tmpfont = layout.font;
229 tmpfont = layout.labelfont;
232 // Resolve against environment font information
233 while (par && par_depth && !tmpfont.resolved()) {
234 par = par->DepthHook(par_depth - 1);
236 tmpfont.realize(textclasslist.
237 Style(buf->params.textclass,
238 par->GetLayout()).font);
239 par_depth = par->GetDepth();
243 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
246 // Cosmetic improvement: If this is an open footnote, make the font
248 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
249 && par->footnotekind == LyXParagraph::FOOTNOTE) {
257 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
258 LyXParagraph::size_type pos,
262 // Let the insets convert their font
263 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
264 if (par->GetInset(pos))
265 font = par->GetInset(pos)->ConvertFont(font);
268 LyXLayout const & layout =
269 textclasslist.Style(buf->params.textclass,
272 // Get concrete layout font to reduce against
275 if (pos < BeginningOfMainBody(buf, par))
276 layoutfont = layout.labelfont;
278 layoutfont = layout.font;
280 // Realize against environment font information
281 if (par->GetDepth()){
282 LyXParagraph * tp = par;
283 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
284 tp = tp->DepthHook(tp->GetDepth()-1);
286 layoutfont.realize(textclasslist.
287 Style(buf->params.textclass,
288 tp->GetLayout()).font);
292 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
295 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
296 && par->footnotekind == LyXParagraph::FOOTNOTE) {
297 layoutfont.decSize();
300 // Now, reduce font against full layout font
301 font.reduce(layoutfont);
303 par->SetFont(pos, font);
307 /* inserts a new row behind the specified row, increments
308 * the touched counters */
309 void LyXText::InsertRow(Row * row, LyXParagraph * par,
310 LyXParagraph::size_type pos) const
312 Row * tmprow = new Row;
315 tmprow->next(firstrow);
318 tmprow->previous(row);
319 tmprow->next(row->next());
324 tmprow->next()->previous(tmprow);
326 if (tmprow->previous())
327 tmprow->previous()->next(tmprow);
335 ++number_of_rows; // one more row
339 // removes the row and reset the touched counters
340 void LyXText::RemoveRow(Row * row) const
342 /* this must not happen before the currentrow for clear reasons.
343 so the trick is just to set the current row onto the previous
346 GetRow(row->par(), row->pos(), unused_y);
349 row->next()->previous(row->previous());
350 if (!row->previous()) {
351 firstrow = row->next();
353 row->previous()->next(row->next());
356 lastrow = row->previous();
358 height -= row->height(); // the text becomes smaller
361 --number_of_rows; // one row less
365 // remove all following rows of the paragraph of the specified row.
366 void LyXText::RemoveParagraph(Row * row) const
368 LyXParagraph * tmppar = row->par();
372 while (row && row->par() == tmppar) {
373 tmprow = row->next();
380 // insert the specified paragraph behind the specified row
381 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
384 InsertRow(row, par, 0); /* insert a new row, starting
387 SetCounter(bview->buffer(), par); // set the counters
389 // and now append the whole paragraph behind the new row
392 AppendParagraph(bview, firstrow);
394 row->next()->height(0);
395 AppendParagraph(bview, row->next());
401 void LyXText::ToggleFootnote(BufferView * bview)
403 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
405 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
407 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
409 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
410 CloseFootnote(bview);
417 void LyXText::OpenStuff(BufferView * bview)
419 if (cursor.pos() == 0 && cursor.par()->bibkey){
420 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
421 } else if (cursor.pos() < cursor.par()->Last()
422 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
423 && cursor.par()->GetInset(cursor.pos())->Editable()) {
424 bview->owner()->getMiniBuffer()
425 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
426 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
427 SetCursorParUndo(bview->buffer());
428 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
432 ToggleFootnote(bview);
440 void LyXText::CloseFootnote(BufferView * bview)
442 LyXParagraph * tmppar;
443 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
445 // if the cursor is not in an open footnote, or
446 // there is no open footnote in this paragraph, just return.
447 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
450 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
451 bview->owner()->getMiniBuffer()
452 ->Set(_("Nothing to do"));
456 // ok, move the cursor right before the footnote
457 // just a little faster than using CursorRight()
459 cursor.par()->ParFromPos(cursor.pos()) != par;) {
460 cursor.pos(cursor.pos() + 1);
463 // now the cursor is at the beginning of the physical par
464 SetCursor(bview, cursor.par(),
466 cursor.par()->ParFromPos(cursor.pos())->size());
468 /* we are in a footnote, so let us move at the beginning */
469 /* this is just faster than using just CursorLeft() */
471 tmppar = cursor.par();
472 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
473 // just a little bit faster than movin the cursor
474 tmppar = tmppar->Previous();
476 SetCursor(bview, tmppar, tmppar->Last());
479 // the cursor must be exactly before the footnote
480 par = cursor.par()->ParFromPos(cursor.pos());
482 status = LyXText::NEED_MORE_REFRESH;
483 refresh_row = cursor.row();
484 refresh_y = cursor.y() - cursor.row()->baseline();
486 tmppar = cursor.par();
487 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
488 Row * row = cursor.row();
490 tmppar->CloseFootnote(cursor.pos());
492 while (tmppar != endpar) {
493 RemoveRow(row->next());
495 tmppar = row->next()->par();
500 AppendParagraph(bview, cursor.row());
502 SetCursor(bview, cursor.par(), cursor.pos());
506 if (cursor.row()->next())
507 SetHeightOfRow(bview, cursor.row()->next());
512 /* used in setlayout */
513 // Asger is not sure we want to do this...
514 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
518 LyXLayout const & layout =
519 textclasslist.Style(buf->params.textclass, par->GetLayout());
521 LyXFont layoutfont, tmpfont;
522 for (LyXParagraph::size_type pos = 0;
523 pos < par->Last(); ++pos) {
524 if (pos < BeginningOfMainBody(buf, par))
525 layoutfont = layout.labelfont;
527 layoutfont = layout.font;
529 tmpfont = par->GetFontSettings(buf->params, pos);
530 tmpfont.reduce(layoutfont);
531 par->SetFont(pos, tmpfont);
536 LyXParagraph * LyXText::SetLayout(BufferView * bview,
537 LyXCursor & cur, LyXCursor & sstart_cur,
538 LyXCursor & send_cur,
539 LyXTextClass::size_type layout)
542 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
544 LyXParagraph * endpar = send_cur.par()->Next();
546 LyXParagraph * undoendpar = endpar;
548 if (endpar && endpar->GetDepth()) {
549 while (endpar && endpar->GetDepth()) {
551 endpar = endpar->LastPhysicalPar()->Next();
553 endpar = endpar->Next();
558 endpar = endpar->Next(); // because of parindents etc.
561 SetUndo(bview->buffer(), Undo::EDIT,
563 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
565 sstart_cur.par()->previous,
569 /* ok we have a selection. This is always between sstart_cur
570 * and sel_end cursor */
573 LyXLayout const & lyxlayout =
574 textclasslist.Style(bview->buffer()->params.textclass, layout);
576 while (cur.par() != send_cur.par()) {
578 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
580 cur.par()->SetLayout(bview->buffer()->params, layout);
581 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
583 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
585 LyXParagraph * fppar = cur.par();
587 fppar->added_space_top = lyxlayout.fill_top ?
588 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
589 fppar->added_space_bottom = lyxlayout.fill_bottom ?
590 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
591 if (lyxlayout.margintype == MARGIN_MANUAL)
592 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
593 if (lyxlayout.labeltype != LABEL_BIBLIO
595 delete fppar->bibkey;
601 cur.par(cur.par()->Next());
604 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
606 cur.par()->SetLayout(bview->buffer()->params, layout);
607 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
609 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
611 LyXParagraph * fppar = cur.par();
613 fppar->added_space_top = lyxlayout.fill_top ?
614 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
615 fppar->added_space_bottom = lyxlayout.fill_bottom ?
616 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
617 if (lyxlayout.margintype == MARGIN_MANUAL)
618 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
619 if (lyxlayout.labeltype != LABEL_BIBLIO
621 delete fppar->bibkey;
630 // set layout over selection and make a total rebreak of those paragraphs
631 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
633 LyXCursor tmpcursor = cursor; /* store the current cursor */
635 // if there is no selection just set the layout
636 // of the current paragraph */
638 sel_start_cursor = cursor; // dummy selection
639 sel_end_cursor = cursor;
642 endpar = SetLayout(bview, cursor, sel_start_cursor,
643 sel_end_cursor, layout);
644 RedoParagraphs(bview, sel_start_cursor, endpar);
646 // we have to reset the selection, because the
647 // geometry could have changed
648 SetCursor(bview, sel_start_cursor.par(),
649 sel_start_cursor.pos(), false);
651 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
653 UpdateCounters(bview, cursor.row());
656 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
660 // increment depth over selection and
661 // make a total rebreak of those paragraphs
662 void LyXText::IncDepth(BufferView * bview)
664 // If there is no selection, just use the current paragraph
666 sel_start_cursor = cursor; // dummy selection
667 sel_end_cursor = cursor;
670 // We end at the next paragraph with depth 0
671 LyXParagraph * endpar =
673 sel_end_cursor.par()->LastPhysicalPar()->Next();
675 sel_end_cursor.par()->Next();
677 LyXParagraph * undoendpar = endpar;
679 if (endpar && endpar->GetDepth()) {
680 while (endpar && endpar->GetDepth()) {
682 endpar = endpar->LastPhysicalPar()->Next();
684 endpar = endpar->Next();
690 endpar = endpar->Next(); // because of parindents etc.
693 SetUndo(bview->buffer(), Undo::EDIT,
696 .par()->ParFromPos(sel_start_cursor.pos())->previous,
698 sel_start_cursor.par()->previous,
702 LyXCursor tmpcursor = cursor; // store the current cursor
704 // ok we have a selection. This is always between sel_start_cursor
705 // and sel_end cursor
706 cursor = sel_start_cursor;
708 bool anything_changed = false;
711 // NOTE: you can't change the depth of a bibliography entry
714 cursor.par()->footnoteflag ==
715 sel_start_cursor.par()->footnoteflag &&
717 textclasslist.Style(bview->buffer()->params.textclass,
718 cursor.par()->GetLayout()
719 ).labeltype != LABEL_BIBLIO) {
720 LyXParagraph * prev =
722 cursor.par()->FirstPhysicalPar()->Previous();
724 cursor.par()->Previous();
727 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
728 || (prev->GetDepth() == cursor.par()->GetDepth()
729 && textclasslist.Style(bview->buffer()->params.textclass,
730 prev->GetLayout()).isEnvironment()))) {
732 cursor.par()->FirstPhysicalPar()->depth++;
734 cursor.par()->depth++;
736 anything_changed = true;
739 if (cursor.par() == sel_end_cursor.par())
741 cursor.par(cursor.par()->Next());
744 // if nothing changed set all depth to 0
745 if (!anything_changed) {
746 cursor = sel_start_cursor;
747 while (cursor.par() != sel_end_cursor.par()) {
749 cursor.par()->FirstPhysicalPar()->depth = 0;
751 cursor.par()->depth = 0;
753 cursor.par(cursor.par()->Next());
756 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
757 cursor.par()->FirstPhysicalPar()->depth = 0;
759 cursor.par()->depth = 0;
763 RedoParagraphs(bview, sel_start_cursor, endpar);
765 // we have to reset the selection, because the
766 // geometry could have changed
767 SetCursor(bview, sel_start_cursor.par(),
768 sel_start_cursor.pos());
770 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
771 UpdateCounters(bview, cursor.row());
774 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
778 // decrement depth over selection and
779 // make a total rebreak of those paragraphs
780 void LyXText::DecDepth(BufferView * bview)
782 // if there is no selection just set the layout
783 // of the current paragraph
785 sel_start_cursor = cursor; // dummy selection
786 sel_end_cursor = cursor;
789 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
791 LyXParagraph * endpar = sel_end_cursor.par()->Next();
793 LyXParagraph * undoendpar = endpar;
795 if (endpar && endpar->GetDepth()) {
796 while (endpar && endpar->GetDepth()) {
798 endpar = endpar->LastPhysicalPar()->Next();
800 endpar = endpar->Next();
806 endpar = endpar->Next(); // because of parindents etc.
809 SetUndo(bview->buffer(), Undo::EDIT,
812 .par()->ParFromPos(sel_start_cursor.pos())->previous,
814 sel_start_cursor.par()->previous,
818 LyXCursor tmpcursor = cursor; // store the current cursor
820 // ok we have a selection. This is always between sel_start_cursor
821 // and sel_end cursor
822 cursor = sel_start_cursor;
826 if (cursor.par()->footnoteflag ==
827 sel_start_cursor.par()->footnoteflag) {
828 if (cursor.par()->FirstPhysicalPar()->depth)
829 cursor.par()->FirstPhysicalPar()->depth--;
832 if (cursor.par()->depth)
833 cursor.par()->depth--;
835 if (cursor.par() == sel_end_cursor.par())
837 cursor.par(cursor.par()->Next());
840 RedoParagraphs(bview, sel_start_cursor, endpar);
842 // we have to reset the selection, because the
843 // geometry could have changed
844 SetCursor(bview, sel_start_cursor.par(),
845 sel_start_cursor.pos());
847 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
848 UpdateCounters(bview, cursor.row());
851 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
855 // set font over selection and make a total rebreak of those paragraphs
856 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
858 // if there is no selection just set the current_font
860 // Determine basis font
862 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
864 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
866 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
867 // Update current font
868 real_current_font.update(font,
869 bview->buffer()->params.language_info,
872 // Reduce to implicit settings
873 current_font = real_current_font;
874 current_font.reduce(layoutfont);
875 // And resolve it completely
876 real_current_font.realize(layoutfont);
880 LyXCursor tmpcursor = cursor; // store the current cursor
882 // ok we have a selection. This is always between sel_start_cursor
883 // and sel_end cursor
885 SetUndo(bview->buffer(), Undo::EDIT,
887 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
888 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next
890 sel_start_cursor.par()->previous,
891 sel_end_cursor.par()->next
894 cursor = sel_start_cursor;
895 while (cursor.par() != sel_end_cursor.par() ||
898 cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag &&
900 cursor.pos() < sel_end_cursor.pos()))
902 if (cursor.pos() < cursor.par()->Last()
904 && cursor.par()->footnoteflag
905 == sel_start_cursor.par()->footnoteflag
908 // an open footnote should behave
910 LyXFont newfont = GetFont(bview->buffer(),
911 cursor.par(), cursor.pos());
913 bview->buffer()->params.language_info,
915 SetCharFont(bview->buffer(),
916 cursor.par(), cursor.pos(), newfont);
917 cursor.pos(cursor.pos() + 1);
920 cursor.par(cursor.par()->Next());
924 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
926 // we have to reset the selection, because the
927 // geometry could have changed
928 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
930 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
933 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
934 tmpcursor.boundary());
938 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
940 Row * tmprow = cur.row();
941 long y = cur.y() - tmprow->baseline();
943 SetHeightOfRow(bview, tmprow);
945 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
947 LyXParagraph * first_phys_par = tmprow->par();
949 // find the first row of the paragraph
950 if (first_phys_par != tmprow->par())
951 while (tmprow->previous()
952 && tmprow->previous()->par() != first_phys_par) {
953 tmprow = tmprow->previous();
954 y -= tmprow->height();
955 SetHeightOfRow(bview, tmprow);
957 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
958 tmprow = tmprow->previous();
959 y -= tmprow->height();
960 SetHeightOfRow(bview, tmprow);
963 // we can set the refreshing parameters now
964 status = LyXText::NEED_MORE_REFRESH;
966 refresh_row = tmprow;
967 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
971 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
973 Row * tmprow = cur.row();
975 long y = cur.y() - tmprow->baseline();
976 SetHeightOfRow(bview, tmprow);
978 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
980 LyXParagraph * first_phys_par = tmprow->par();
982 // find the first row of the paragraph
983 if (first_phys_par != tmprow->par())
984 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
985 tmprow = tmprow->previous();
986 y -= tmprow->height();
988 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
989 tmprow = tmprow->previous();
990 y -= tmprow->height();
993 // we can set the refreshing parameters now
994 if (status == LyXText::UNCHANGED || y < refresh_y) {
996 refresh_row = tmprow;
998 status = LyXText::NEED_MORE_REFRESH;
999 SetCursor(bview, cur.par(), cur.pos());
1003 /* deletes and inserts again all paragaphs between the cursor
1004 * and the specified par
1005 * This function is needed after SetLayout and SetFont etc. */
1006 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
1007 LyXParagraph const * endpar) const
1010 LyXParagraph * tmppar = 0, * first_phys_par = 0;
1012 Row * tmprow = cur.row();
1014 long y = cur.y() - tmprow->baseline();
1016 if (!tmprow->previous()){
1017 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
1020 first_phys_par = tmprow->par()->FirstPhysicalPar();
1022 first_phys_par = tmprow->par();
1024 // find the first row of the paragraph
1025 if (first_phys_par != tmprow->par())
1026 while (tmprow->previous() &&
1027 (tmprow->previous()->par() != first_phys_par)) {
1028 tmprow = tmprow->previous();
1029 y -= tmprow->height();
1031 while (tmprow->previous()
1032 && tmprow->previous()->par() == first_phys_par) {
1033 tmprow = tmprow->previous();
1034 y -= tmprow->height();
1038 // we can set the refreshing parameters now
1039 status = LyXText::NEED_MORE_REFRESH;
1041 refresh_row = tmprow->previous(); /* the real refresh row will
1042 be deleted, so I store
1043 the previous here */
1046 tmppar = tmprow->next()->par();
1049 while (tmppar != endpar) {
1050 RemoveRow(tmprow->next());
1052 tmppar = tmprow->next()->par();
1057 // remove the first one
1058 tmprow2 = tmprow; /* this is because tmprow->previous()
1060 tmprow = tmprow->previous();
1063 tmppar = first_phys_par;
1067 InsertParagraph(bview, tmppar, tmprow);
1070 while (tmprow->next() && tmprow->next()->par() == tmppar)
1071 tmprow = tmprow->next();
1072 tmppar = tmppar->Next();
1074 } while (tmppar != endpar);
1076 // this is because of layout changes
1078 refresh_y -= refresh_row->height();
1079 SetHeightOfRow(bview, refresh_row);
1081 refresh_row = firstrow;
1083 SetHeightOfRow(bview, refresh_row);
1086 if (tmprow && tmprow->next())
1087 SetHeightOfRow(bview, tmprow->next());
1091 bool LyXText::FullRebreak(BufferView * bview)
1097 if (need_break_row) {
1098 BreakAgain(bview, need_break_row);
1106 /* important for the screen */
1109 /* the cursor set functions have a special mechanism. When they
1110 * realize, that you left an empty paragraph, they will delete it.
1111 * They also delete the corresponding row */
1113 // need the selection cursor:
1114 void LyXText::SetSelection()
1117 last_sel_cursor = sel_cursor;
1118 sel_start_cursor = sel_cursor;
1119 sel_end_cursor = sel_cursor;
1124 // first the toggling area
1125 if (cursor.y() < last_sel_cursor.y()
1126 || (cursor.y() == last_sel_cursor.y()
1127 && cursor.x() < last_sel_cursor.x())) {
1128 toggle_end_cursor = last_sel_cursor;
1129 toggle_cursor = cursor;
1131 toggle_end_cursor = cursor;
1132 toggle_cursor = last_sel_cursor;
1135 last_sel_cursor = cursor;
1137 // and now the whole selection
1139 if (sel_cursor.par() == cursor.par())
1140 if (sel_cursor.pos() < cursor.pos()) {
1141 sel_end_cursor = cursor;
1142 sel_start_cursor = sel_cursor;
1144 sel_end_cursor = sel_cursor;
1145 sel_start_cursor = cursor;
1147 else if (sel_cursor.y() < cursor.y() ||
1148 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1149 sel_end_cursor = cursor;
1150 sel_start_cursor = sel_cursor;
1153 sel_end_cursor = sel_cursor;
1154 sel_start_cursor = cursor;
1157 // a selection with no contents is not a selection
1158 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1159 sel_start_cursor.pos() == sel_end_cursor.pos())
1164 string LyXText::selectionAsString(Buffer const * buffer) const
1166 if (!selection) return string();
1169 // Special handling if the whole selection is within one paragraph
1170 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1171 result += sel_start_cursor.par()->String(buffer,
1172 sel_start_cursor.pos(),
1173 sel_end_cursor.pos());
1177 // The selection spans more than one paragraph
1179 // First paragraph in selection
1180 result += sel_start_cursor.par()->String(buffer,
1181 sel_start_cursor.pos(),
1182 sel_start_cursor.par()->Last())
1185 // The paragraphs in between (if any)
1186 LyXCursor tmpcur(sel_start_cursor);
1187 tmpcur.par(tmpcur.par()->Next());
1188 while (tmpcur.par() != sel_end_cursor.par()) {
1189 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1190 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1193 // Last paragraph in selection
1194 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1200 void LyXText::ClearSelection() const
1207 void LyXText::CursorHome(BufferView * bview) const
1209 SetCursor(bview, cursor.par(), cursor.row()->pos());
1213 void LyXText::CursorEnd(BufferView * bview) const
1215 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1216 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1218 if (cursor.par()->Last() &&
1219 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1220 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1221 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1223 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1226 if (cursor.par()->table) {
1227 int cell = NumberOfCell(cursor.par(), cursor.pos());
1228 if (cursor.par()->table->RowHasContRow(cell) &&
1229 cursor.par()->table->CellHasContRow(cell)<0) {
1230 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1231 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1233 if (cursor.par()->Last() &&
1234 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1235 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1236 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1238 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1246 void LyXText::CursorTop(BufferView * bview) const
1248 while (cursor.par()->Previous())
1249 cursor.par(cursor.par()->Previous());
1250 SetCursor(bview, cursor.par(), 0);
1254 void LyXText::CursorBottom(BufferView * bview) const
1256 while (cursor.par()->Next())
1257 cursor.par(cursor.par()->Next());
1258 SetCursor(bview, cursor.par(), cursor.par()->Last());
1262 /* returns a pointer to the row near the specified y-coordinate
1263 * (relative to the whole text). y is set to the real beginning
1265 Row * LyXText::GetRowNearY(long & y) const
1267 Row * tmprow = firstrow;
1270 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1271 tmpy += tmprow->height();
1272 tmprow = tmprow->next();
1275 y = tmpy; // return the real y
1280 void LyXText::ToggleFree(BufferView * bview,
1281 LyXFont const & font, bool toggleall)
1283 // If the mask is completely neutral, tell user
1284 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1285 // Could only happen with user style
1286 bview->owner()->getMiniBuffer()
1287 ->Set(_("No font change defined. Use Character under"
1288 " the Layout menu to define font change."));
1292 // Try implicit word selection
1293 // If there is a change in the language the implicit word selection
1295 LyXCursor resetCursor = cursor;
1296 bool implicitSelection = (font.language() == ignore_language)
1297 ? SelectWordWhenUnderCursor(bview) : false;
1300 SetFont(bview, font, toggleall);
1302 /* Implicit selections are cleared afterwards and cursor is set to the
1303 original position. */
1304 if (implicitSelection) {
1306 cursor = resetCursor;
1307 SetCursor(bview, cursor.par(), cursor.pos());
1308 sel_cursor = cursor;
1313 LyXParagraph::size_type
1314 LyXText::BeginningOfMainBody(Buffer const * buf,
1315 LyXParagraph const * par) const
1317 if (textclasslist.Style(buf->params.textclass,
1318 par->GetLayout()).labeltype != LABEL_MANUAL)
1321 return par->BeginningOfMainBody();
1326 /* if there is a selection, reset every environment you can find
1327 * in the selection, otherwise just the environment you are in */
1328 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1330 LyXParagraph * tmppar, * firsttmppar;
1334 /* is is only allowed, if the cursor is IN an open footnote.
1335 * Otherwise it is too dangerous */
1336 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1339 SetUndo(bview->buffer(), Undo::FINISH,
1340 cursor.par()->PreviousBeforeFootnote()->previous,
1341 cursor.par()->NextAfterFootnote()->next);
1343 /* ok, move to the beginning of the footnote. */
1344 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1345 cursor.par(cursor.par()->Previous());
1347 SetCursor(bview, cursor.par(), cursor.par()->Last());
1348 /* this is just faster than using CursorLeft(); */
1350 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1351 tmppar = firsttmppar;
1352 /* tmppar is now the paragraph right before the footnote */
1354 bool first_footnote_par_is_not_empty = tmppar->next->size();
1357 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1358 tmppar = tmppar->next; /* I use next instead of Next(),
1359 * because there cannot be any
1360 * footnotes in a footnote
1362 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1364 /* remember the captions and empty paragraphs */
1365 if ((textclasslist.Style(bview->buffer()->params.textclass,
1366 tmppar->GetLayout())
1367 .labeltype == LABEL_SENSITIVE)
1369 tmppar->SetLayout(bview->buffer()->params, 0);
1372 // now we will paste the ex-footnote, if the layouts allow it
1373 // first restore the layout of the paragraph right behind
1376 tmppar->next->MakeSameLayout(cursor.par());
1379 if ((!tmppar->GetLayout()
1385 && (!tmppar->Next()->Last()
1386 || tmppar->Next()->HasSameLayout(tmppar)))) {
1387 if (tmppar->Next()->Last()
1388 && tmppar->Next()->IsLineSeparator(0))
1389 tmppar->Next()->Erase(0);
1390 tmppar->PasteParagraph(bview->buffer()->params);
1393 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1394 * by the pasting of the beginning */
1396 /* then the beginning */
1397 /* if there is no space between the text and the footnote, so we insert
1399 * (only if the previous par and the footnotepar are not empty!) */
1400 if ((!firsttmppar->next->GetLayout()
1402 && !firsttmppar->next->table
1405 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1406 if (firsttmppar->size()
1407 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1408 && first_footnote_par_is_not_empty) {
1409 firsttmppar->next->InsertChar(0, ' ');
1411 firsttmppar->PasteParagraph(bview->buffer()->params);
1414 /* now redo the paragaphs */
1415 RedoParagraphs(bview, cursor, tmppar);
1417 SetCursor(bview, cursor.par(), cursor.pos());
1419 /* sometimes it can happen, that there is a counter change */
1420 Row * row = cursor.row();
1421 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1423 UpdateCounters(bview, row);
1431 /* the DTP switches for paragraphs. LyX will store them in the
1432 * first physicla paragraph. When a paragraph is broken, the top settings
1433 * rest, the bottom settings are given to the new one. So I can make shure,
1434 * they do not duplicate themself and you cannnot make dirty things with
1437 void LyXText::SetParagraph(BufferView * bview,
1438 bool line_top, bool line_bottom,
1439 bool pagebreak_top, bool pagebreak_bottom,
1440 VSpace const & space_top,
1441 VSpace const & space_bottom,
1443 string labelwidthstring,
1446 LyXCursor tmpcursor = cursor;
1448 sel_start_cursor = cursor;
1449 sel_end_cursor = cursor;
1452 // make sure that the depth behind the selection are restored, too
1454 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1456 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1458 LyXParagraph * undoendpar = endpar;
1460 if (endpar && endpar->GetDepth()) {
1461 while (endpar && endpar->GetDepth()) {
1463 endpar = endpar->LastPhysicalPar()->Next();
1465 endpar = endpar->Next();
1467 undoendpar = endpar;
1471 endpar = endpar->Next(); // because of parindents etc.
1474 SetUndo(bview->buffer(), Undo::EDIT,
1477 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1479 sel_start_cursor.par()->previous,
1484 LyXParagraph * tmppar = sel_end_cursor.par();
1486 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1487 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1489 while (tmppar != sel_start_cursor.par()->Previous()) {
1490 SetCursor(bview, tmppar, 0);
1492 status = LyXText::NEED_MORE_REFRESH;
1493 refresh_row = cursor.row();
1494 refresh_y = cursor.y() - cursor.row()->baseline();
1496 if (cursor.par()->footnoteflag ==
1497 sel_start_cursor.par()->footnoteflag) {
1499 cursor.par()->line_top = line_top;
1500 cursor.par()->line_bottom = line_bottom;
1501 cursor.par()->pagebreak_top = pagebreak_top;
1502 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1503 cursor.par()->added_space_top = space_top;
1504 cursor.par()->added_space_bottom = space_bottom;
1505 // does the layout allow the new alignment?
1506 if (align == LYX_ALIGN_LAYOUT)
1507 align = textclasslist
1508 .Style(bview->buffer()->params.textclass,
1509 cursor.par()->GetLayout()).align;
1510 if (align & textclasslist
1511 .Style(bview->buffer()->params.textclass,
1512 cursor.par()->GetLayout()).alignpossible) {
1513 if (align == textclasslist
1514 .Style(bview->buffer()->params.textclass,
1515 cursor.par()->GetLayout()).align)
1516 cursor.par()->align = LYX_ALIGN_LAYOUT;
1518 cursor.par()->align = align;
1520 cursor.par()->SetLabelWidthString(labelwidthstring);
1521 cursor.par()->noindent = noindent;
1525 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1527 tmppar = cursor.par()->Previous();
1531 RedoParagraphs(bview, sel_start_cursor, endpar);
1534 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1535 sel_cursor = cursor;
1536 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1538 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1540 bview->updateInset(inset_owner, true);
1544 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1546 char const * widthp,
1547 int alignment, bool hfill,
1548 bool start_minipage)
1550 LyXCursor tmpcursor = cursor;
1551 LyXParagraph * tmppar;
1553 sel_start_cursor = cursor;
1554 sel_end_cursor = cursor;
1557 // make sure that the depth behind the selection are restored, too
1559 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1561 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1563 LyXParagraph * undoendpar = endpar;
1565 if (endpar && endpar->GetDepth()) {
1566 while (endpar && endpar->GetDepth()) {
1568 endpar = endpar->LastPhysicalPar()->Next();
1570 endpar = endpar->Next();
1572 undoendpar = endpar;
1576 endpar = endpar->Next(); // because of parindents etc.
1579 SetUndo(bview->buffer(), Undo::EDIT,
1582 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1584 sel_start_cursor.par()->previous,
1588 tmppar = sel_end_cursor.par();
1590 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1591 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1593 while(tmppar != sel_start_cursor.par()->Previous()) {
1594 SetCursor(bview, tmppar, 0);
1596 status = LyXText::NEED_MORE_REFRESH;
1597 refresh_row = cursor.row();
1598 refresh_y = cursor.y() - cursor.row()->baseline();
1600 if (cursor.par()->footnoteflag ==
1601 sel_start_cursor.par()->footnoteflag) {
1603 if (type == LyXParagraph::PEXTRA_NONE) {
1604 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1605 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1606 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1609 cursor.par()->SetPExtraType(bview->buffer()->params,
1610 type, width, widthp);
1611 cursor.par()->pextra_hfill = hfill;
1612 cursor.par()->pextra_start_minipage = start_minipage;
1613 cursor.par()->pextra_alignment = alignment;
1617 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1619 tmppar = cursor.par()->Previous();
1622 RedoParagraphs(bview, sel_start_cursor, endpar);
1624 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1625 sel_cursor = cursor;
1626 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1628 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1632 char loweralphaCounter(int n)
1634 if (n < 1 || n > 26)
1641 char alphaCounter(int n)
1643 if (n < 1 || n > 26)
1650 char hebrewCounter(int n)
1652 static const char hebrew[22] = {
1653 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1654 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1655 '÷', 'ø', 'ù', 'ú'
1657 if (n < 1 || n > 22)
1665 char const * romanCounter(int n)
1667 static char const * roman[20] = {
1668 "i", "ii", "iii", "iv", "v",
1669 "vi", "vii", "viii", "ix", "x",
1670 "xi", "xii", "xiii", "xiv", "xv",
1671 "xvi", "xvii", "xviii", "xix", "xx"
1673 if (n < 1 || n > 20)
1680 // set the counter of a paragraph. This includes the labels
1681 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1684 // this is only relevant for the beginning of paragraph
1685 par = par->FirstPhysicalPar();
1687 LyXLayout const & layout =
1688 textclasslist.Style(buf->params.textclass,
1691 LyXTextClass const & textclass =
1692 textclasslist.TextClass(buf->params.textclass);
1694 /* copy the prev-counters to this one, unless this is the start of a
1695 footnote or of a bibliography or the very first paragraph */
1698 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1699 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1700 && par->footnotekind == LyXParagraph::FOOTNOTE)
1702 && !(textclasslist.Style(buf->params.textclass,
1703 par->Previous()->GetLayout()
1704 ).labeltype != LABEL_BIBLIO
1705 && layout.labeltype == LABEL_BIBLIO)) {
1706 for (int i = 0; i < 10; ++i) {
1707 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1710 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1712 par->appendix = par->Previous()->appendix;
1714 if (!par->appendix && par->start_of_appendix){
1715 par->appendix = true;
1716 for (int i = 0; i < 10; ++i) {
1717 par->setCounter(i, 0);
1721 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1722 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1724 par->enumdepth = par->Previous()->enumdepth;
1725 par->itemdepth = par->Previous()->itemdepth;
1728 for (int i = 0; i < 10; ++i) {
1729 par->setCounter(i, 0);
1731 par->appendix = par->start_of_appendix;
1737 // if this is an open marginnote and this is the first
1738 // entry in the marginnote and the enclosing
1739 // environment is an enum/item then correct for the
1740 // LaTeX behaviour (ARRae)
1741 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1742 && par->footnotekind == LyXParagraph::MARGIN
1744 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1745 && (par->PreviousBeforeFootnote()
1746 && textclasslist.Style(buf->params.textclass,
1747 par->PreviousBeforeFootnote()->GetLayout()
1748 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1749 // Any itemize or enumerate environment in a marginnote
1750 // that is embedded in an itemize or enumerate
1751 // paragraph is seen by LaTeX as being at a deeper
1752 // level within that enclosing itemization/enumeration
1753 // even if there is a "standard" layout at the start of
1759 /* Maybe we have to increment the enumeration depth.
1760 * BUT, enumeration in a footnote is considered in isolation from its
1761 * surrounding paragraph so don't increment if this is the
1762 * first line of the footnote
1763 * AND, bibliographies can't have their depth changed ie. they
1764 * are always of depth 0
1767 && par->Previous()->GetDepth() < par->GetDepth()
1768 && textclasslist.Style(buf->params.textclass,
1769 par->Previous()->GetLayout()
1770 ).labeltype == LABEL_COUNTER_ENUMI
1771 && par->enumdepth < 3
1773 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1774 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1775 && par->footnotekind == LyXParagraph::FOOTNOTE)
1777 && layout.labeltype != LABEL_BIBLIO) {
1781 /* Maybe we have to decrement the enumeration depth, see note above */
1783 && par->Previous()->GetDepth() > par->GetDepth()
1785 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1786 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1787 && par->footnotekind == LyXParagraph::FOOTNOTE)
1789 && layout.labeltype != LABEL_BIBLIO) {
1790 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1791 par->setCounter(6 + par->enumdepth,
1792 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1793 /* reset the counters.
1794 * A depth change is like a breaking layout
1796 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1797 par->setCounter(i, 0);
1800 if (!par->labelstring.empty()) {
1801 par->labelstring.erase();
1804 if (layout.margintype == MARGIN_MANUAL) {
1805 if (par->labelwidthstring.empty()) {
1806 par->SetLabelWidthString(layout.labelstring());
1809 par->SetLabelWidthString(string());
1812 /* is it a layout that has an automatic label ? */
1813 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1815 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1816 if (i >= 0 && i<= buf->params.secnumdepth) {
1817 par->incCounter(i); // increment the counter
1819 // Is there a label? Useful for Chapter layout
1820 if (!par->appendix){
1821 if (!layout.labelstring().empty())
1822 par->labelstring = layout.labelstring();
1824 par->labelstring.erase();
1826 if (!layout.labelstring_appendix().empty())
1827 par->labelstring = layout.labelstring_appendix();
1829 par->labelstring.erase();
1833 std::ostringstream s;
1837 if (!par->appendix) {
1838 switch (2 * LABEL_COUNTER_CHAPTER -
1839 textclass.maxcounter() + i) {
1840 case LABEL_COUNTER_CHAPTER:
1841 s << par->getCounter(i);
1843 case LABEL_COUNTER_SECTION:
1844 s << par->getCounter(i - 1) << '.'
1845 << par->getCounter(i);
1847 case LABEL_COUNTER_SUBSECTION:
1848 s << par->getCounter(i - 2) << '.'
1849 << par->getCounter(i - 1) << '.'
1850 << par->getCounter(i);
1852 case LABEL_COUNTER_SUBSUBSECTION:
1853 s << par->getCounter(i - 3) << '.'
1854 << par->getCounter(i - 2) << '.'
1855 << par->getCounter(i - 1) << '.'
1856 << par->getCounter(i);
1859 case LABEL_COUNTER_PARAGRAPH:
1860 s << par->getCounter(i - 4) << '.'
1861 << par->getCounter(i - 3) << '.'
1862 << par->getCounter(i - 2) << '.'
1863 << par->getCounter(i - 1) << '.'
1864 << par->getCounter(i);
1866 case LABEL_COUNTER_SUBPARAGRAPH:
1867 s << par->getCounter(i - 5) << '.'
1868 << par->getCounter(i - 4) << '.'
1869 << par->getCounter(i - 3) << '.'
1870 << par->getCounter(i - 2) << '.'
1871 << par->getCounter(i - 1) << '.'
1872 << par->getCounter(i);
1876 // Can this ever be reached? And in the
1877 // case it is, how can this be correct?
1879 s << par->getCounter(i) << '.';
1882 } else { // appendix
1883 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1884 case LABEL_COUNTER_CHAPTER:
1885 if (par->isRightToLeftPar(buf->params))
1886 s << hebrewCounter(par->getCounter(i));
1888 s << alphaCounter(par->getCounter(i));
1890 case LABEL_COUNTER_SECTION:
1891 if (par->isRightToLeftPar(buf->params))
1892 s << hebrewCounter(par->getCounter(i - 1));
1894 s << alphaCounter(par->getCounter(i - 1));
1897 << par->getCounter(i);
1900 case LABEL_COUNTER_SUBSECTION:
1901 if (par->isRightToLeftPar(buf->params))
1902 s << hebrewCounter(par->getCounter(i - 2));
1904 s << alphaCounter(par->getCounter(i - 2));
1907 << par->getCounter(i-1) << '.'
1908 << par->getCounter(i);
1911 case LABEL_COUNTER_SUBSUBSECTION:
1912 if (par->isRightToLeftPar(buf->params))
1913 s << hebrewCounter(par->getCounter(i-3));
1915 s << alphaCounter(par->getCounter(i-3));
1918 << par->getCounter(i-2) << '.'
1919 << par->getCounter(i-1) << '.'
1920 << par->getCounter(i);
1923 case LABEL_COUNTER_PARAGRAPH:
1924 if (par->isRightToLeftPar(buf->params))
1925 s << hebrewCounter(par->getCounter(i-4));
1927 s << alphaCounter(par->getCounter(i-4));
1930 << par->getCounter(i-3) << '.'
1931 << par->getCounter(i-2) << '.'
1932 << par->getCounter(i-1) << '.'
1933 << par->getCounter(i);
1936 case LABEL_COUNTER_SUBPARAGRAPH:
1937 if (par->isRightToLeftPar(buf->params))
1938 s << hebrewCounter(par->getCounter(i-5));
1940 s << alphaCounter(par->getCounter(i-5));
1943 << par->getCounter(i-4) << '.'
1944 << par->getCounter(i-3) << '.'
1945 << par->getCounter(i-2) << '.'
1946 << par->getCounter(i-1) << '.'
1947 << par->getCounter(i);
1951 // Can this ever be reached? And in the
1952 // case it is, how can this be correct?
1954 s << par->getCounter(i) << '.';
1960 par->labelstring += s.str().c_str();
1961 // We really want to remove the c_str as soon as
1965 char * tmps = s.str();
1966 par->labelstring += tmps;
1970 for (i++; i < 10; ++i) {
1971 // reset the following counters
1972 par->setCounter(i, 0);
1974 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1975 for (i++; i < 10; ++i) {
1976 // reset the following counters
1977 par->setCounter(i, 0);
1979 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1980 par->incCounter(i + par->enumdepth);
1981 int number = par->getCounter(i + par->enumdepth);
1984 std::ostringstream s;
1988 switch (par->enumdepth) {
1990 if (par->isRightToLeftPar(buf->params))
1992 << hebrewCounter(number)
1996 << loweralphaCounter(number)
2000 if (par->isRightToLeftPar(buf->params))
2001 s << '.' << romanCounter(number);
2003 s << romanCounter(number) << '.';
2006 if (par->isRightToLeftPar(buf->params))
2008 << alphaCounter(number);
2010 s << alphaCounter(number)
2014 if (par->isRightToLeftPar(buf->params))
2021 par->labelstring = s.str().c_str();
2022 // we really want to get rid of that c_str()
2025 char * tmps = s.str();
2026 par->labelstring = tmps;
2030 for (i += par->enumdepth + 1; i < 10; ++i)
2031 par->setCounter(i, 0); /* reset the following counters */
2034 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2035 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2037 int number = par->getCounter(i);
2039 InsetCommandParams p( "bibitem" );
2040 par->bibkey = new InsetBibKey(p);
2042 par->bibkey->setCounter(number);
2043 par->labelstring = layout.labelstring();
2045 // In biblio should't be following counters but...
2047 string s = layout.labelstring();
2049 // the caption hack:
2050 if (layout.labeltype == LABEL_SENSITIVE) {
2051 bool isOK (par->InInset() && par->InInset()->owner() &&
2052 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2054 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2055 && (par->footnotekind == LyXParagraph::FIG
2056 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2057 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2058 ? ":øåéà " : "Figure:";
2059 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2060 && (par->footnotekind == LyXParagraph::TAB
2061 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2062 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2063 ? ":äìáè" : "Table:";
2064 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2065 && par->footnotekind == LyXParagraph::ALGORITHM) {
2066 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2067 ? ":Ãúéøåâìà " : "Algorithm:";
2071 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2073 = floatList.getType(tmp->type());
2074 // We should get the correct number here too.
2075 s = fl.name + " #:";
2077 /* par->SetLayout(0);
2078 s = layout->labelstring; */
2079 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2080 ? " :úåòîùî øñç" : "Senseless: ";
2083 par->labelstring = s;
2085 /* reset the enumeration counter. They are always resetted
2086 * when there is any other layout between */
2087 for (int i = 6 + par->enumdepth; i < 10; ++i)
2088 par->setCounter(i, 0);
2093 /* Updates all counters BEHIND the row. Changed paragraphs
2094 * with a dynamic left margin will be rebroken. */
2095 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2102 if (row->par()->next
2104 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2108 par = row->par()->LastPhysicalPar()->Next();
2110 par = row->par()->Next();
2113 par = row->par()->next;
2118 while (row->par() != par)
2121 SetCounter(bview->buffer(), par);
2123 /* now check for the headline layouts. remember that they
2124 * have a dynamic left margin */
2129 ( textclasslist.Style(bview->buffer()->params.textclass,
2130 par->layout).margintype == MARGIN_DYNAMIC
2131 || textclasslist.Style(bview->buffer()->params.textclass,
2132 par->layout).labeltype == LABEL_SENSITIVE)
2135 /* Rebreak the paragraph */
2136 RemoveParagraph(row);
2137 AppendParagraph(bview, row);
2140 /* think about the damned open footnotes! */
2141 while (par->Next() &&
2142 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2143 || par->Next()->IsDummy())){
2145 if (par->IsDummy()) {
2146 while (row->par() != par)
2148 RemoveParagraph(row);
2149 AppendParagraph(bview, row);
2155 par = par->LastPhysicalPar()->Next();
2164 /* insets an inset. */
2165 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2167 if (!cursor.par()->InsertInsetAllowed(inset))
2169 SetUndo(bview->buffer(), Undo::INSERT,
2171 cursor.par()->ParFromPos(cursor.pos())->previous,
2172 cursor.par()->ParFromPos(cursor.pos())->next
2174 cursor.par()->previous,
2178 cursor.par()->InsertInset(cursor.pos(), inset);
2179 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2180 * The character will not be inserted a
2185 void LyXText::copyEnvironmentType()
2187 copylayouttype = cursor.par()->GetLayout();
2191 void LyXText::pasteEnvironmentType(BufferView * bview)
2193 SetLayout(bview, copylayouttype);
2197 void LyXText::CutSelection(BufferView * bview, bool doclear)
2199 // Stuff what we got on the clipboard. Even if there is no selection.
2201 // There is a problem with having the stuffing here in that the
2202 // larger the selection the slower LyX will get. This can be
2203 // solved by running the line below only when the selection has
2204 // finished. The solution used currently just works, to make it
2205 // faster we need to be more clever and probably also have more
2206 // calls to stuffClipboard. (Lgb)
2207 bview->stuffClipboard(selectionAsString(bview->buffer()));
2209 // This doesn't make sense, if there is no selection
2213 // OK, we have a selection. This is always between sel_start_cursor
2214 // and sel_end cursor
2216 // Check whether there are half footnotes in the selection
2217 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2218 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2219 LyXParagraph * tmppar = sel_start_cursor.par();
2220 while (tmppar != sel_end_cursor.par()){
2221 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2222 WriteAlert(_("Impossible operation"),
2223 _("Don't know what to do with half floats."),
2227 tmppar = tmppar->Next();
2232 /* table stuff -- begin */
2233 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2234 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2235 WriteAlert(_("Impossible operation"),
2236 _("Don't know what to do with half tables."),
2240 sel_start_cursor.par()->table->Reinit();
2242 /* table stuff -- end */
2244 // make sure that the depth behind the selection are restored, too
2246 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2248 LyXParagraph * endpar = sel_end_cursor.par()->Next();
2250 LyXParagraph * undoendpar = endpar;
2252 if (endpar && endpar->GetDepth()) {
2253 while (endpar && endpar->GetDepth()) {
2255 endpar = endpar->LastPhysicalPar()->Next();
2257 endpar = endpar->Next();
2259 undoendpar = endpar;
2261 } else if (endpar) {
2262 endpar = endpar->Next(); // because of parindents etc.
2265 SetUndo(bview->buffer(), Undo::DELETE,
2268 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2270 sel_start_cursor.par()->previous,
2276 // there are two cases: cut only within one paragraph or
2277 // more than one paragraph
2279 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2280 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2282 if (sel_start_cursor.par() == sel_end_cursor.par())
2285 // only within one paragraph
2286 endpar = sel_start_cursor.par();
2287 int pos = sel_end_cursor.pos();
2288 cap.cutSelection(sel_start_cursor.par(), &endpar,
2289 sel_start_cursor.pos(), pos,
2290 bview->buffer()->params.textclass, doclear);
2291 sel_end_cursor.pos(pos);
2293 endpar = sel_end_cursor.par();
2295 int pos = sel_end_cursor.pos();
2296 cap.cutSelection(sel_start_cursor.par(), &endpar,
2297 sel_start_cursor.pos(), pos,
2298 bview->buffer()->params.textclass, doclear);
2300 sel_end_cursor.par(endpar);
2301 sel_end_cursor.pos(pos);
2302 cursor.pos(sel_end_cursor.pos());
2304 endpar = endpar->Next();
2306 // sometimes necessary
2308 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2310 RedoParagraphs(bview, sel_start_cursor, endpar);
2313 cursor = sel_start_cursor;
2314 SetCursor(bview, cursor.par(), cursor.pos());
2315 sel_cursor = cursor;
2316 UpdateCounters(bview, cursor.row());
2320 void LyXText::CopySelection(BufferView * bview)
2322 // Stuff what we got on the clipboard. Even if there is no selection.
2324 // There is a problem with having the stuffing here in that the
2325 // larger the selection the slower LyX will get. This can be
2326 // solved by running the line below only when the selection has
2327 // finished. The solution used currently just works, to make it
2328 // faster we need to be more clever and probably also have more
2329 // calls to stuffClipboard. (Lgb)
2330 bview->stuffClipboard(selectionAsString(bview->buffer()));
2332 // this doesnt make sense, if there is no selection
2336 // ok we have a selection. This is always between sel_start_cursor
2337 // and sel_end cursor
2340 /* check wether there are half footnotes in the selection */
2341 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2342 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2343 LyXParagraph * tmppar = sel_start_cursor.par();
2344 while (tmppar != sel_end_cursor.par()) {
2345 if (tmppar->footnoteflag !=
2346 sel_end_cursor.par()->footnoteflag) {
2347 WriteAlert(_("Impossible operation"),
2348 _("Don't know what to do"
2349 " with half floats."),
2353 tmppar = tmppar->Next();
2358 /* table stuff -- begin */
2359 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2360 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2361 WriteAlert(_("Impossible operation"),
2362 _("Don't know what to do with half tables."),
2367 /* table stuff -- end */
2370 // copy behind a space if there is one
2371 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2372 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2373 && (sel_start_cursor.par() != sel_end_cursor.par()
2374 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2375 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2379 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2380 sel_start_cursor.pos(), sel_end_cursor.pos(),
2381 bview->buffer()->params.textclass);
2385 void LyXText::PasteSelection(BufferView * bview)
2389 // this does not make sense, if there is nothing to paste
2390 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2393 SetUndo(bview->buffer(), Undo::INSERT,
2395 cursor.par()->ParFromPos(cursor.pos())->previous,
2396 cursor.par()->ParFromPos(cursor.pos())->next
2398 cursor.par()->previous,
2403 LyXParagraph * endpar;
2404 LyXParagraph * actpar = cursor.par();
2406 int pos = cursor.pos();
2407 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2409 RedoParagraphs(bview, cursor, endpar);
2411 SetCursor(bview, cursor.par(), cursor.pos());
2414 sel_cursor = cursor;
2415 SetCursor(bview, actpar, pos);
2417 UpdateCounters(bview, cursor.row());
2421 // returns a pointer to the very first LyXParagraph
2422 LyXParagraph * LyXText::FirstParagraph() const
2424 return OwnerParagraph();
2428 // returns true if the specified string is at the specified position
2429 bool LyXText::IsStringInText(LyXParagraph * par,
2430 LyXParagraph::size_type pos,
2431 char const * str) const
2435 while (pos + i < par->Last() && str[i] &&
2436 str[i] == par->GetChar(pos + i)) {
2446 // sets the selection over the number of characters of string, no check!!
2447 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2449 sel_cursor = cursor;
2450 for (int i = 0; string[i]; ++i)
2456 // simple replacing. The font of the first selected character is used
2457 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2459 SetCursorParUndo(bview->buffer());
2462 if (!selection) { // create a dummy selection
2463 sel_end_cursor = cursor;
2464 sel_start_cursor = cursor;
2467 // Get font setting before we cut
2468 LyXParagraph::size_type pos = sel_end_cursor.pos();
2469 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2470 sel_start_cursor.pos());
2472 // Insert the new string
2473 for (int i = 0; str[i]; ++i) {
2474 sel_end_cursor.par()->InsertChar(pos, str[i], font);
2478 // Cut the selection
2479 CutSelection(bview);
2485 // if the string can be found: return true and set the cursor to
2487 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2489 LyXParagraph * par = cursor.par();
2490 LyXParagraph::size_type pos = cursor.pos();
2491 while (par && !IsStringInText(par, pos, str)) {
2492 if (pos < par->Last() - 1)
2500 SetCursor(bview, par, pos);
2508 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2510 LyXParagraph * par = cursor.par();
2511 int pos = cursor.pos();
2517 // We skip empty paragraphs (Asger)
2519 par = par->Previous();
2521 pos = par->Last() - 1;
2522 } while (par && pos < 0);
2524 } while (par && !IsStringInText(par, pos, string));
2527 SetCursor(bview, par, pos);
2534 // needed to insert the selection
2535 void LyXText::InsertStringA(BufferView * bview, string const & str)
2537 LyXParagraph * par = cursor.par();
2538 LyXParagraph::size_type pos = cursor.pos();
2539 LyXParagraph::size_type a = 0;
2540 LyXParagraph * endpar = cursor.par()->Next();
2542 SetCursorParUndo(bview->buffer());
2545 textclasslist.Style(bview->buffer()->params.textclass,
2546 cursor.par()->GetLayout()).isEnvironment();
2547 // only to be sure, should not be neccessary
2550 // insert the string, don't insert doublespace
2551 string::size_type i = 0;
2552 while (i < str.length()) {
2553 if (str[i] != '\n') {
2555 && i + 1 < str.length() && str[i + 1] != ' '
2556 && pos && par->GetChar(pos - 1)!= ' ') {
2557 par->InsertChar(pos, ' ', current_font);
2560 } else if (par->table) {
2561 if (str[i] == '\t') {
2562 while((pos < par->size()) &&
2563 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2565 if (pos < par->size())
2567 else // no more fields to fill skip the rest
2569 } else if ((str[i] != 13) &&
2570 ((str[i] & 127) >= ' ')) {
2571 par->InsertChar(pos, str[i],
2576 } else if (str[i] == ' ') {
2577 InsetSpecialChar * new_inset =
2578 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2579 if (par->InsertInsetAllowed(new_inset)) {
2580 par->InsertInset(pos, new_inset,
2586 } else if (str[i] == '\t') {
2587 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2588 InsetSpecialChar * new_inset =
2589 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2590 if (par->InsertInsetAllowed(new_inset)) {
2591 par->InsertInset(pos, new_inset,
2598 } else if (str[i] != 13 &&
2599 // Ignore unprintables
2600 (str[i] & 127) >= ' ') {
2601 par->InsertChar(pos, str[i], current_font);
2607 if ((i + 1) >= str.length()) {
2608 if (pos < par->size())
2612 while((pos < par->size()) &&
2613 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2616 int cell = NumberOfCell(par, pos);
2617 while((pos < par->size()) &&
2618 !(par->table->IsFirstCell(cell))) {
2620 while((pos < par->size()) &&
2621 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2624 cell = NumberOfCell(par, pos);
2626 if (pos >= par->size())
2627 // no more fields to fill skip the rest
2631 if (!par->size()) { // par is empty
2632 InsetSpecialChar * new_inset =
2633 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2634 if (par->InsertInsetAllowed(new_inset)) {
2635 par->InsertInset(pos,
2643 par->BreakParagraph(bview->buffer()->params, pos, flag);
2653 RedoParagraphs(bview, cursor, endpar);
2654 SetCursor(bview, cursor.par(), cursor.pos());
2655 sel_cursor = cursor;
2656 SetCursor(bview, par, pos);
2661 /* turns double-CR to single CR, others where converted into one blank and 13s
2662 * that are ignored .Double spaces are also converted into one. Spaces at
2663 * the beginning of a paragraph are forbidden. tabs are converted into one
2664 * space. then InsertStringA is called */
2665 void LyXText::InsertStringB(BufferView * bview, string const & s)
2669 LyXParagraph * par = cursor.par();
2671 string::size_type i = 1;
2672 while (i < str.length()) {
2679 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2681 if (str[i] == '\n' && i + 1 < str.length()
2686 if (str[i + 1] != '\n') {
2687 if (str[i - 1] != ' ')
2692 while (i + 1 < str.length()
2693 && (str[i + 1] == ' '
2694 || str[i + 1] == '\t'
2695 || str[i + 1] == '\n'
2696 || str[i + 1] == 13)) {
2703 InsertStringA(bview, str);
2707 bool LyXText::GotoNextError(BufferView * bview) const
2709 LyXCursor res = cursor;
2711 if (res.pos() < res.par()->Last() - 1) {
2712 res.pos(res.pos() + 1);
2714 res.par(res.par()->Next());
2718 } while (res.par() &&
2719 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2720 && res.par()->GetInset(res.pos())->AutoDelete()));
2723 SetCursor(bview, res.par(), res.pos());
2730 bool LyXText::GotoNextNote(BufferView * bview) const
2732 LyXCursor res = cursor;
2734 if (res.pos() < res.par()->Last() - 1) {
2735 res.pos(res.pos() + 1);
2737 res.par(res.par()->Next());
2741 } while (res.par() &&
2742 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2743 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2746 SetCursor(bview, res.par(), res.pos());
2753 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2754 LyXParagraph::size_type pos)
2756 LyXCursor tmpcursor;
2759 /* table stuff -- begin*/
2762 CheckParagraphInTable(bview, par, pos);
2766 /* table stuff -- end*/
2769 LyXParagraph::size_type z;
2770 Row * row = GetRow(par, pos, y);
2772 // is there a break one row above
2773 if (row->previous() && row->previous()->par() == row->par()) {
2774 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2775 if ( z >= row->pos()) {
2776 // set the dimensions of the row above
2777 y -= row->previous()->height();
2779 refresh_row = row->previous();
2780 status = LyXText::NEED_MORE_REFRESH;
2782 BreakAgain(bview, row->previous());
2784 // set the cursor again. Otherwise
2785 // dangling pointers are possible
2786 SetCursor(bview, cursor.par(), cursor.pos());
2787 sel_cursor = cursor;
2792 int tmpheight = row->height();
2793 LyXParagraph::size_type tmplast = RowLast(row);
2797 BreakAgain(bview, row);
2798 if (row->height() == tmpheight && RowLast(row) == tmplast)
2799 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2801 status = LyXText::NEED_MORE_REFRESH;
2803 // check the special right address boxes
2804 if (textclasslist.Style(bview->buffer()->params.textclass,
2805 par->GetLayout()).margintype
2806 == MARGIN_RIGHT_ADDRESS_BOX) {
2813 RedoDrawingOfParagraph(bview, tmpcursor);
2819 // set the cursor again. Otherwise dangling pointers are possible
2820 // also set the selection
2824 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2825 sel_cursor = cursor;
2826 SetCursorIntern(bview, sel_start_cursor.par(),
2827 sel_start_cursor.pos());
2828 sel_start_cursor = cursor;
2829 SetCursorIntern(bview, sel_end_cursor.par(),
2830 sel_end_cursor.pos());
2831 sel_end_cursor = cursor;
2832 SetCursorIntern(bview, last_sel_cursor.par(),
2833 last_sel_cursor.pos());
2834 last_sel_cursor = cursor;
2837 SetCursorIntern(bview, cursor.par(), cursor.pos());
2841 // returns false if inset wasn't found
2842 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2844 // first check the current paragraph
2845 int pos = cursor.par()->GetPositionOfInset(inset);
2847 CheckParagraph(bview, cursor.par(), pos);
2851 // check every paragraph
2853 LyXParagraph * par = FirstParagraph();
2856 // make sure the paragraph is open
2857 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2859 pos = par->GetPositionOfInset(inset);
2861 CheckParagraph(bview, par, pos);
2874 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2875 LyXParagraph::size_type pos,
2876 bool setfont, bool boundary) const
2878 LyXCursor old_cursor = cursor;
2879 SetCursorIntern(bview, par, pos, setfont, boundary);
2880 DeleteEmptyParagraphMechanism(bview, old_cursor);
2884 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2885 LyXParagraph::size_type pos, bool boundary) const
2888 // correct the cursor position if impossible
2889 if (pos > par->Last()){
2890 LyXParagraph * tmppar = par->ParFromPos(pos);
2891 pos = par->PositionInParFromPos(pos);
2894 if (par->IsDummy() && par->previous &&
2895 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2896 while (par->previous &&
2897 ((par->previous->IsDummy() &&
2898 (par->previous->previous->footnoteflag ==
2899 LyXParagraph::CLOSED_FOOTNOTE)) ||
2900 (par->previous->footnoteflag ==
2901 LyXParagraph::CLOSED_FOOTNOTE))) {
2902 par = par->previous ;
2903 if (par->IsDummy() &&
2904 (par->previous->footnoteflag ==
2905 LyXParagraph::CLOSED_FOOTNOTE))
2906 pos += par->size() + 1;
2908 if (par->previous) {
2909 par = par->previous;
2911 pos += par->size() + 1;
2916 cur.boundary(boundary);
2918 /* get the cursor y position in text */
2920 Row * row = GetRow(par, pos, y);
2921 /* y is now the beginning of the cursor row */
2922 y += row->baseline();
2923 /* y is now the cursor baseline */
2926 /* now get the cursors x position */
2928 float fill_separator, fill_hfill, fill_label_hfill;
2929 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2931 LyXParagraph::size_type cursor_vpos = 0;
2932 LyXParagraph::size_type last = RowLastPrintable(row);
2934 if (pos > last + 1) // This shouldn't happen.
2936 else if (pos < row->pos())
2939 if (last < row->pos())
2940 cursor_vpos = row->pos();
2941 else if (pos > last && !boundary)
2942 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2943 ? row->pos() : last + 1;
2944 else if (pos > row->pos() &&
2945 (pos > last || boundary
2947 || (row->par()->table && row->par()->IsNewline(pos))
2950 /// Place cursor after char at (logical) position pos - 1
2951 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2952 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2954 /// Place cursor before char at (logical) position pos
2955 cursor_vpos = (bidi_level(pos) % 2 == 0)
2956 ? log2vis(pos) : log2vis(pos) + 1;
2959 /* table stuff -- begin*/
2960 if (row->par()->table) {
2961 int cell = NumberOfCell(row->par(), row->pos());
2963 x += row->par()->table->GetBeginningOfTextInCell(cell);
2964 for (LyXParagraph::size_type vpos = row->pos();
2965 vpos < cursor_vpos; ++vpos) {
2966 pos = vis2log(vpos);
2967 if (row->par()->IsNewline(pos)) {
2968 x = x_old + row->par()->table->WidthOfColumn(cell);
2971 x += row->par()->table->GetBeginningOfTextInCell(cell);
2973 x += SingleWidth(bview, row->par(), pos);
2977 /* table stuff -- end*/
2979 LyXParagraph::size_type main_body =
2980 BeginningOfMainBody(bview->buffer(), row->par());
2981 if ((main_body > 0) &&
2982 ((main_body-1 > last) ||
2983 !row->par()->IsLineSeparator(main_body-1)))
2986 for (LyXParagraph::size_type vpos = row->pos();
2987 vpos < cursor_vpos; ++vpos) {
2988 pos = vis2log(vpos);
2989 if (main_body > 0 && pos == main_body-1) {
2990 x += fill_label_hfill +
2991 lyxfont::width(textclasslist.Style(
2992 bview->buffer()->params.textclass,
2993 row->par()->GetLayout())
2995 GetFont(bview->buffer(), row->par(), -2));
2996 if (row->par()->IsLineSeparator(main_body-1))
2997 x -= SingleWidth(bview, row->par(),main_body-1);
2999 if (HfillExpansion(bview->buffer(), row, pos)) {
3000 x += SingleWidth(bview, row->par(), pos);
3001 if (pos >= main_body)
3004 x += fill_label_hfill;
3005 } else if (row->par()->IsSeparator(pos)) {
3006 x += SingleWidth(bview, row->par(), pos);
3007 if (pos >= main_body)
3008 x += fill_separator;
3010 x += SingleWidth(bview, row->par(), pos);
3022 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
3023 LyXParagraph::size_type pos,
3024 bool setfont, bool boundary) const
3026 SetCursor(bview, cursor, par, pos, boundary);
3028 SetCurrentFont(bview);
3031 void LyXText::SetCurrentFont(BufferView * bview) const
3033 LyXParagraph::size_type pos = cursor.pos();
3034 if (cursor.boundary() && pos > 0)
3038 if (pos == cursor.par()->Last()
3040 || (cursor.par()->table && cursor.par()->IsNewline(pos))
3044 else if (cursor.par()->IsSeparator(pos)) {
3045 if (pos > cursor.row()->pos() &&
3046 bidi_level(pos) % 2 ==
3047 bidi_level(pos - 1) % 2)
3049 else if (pos + 1 < cursor.par()->Last())
3055 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
3056 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
3058 if (cursor.pos() == cursor.par()->Last() &&
3059 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
3060 !cursor.boundary()) {
3061 Language const * lang =
3062 cursor.par()->getParLanguage(bview->buffer()->params);
3063 current_font.setLanguage(lang);
3064 real_current_font.setLanguage(lang);
3069 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
3071 LyXCursor old_cursor = cursor;
3073 /* get the row first */
3075 Row * row = GetRowNearY(y);
3076 cursor.par(row->par());
3079 int column = GetColumnNearX(bview, row, x, bound);
3080 cursor.pos(row->pos() + column);
3082 cursor.y(y + row->baseline());
3084 cursor.boundary(bound);
3085 SetCurrentFont(bview);
3086 DeleteEmptyParagraphMechanism(bview, old_cursor);
3090 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
3091 int x, long y) const
3093 /* get the row first */
3095 Row * row = GetRowNearY(y);
3097 int column = GetColumnNearX(bview, row, x, bound);
3099 cur.par(row->par());
3100 cur.pos(row->pos() + column);
3102 cur.y(y + row->baseline());
3104 cur.boundary(bound);
3108 void LyXText::CursorLeft(BufferView * bview, bool internal) const
3110 CursorLeftIntern(bview, internal);
3112 if (cursor.par()->table) {
3113 int cell = NumberOfCell(cursor.par(), cursor.pos());
3114 if (cursor.par()->table->IsContRow(cell)
3115 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3123 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
3125 if (cursor.pos() > 0) {
3126 bool boundary = cursor.boundary();
3127 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
3128 if (!internal && !boundary &&
3129 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
3130 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
3131 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3132 LyXParagraph * par = cursor.par()->Previous();
3133 SetCursor(bview, par, par->Last());
3138 void LyXText::CursorRight(BufferView * bview, bool internal) const
3140 CursorRightIntern(bview, internal);
3142 if (cursor.par()->table) {
3143 int cell = NumberOfCell(cursor.par(), cursor.pos());
3144 if (cursor.par()->table->IsContRow(cell) &&
3145 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3153 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3155 if (!internal && cursor.boundary() &&
3158 !cursor.par()->table ||
3160 !cursor.par()->IsNewline(cursor.pos())))
3161 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3162 else if (cursor.pos() < cursor.par()->Last()) {
3163 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3165 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3166 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3167 } else if (cursor.par()->Next())
3168 SetCursor(bview, cursor.par()->Next(), 0);
3172 void LyXText::CursorUp(BufferView * bview) const
3174 SetCursorFromCoordinates(bview, cursor.x_fix(),
3175 cursor.y() - cursor.row()->baseline() - 1);
3177 if (cursor.par()->table) {
3178 int cell = NumberOfCell(cursor.par(), cursor.pos());
3179 if (cursor.par()->table->IsContRow(cell) &&
3180 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3188 void LyXText::CursorDown(BufferView * bview) const
3191 if (cursor.par()->table &&
3192 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3193 !cursor.par()->next)
3197 SetCursorFromCoordinates(bview, cursor.x_fix(),
3198 cursor.y() - cursor.row()->baseline()
3199 + cursor.row()->height() + 1);
3201 if (cursor.par()->table) {
3202 int cell = NumberOfCell(cursor.par(), cursor.pos());
3203 int cell_above = cursor.par()->table->GetCellAbove(cell);
3204 while(cursor.par()->table &&
3205 cursor.par()->table->IsContRow(cell) &&
3206 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3207 SetCursorFromCoordinates(bview, cursor.x_fix(),
3208 cursor.y() - cursor.row()->baseline()
3209 + cursor.row()->height() + 1);
3210 if (cursor.par()->table) {
3211 cell = NumberOfCell(cursor.par(), cursor.pos());
3212 cell_above = cursor.par()->table->GetCellAbove(cell);
3220 void LyXText::CursorUpParagraph(BufferView * bview) const
3222 if (cursor.pos() > 0) {
3223 SetCursor(bview, cursor.par(), 0);
3225 else if (cursor.par()->Previous()) {
3226 SetCursor(bview, cursor.par()->Previous(), 0);
3231 void LyXText::CursorDownParagraph(BufferView * bview) const
3233 if (cursor.par()->Next()) {
3234 SetCursor(bview, cursor.par()->Next(), 0);
3236 SetCursor(bview, cursor.par(), cursor.par()->Last());
3241 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3242 LyXCursor const & old_cursor) const
3244 // Would be wrong to delete anything if we have a selection.
3245 if (selection) return;
3247 // We allow all kinds of "mumbo-jumbo" when freespacing.
3248 if (textclasslist.Style(bview->buffer()->params.textclass,
3249 old_cursor.par()->GetLayout()).free_spacing)
3252 bool deleted = false;
3254 /* Ok I'll put some comments here about what is missing.
3255 I have fixed BackSpace (and thus Delete) to not delete
3256 double-spaces automagically. I have also changed Cut,
3257 Copy and Paste to hopefully do some sensible things.
3258 There are still some small problems that can lead to
3259 double spaces stored in the document file or space at
3260 the beginning of paragraphs. This happens if you have
3261 the cursor betwenn to spaces and then save. Or if you
3262 cut and paste and the selection have a space at the
3263 beginning and then save right after the paste. I am
3264 sure none of these are very hard to fix, but I will
3265 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3266 that I can get some feedback. (Lgb)
3269 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3270 // delete the LineSeparator.
3273 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3274 // delete the LineSeparator.
3277 // If the pos around the old_cursor were spaces, delete one of them.
3278 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3279 // Only if the cursor has really moved
3281 if (old_cursor.pos() > 0
3282 && old_cursor.pos() < old_cursor.par()->Last()
3283 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3284 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3285 old_cursor.par()->Erase(old_cursor.pos() - 1);
3286 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3288 if (old_cursor.par() == cursor.par() &&
3289 cursor.pos() > old_cursor.pos()) {
3290 SetCursorIntern(bview, cursor.par(),
3293 SetCursorIntern(bview, cursor.par(),
3299 // Do not delete empty paragraphs with keepempty set.
3300 if ((textclasslist.Style(bview->buffer()->params.textclass,
3301 old_cursor.par()->GetLayout())).keepempty)
3304 LyXCursor tmpcursor;
3306 if (old_cursor.par() != cursor.par()) {
3307 if ( (old_cursor.par()->Last() == 0
3308 || (old_cursor.par()->Last() == 1
3309 && old_cursor.par()->IsLineSeparator(0)))
3311 && old_cursor.par()->FirstPhysicalPar()
3312 == old_cursor.par()->LastPhysicalPar()
3315 // ok, we will delete anything
3317 // make sure that you do not delete any environments
3320 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3321 !(old_cursor.row()->previous()
3322 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3323 && !(old_cursor.row()->next()
3324 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3325 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3326 && ((old_cursor.row()->previous()
3327 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3328 || (old_cursor.row()->next()
3329 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3332 status = LyXText::NEED_MORE_REFRESH;
3335 if (old_cursor.row()->previous()) {
3336 refresh_row = old_cursor.row()->previous();
3337 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3339 cursor = old_cursor; // that undo can restore the right cursor position
3340 LyXParagraph * endpar = old_cursor.par()->next;
3341 if (endpar && endpar->GetDepth()) {
3342 while (endpar && endpar->GetDepth()) {
3344 endpar = endpar->LastPhysicalPar()->Next();
3346 endpar = endpar->Next();
3350 SetUndo(bview->buffer(), Undo::DELETE,
3351 old_cursor.par()->previous,
3356 RemoveRow(old_cursor.row());
3357 if (OwnerParagraph() == old_cursor.par()) {
3358 OwnerParagraph(OwnerParagraph()->next);
3361 delete old_cursor.par();
3363 /* Breakagain the next par. Needed
3364 * because of the parindent that
3365 * can occur or dissappear. The
3366 * next row can change its height,
3367 * if there is another layout before */
3368 if (refresh_row->next()) {
3369 BreakAgain(bview, refresh_row->next());
3370 UpdateCounters(bview, refresh_row);
3372 SetHeightOfRow(bview, refresh_row);
3374 refresh_row = old_cursor.row()->next();
3375 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3378 cursor = old_cursor; // that undo can restore the right cursor position
3379 LyXParagraph * endpar = old_cursor.par()->next;
3380 if (endpar && endpar->GetDepth()) {
3381 while (endpar && endpar->GetDepth()) {
3383 endpar = endpar->LastPhysicalPar()->Next();
3385 endpar = endpar->Next();
3389 SetUndo(bview->buffer(), Undo::DELETE,
3390 old_cursor.par()->previous,
3395 RemoveRow(old_cursor.row());
3397 if (OwnerParagraph() == old_cursor.par()) {
3398 OwnerParagraph(OwnerParagraph()->next);
3400 delete old_cursor.par();
3402 /* Breakagain the next par. Needed
3403 because of the parindent that can
3404 occur or dissappear.
3405 The next row can change its height,
3406 if there is another layout before
3409 BreakAgain(bview, refresh_row);
3410 UpdateCounters(bview, refresh_row->previous());
3416 SetCursorIntern(bview, cursor.par(), cursor.pos());
3418 if (sel_cursor.par() == old_cursor.par()
3419 && sel_cursor.pos() == sel_cursor.pos()) {
3420 // correct selection
3421 sel_cursor = cursor;
3428 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3429 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3431 SetCursorIntern(bview, cursor.par(), cursor.pos());
3432 sel_cursor = cursor;
3439 LyXParagraph * LyXText::GetParFromID(int id)
3441 LyXParagraph * result = FirstParagraph();
3442 while (result && result->id() != id)
3443 result = result->next;
3449 bool LyXText::TextUndo(BufferView * bview)
3453 // returns false if no undo possible
3454 Undo * undo = bview->buffer()->undostack.pop();
3458 bview->buffer()->redostack
3459 .push(CreateUndo(bview->buffer(), undo->kind,
3460 GetParFromID(undo->number_of_before_par),
3461 GetParFromID(undo->number_of_behind_par)));
3463 return TextHandleUndo(bview, undo);
3467 bool LyXText::TextRedo(BufferView * bview)
3471 // returns false if no redo possible
3472 Undo * undo = bview->buffer()->redostack.pop();
3476 bview->buffer()->undostack
3477 .push(CreateUndo(bview->buffer(), undo->kind,
3478 GetParFromID(undo->number_of_before_par),
3479 GetParFromID(undo->number_of_behind_par)));
3481 return TextHandleUndo(bview, undo);
3485 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3489 // returns false if no undo possible
3490 bool result = false;
3492 LyXParagraph * before =
3493 GetParFromID(undo->number_of_before_par);
3494 LyXParagraph * behind =
3495 GetParFromID(undo->number_of_behind_par);
3496 LyXParagraph * tmppar;
3497 LyXParagraph * tmppar2;
3498 LyXParagraph * endpar;
3499 LyXParagraph * tmppar5;
3501 // if there's no before take the beginning
3502 // of the document for redoing
3504 SetCursorIntern(bview, FirstParagraph(), 0);
3506 // replace the paragraphs with the undo informations
3508 LyXParagraph * tmppar3 = undo->par;
3509 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3510 LyXParagraph * tmppar4 = tmppar3;
3512 while (tmppar4->next)
3513 tmppar4 = tmppar4->next;
3514 } // get last undo par
3516 // now remove the old text if there is any
3517 if (before != behind || (!behind && !before)){
3519 tmppar5 = before->next;
3521 tmppar5 = OwnerParagraph();
3523 while (tmppar5 && tmppar5 != behind){
3525 tmppar5 = tmppar5->next;
3526 // a memory optimization for edit: Only layout information
3527 // is stored in the undo. So restore the text informations.
3528 if (undo->kind == Undo::EDIT) {
3529 tmppar2->setContentsFromPar(tmppar);
3530 tmppar->clearContents();
3531 tmppar2 = tmppar2->next;
3536 // put the new stuff in the list if there is one
3539 before->next = tmppar3;
3541 OwnerParagraph(tmppar3);
3542 tmppar3->previous = before;
3545 OwnerParagraph(behind);
3548 tmppar4->next = behind;
3550 behind->previous = tmppar4;
3554 // Set the cursor for redoing
3557 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3559 SetCursorIntern(bview, before, 0);
3562 // check wether before points to a closed float and open it if necessary
3563 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3564 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3566 while (tmppar4->previous &&
3567 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3568 tmppar4 = tmppar4->previous;
3569 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3570 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3571 tmppar4 = tmppar4->next;
3578 // open a cosed footnote at the end if necessary
3579 if (behind && behind->previous &&
3580 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3581 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3582 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3583 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3584 behind = behind->next;
3589 // calculate the endpar for redoing the paragraphs.
3592 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3593 endpar = behind->LastPhysicalPar()->Next();
3595 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3597 endpar = behind->Next();
3602 tmppar = GetParFromID(undo->number_of_cursor_par);
3603 RedoParagraphs(bview, cursor, endpar);
3605 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3606 UpdateCounters(bview, cursor.row());
3616 void LyXText::FinishUndo()
3620 // makes sure the next operation will be stored
3621 undo_finished = true;
3625 void LyXText::FreezeUndo()
3629 // this is dangerous and for internal use only
3634 void LyXText::UnFreezeUndo()
3638 // this is dangerous and for internal use only
3639 undo_frozen = false;
3643 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3644 LyXParagraph const * before,
3645 LyXParagraph const * behind) const
3650 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3651 buf->redostack.clear();
3655 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3656 LyXParagraph const * before, LyXParagraph const * behind)
3660 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3664 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3665 LyXParagraph const * before,
3666 LyXParagraph const * behind) const
3671 int before_number = -1;
3672 int behind_number = -1;
3674 before_number = before->id();
3676 behind_number = behind->id();
3677 // Undo::EDIT and Undo::FINISH are
3678 // always finished. (no overlapping there)
3679 // overlapping only with insert and delete inside one paragraph:
3680 // Nobody wants all removed character
3681 // appear one by one when undoing.
3682 // EDIT is special since only layout information, not the
3683 // contents of a paragaph are stored.
3684 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3685 // check wether storing is needed
3686 if (!buf->undostack.empty() &&
3687 buf->undostack.top()->kind == kind &&
3688 buf->undostack.top()->number_of_before_par == before_number &&
3689 buf->undostack.top()->number_of_behind_par == behind_number ){
3694 // create a new Undo
3695 LyXParagraph * undopar;
3696 LyXParagraph * tmppar;
3697 LyXParagraph * tmppar2;
3699 LyXParagraph * start = 0;
3700 LyXParagraph * end = 0;
3703 start = before->next;
3705 start = FirstParagraph();
3707 end = behind->previous;
3709 end = FirstParagraph();
3715 && start != end->next
3716 && (before != behind || (!before && !behind))) {
3718 tmppar2 = tmppar->Clone();
3719 tmppar2->id(tmppar->id());
3721 // a memory optimization: Just store the layout information
3723 if (kind == Undo::EDIT){
3724 //tmppar2->text.clear();
3725 tmppar2->clearContents();
3730 while (tmppar != end && tmppar->next) {
3731 tmppar = tmppar->next;
3732 tmppar2->next = tmppar->Clone();
3733 tmppar2->next->id(tmppar->id());
3734 // a memory optimization: Just store the layout
3735 // information when only edit
3736 if (kind == Undo::EDIT){
3737 //tmppar2->next->text.clear();
3738 tmppar2->clearContents();
3740 tmppar2->next->previous = tmppar2;
3741 tmppar2 = tmppar2->next;
3745 undopar = 0; // nothing to replace (undo of delete maybe)
3748 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3749 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3751 int cursor_par = cursor.par()->id();
3752 int cursor_pos = cursor.pos();
3755 Undo * undo = new Undo(kind,
3756 before_number, behind_number,
3757 cursor_par, cursor_pos,
3760 undo_finished = false;
3765 void LyXText::SetCursorParUndo(Buffer * buf)
3769 SetUndo(buf, Undo::FINISH,
3771 cursor.par()->ParFromPos(cursor.pos())->previous,
3772 cursor.par()->ParFromPos(cursor.pos())->next
3774 cursor.par()->previous,
3782 void LyXText::RemoveTableRow(LyXCursor & cur) const
3788 // move to the previous row
3789 int cell_act = NumberOfCell(cur.par(), cur.pos());
3792 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3793 cur.pos(cur.pos() - 1);
3795 !cur.par()->table->IsFirstCell(cell_act)) {
3796 cur.pos(cur.pos() - 1);
3797 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3798 cur.pos(cur.pos() - 1);
3802 // now we have to pay attention if the actual table is the
3803 // main row of TableContRows and if yes to delete all of them
3808 // delete up to the next row
3809 while (cur.pos() < cur.par()->Last() &&
3811 || !cur.par()->table->IsFirstCell(cell_act))) {
3812 while (cur.pos() < cur.par()->Last() &&
3813 !cur.par()->IsNewline(cur.pos()))
3814 cur.par()->Erase(cur.pos());
3817 if (cur.pos() < cur.par()->Last())
3818 cur.par()->Erase(cur.pos());
3820 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3821 cur.pos(cur.pos() - 1);
3822 cur.par()->Erase(cur.pos()); // no newline at very end!
3824 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3825 !cur.par()->table->IsContRow(cell_org) &&
3826 cur.par()->table->IsContRow(cell));
3827 cur.par()->table->DeleteRow(cell_org);
3834 bool LyXText::IsEmptyTableCell() const
3836 LyXParagraph::size_type pos = cursor.pos() - 1;
3837 while (pos >= 0 && pos < cursor.par()->Last()
3838 && !cursor.par()->IsNewline(pos))
3840 return cursor.par()->IsNewline(pos + 1);
3845 void LyXText::toggleAppendix(BufferView * bview)
3848 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3850 LyXParagraph * par = cursor.par();
3852 bool start = !par->start_of_appendix;
3854 // ensure that we have only one start_of_appendix in this document
3855 LyXParagraph * tmp = FirstParagraph();
3856 for (; tmp; tmp = tmp->next)
3857 tmp->start_of_appendix = 0;
3858 par->start_of_appendix = start;
3860 // we can set the refreshing parameters now
3861 status = LyXText::NEED_MORE_REFRESH;
3863 refresh_row = 0; // not needed for full update
3864 UpdateCounters(bview, 0);
3865 SetCursor(bview, cursor.par(), cursor.pos());
3869 LyXParagraph * LyXText::OwnerParagraph() const
3872 return inset_owner->par;
3874 return bv_owner->buffer()->paragraph;
3878 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3881 inset_owner->par = p;
3883 bv_owner->buffer()->paragraph = p;