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)
70 the_locking_inset = 0;
78 status = LyXText::UNCHANGED;
79 // set cursor at the very top position
80 selection = true; /* these setting is necessary
81 because of the delete-empty-
82 paragraph mechanism in
85 LyXParagraph * par = OwnerParagraph();
86 current_font = GetFont(bv_owner->buffer(), par, 0);
88 InsertParagraph(bv_owner, par, lastrow);
91 SetCursor(bv_owner, firstrow->par(), 0);
93 current_font = LyXFont(LyXFont::ALL_SANE);
99 // no rebreak necessary
102 undo_finished = true;
105 // Default layouttype for copy environment type
109 // Dump all rowinformation:
110 Row * tmprow = firstrow;
111 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
113 lyxerr << tmprow->baseline() << '\t'
114 << tmprow->par << '\t'
115 << tmprow->pos() << '\t'
116 << tmprow->height << '\t'
117 << tmprow->ascent_of_text << '\t'
118 << tmprow->fill << '\n';
119 tmprow = tmprow->next();
126 void LyXText::init(BufferView * bview)
131 LyXParagraph * par = OwnerParagraph();
132 current_font = GetFont(bview->buffer(), par, 0);
134 InsertParagraph(bview, par, lastrow);
137 SetCursorIntern(bview, firstrow->par(), 0);
140 // Dump all rowinformation:
141 Row * tmprow = firstrow;
142 lyxerr << "Width = " << width << endl;
143 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
145 lyxerr << tmprow->baseline() << '\t'
146 << tmprow->par() << '\t'
147 << tmprow->pos() << '\t'
148 << tmprow->height() << '\t'
149 << tmprow->ascent_of_text() << '\t'
150 << tmprow->fill() << '\n';
151 tmprow = tmprow->next();
159 // Delete all rows, this does not touch the paragraphs!
160 Row * tmprow = firstrow;
162 tmprow = firstrow->next();
169 // Gets the fully instantiated font at a given position in a paragraph
170 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
171 // The difference is that this one is used for displaying, and thus we
172 // are allowed to make cosmetic improvements. For instance make footnotes
174 // If position is -1, we get the layout font of the paragraph.
175 // If position is -2, we get the font of the manual label of the paragraph.
176 LyXFont const LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
177 LyXParagraph::size_type pos) const
179 LyXLayout const & layout =
180 textclasslist.Style(buf->params.textclass, par->GetLayout());
182 char par_depth = par->GetDepth();
183 // We specialize the 95% common case:
186 par->footnoteflag == LyXParagraph::NO_FOOTNOTE &&
191 if (layout.labeltype == LABEL_MANUAL
192 && pos < BeginningOfMainBody(buf, par)) {
194 LyXFont f = par->GetFontSettings(buf->params,
196 return f.realize(layout.reslabelfont);
198 LyXFont f = par->GetFontSettings(buf->params, pos);
199 return f.realize(layout.resfont);
204 // process layoutfont for pos == -1 and labelfont for pos < -1
206 return layout.resfont;
208 return layout.reslabelfont;
212 // The uncommon case need not be optimized as much
214 LyXFont layoutfont, tmpfont;
218 if (pos < BeginningOfMainBody(buf, par)) {
220 layoutfont = layout.labelfont;
223 layoutfont = layout.font;
225 tmpfont = par->GetFontSettings(buf->params, pos);
226 tmpfont.realize(layoutfont);
229 // process layoutfont for pos == -1 and labelfont for pos < -1
231 tmpfont = layout.font;
233 tmpfont = layout.labelfont;
236 // Resolve against environment font information
237 while (par && par_depth && !tmpfont.resolved()) {
238 par = par->DepthHook(par_depth - 1);
240 tmpfont.realize(textclasslist.
241 Style(buf->params.textclass,
242 par->GetLayout()).font);
243 par_depth = par->GetDepth();
247 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
250 // Cosmetic improvement: If this is an open footnote, make the font
252 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
253 && par->footnotekind == LyXParagraph::FOOTNOTE) {
261 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
262 LyXParagraph::size_type pos,
266 // Let the insets convert their font
267 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
268 if (par->GetInset(pos))
269 font = par->GetInset(pos)->ConvertFont(font);
272 LyXLayout const & layout =
273 textclasslist.Style(buf->params.textclass,
276 // Get concrete layout font to reduce against
279 if (pos < BeginningOfMainBody(buf, par))
280 layoutfont = layout.labelfont;
282 layoutfont = layout.font;
284 // Realize against environment font information
285 if (par->GetDepth()){
286 LyXParagraph * tp = par;
287 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
288 tp = tp->DepthHook(tp->GetDepth()-1);
290 layoutfont.realize(textclasslist.
291 Style(buf->params.textclass,
292 tp->GetLayout()).font);
296 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
299 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
300 && par->footnotekind == LyXParagraph::FOOTNOTE) {
301 layoutfont.decSize();
304 // Now, reduce font against full layout font
305 font.reduce(layoutfont);
307 par->SetFont(pos, font);
311 /* inserts a new row behind the specified row, increments
312 * the touched counters */
313 void LyXText::InsertRow(Row * row, LyXParagraph * par,
314 LyXParagraph::size_type pos) const
316 Row * tmprow = new Row;
319 tmprow->next(firstrow);
322 tmprow->previous(row);
323 tmprow->next(row->next());
328 tmprow->next()->previous(tmprow);
330 if (tmprow->previous())
331 tmprow->previous()->next(tmprow);
339 ++number_of_rows; // one more row
343 // removes the row and reset the touched counters
344 void LyXText::RemoveRow(Row * row) const
346 /* this must not happen before the currentrow for clear reasons.
347 so the trick is just to set the current row onto the previous
350 GetRow(row->par(), row->pos(), unused_y);
353 row->next()->previous(row->previous());
354 if (!row->previous()) {
355 firstrow = row->next();
357 row->previous()->next(row->next());
360 lastrow = row->previous();
362 height -= row->height(); // the text becomes smaller
365 --number_of_rows; // one row less
369 // remove all following rows of the paragraph of the specified row.
370 void LyXText::RemoveParagraph(Row * row) const
372 LyXParagraph * tmppar = row->par();
376 while (row && row->par() == tmppar) {
377 tmprow = row->next();
384 // insert the specified paragraph behind the specified row
385 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
388 InsertRow(row, par, 0); /* insert a new row, starting
391 SetCounter(bview->buffer(), par); // set the counters
393 // and now append the whole paragraph behind the new row
396 AppendParagraph(bview, firstrow);
398 row->next()->height(0);
399 AppendParagraph(bview, row->next());
405 void LyXText::ToggleFootnote(BufferView * bview)
407 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
409 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
411 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
413 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
414 CloseFootnote(bview);
421 void LyXText::OpenStuff(BufferView * bview)
423 if (cursor.pos() == 0 && cursor.par()->bibkey){
424 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
425 } else if (cursor.pos() < cursor.par()->Last()
426 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
427 && cursor.par()->GetInset(cursor.pos())->Editable()) {
428 bview->owner()->getMiniBuffer()
429 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
430 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
431 SetCursorParUndo(bview->buffer());
432 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
436 ToggleFootnote(bview);
444 void LyXText::CloseFootnote(BufferView * bview)
446 LyXParagraph * tmppar;
447 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
449 // if the cursor is not in an open footnote, or
450 // there is no open footnote in this paragraph, just return.
451 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
454 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
455 bview->owner()->getMiniBuffer()
456 ->Set(_("Nothing to do"));
460 // ok, move the cursor right before the footnote
461 // just a little faster than using CursorRight()
463 cursor.par()->ParFromPos(cursor.pos()) != par;) {
464 cursor.pos(cursor.pos() + 1);
467 // now the cursor is at the beginning of the physical par
468 SetCursor(bview, cursor.par(),
470 cursor.par()->ParFromPos(cursor.pos())->size());
472 /* we are in a footnote, so let us move at the beginning */
473 /* this is just faster than using just CursorLeft() */
475 tmppar = cursor.par();
476 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
477 // just a little bit faster than movin the cursor
478 tmppar = tmppar->Previous();
480 SetCursor(bview, tmppar, tmppar->Last());
483 // the cursor must be exactly before the footnote
484 par = cursor.par()->ParFromPos(cursor.pos());
486 status = LyXText::NEED_MORE_REFRESH;
487 refresh_row = cursor.row();
488 refresh_y = cursor.y() - cursor.row()->baseline();
490 tmppar = cursor.par();
491 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
492 Row * row = cursor.row();
494 tmppar->CloseFootnote(cursor.pos());
496 while (tmppar != endpar) {
497 RemoveRow(row->next());
499 tmppar = row->next()->par();
504 AppendParagraph(bview, cursor.row());
506 SetCursor(bview, cursor.par(), cursor.pos());
510 if (cursor.row()->next())
511 SetHeightOfRow(bview, cursor.row()->next());
516 /* used in setlayout */
517 // Asger is not sure we want to do this...
518 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
522 LyXLayout const & layout =
523 textclasslist.Style(buf->params.textclass, par->GetLayout());
525 LyXFont layoutfont, tmpfont;
526 for (LyXParagraph::size_type pos = 0;
527 pos < par->Last(); ++pos) {
528 if (pos < BeginningOfMainBody(buf, par))
529 layoutfont = layout.labelfont;
531 layoutfont = layout.font;
533 tmpfont = par->GetFontSettings(buf->params, pos);
534 tmpfont.reduce(layoutfont);
535 par->SetFont(pos, tmpfont);
540 LyXParagraph * LyXText::SetLayout(BufferView * bview,
541 LyXCursor & cur, LyXCursor & sstart_cur,
542 LyXCursor & send_cur,
543 LyXTextClass::size_type layout)
546 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
548 LyXParagraph * endpar = send_cur.par()->Next();
550 LyXParagraph * undoendpar = endpar;
552 if (endpar && endpar->GetDepth()) {
553 while (endpar && endpar->GetDepth()) {
555 endpar = endpar->LastPhysicalPar()->Next();
557 endpar = endpar->Next();
562 endpar = endpar->Next(); // because of parindents etc.
565 SetUndo(bview->buffer(), Undo::EDIT,
567 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
569 sstart_cur.par()->previous,
573 /* ok we have a selection. This is always between sstart_cur
574 * and sel_end cursor */
577 LyXLayout const & lyxlayout =
578 textclasslist.Style(bview->buffer()->params.textclass, layout);
580 while (cur.par() != send_cur.par()) {
582 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
584 cur.par()->SetLayout(bview->buffer()->params, layout);
585 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
587 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
589 LyXParagraph * fppar = cur.par();
591 fppar->added_space_top = lyxlayout.fill_top ?
592 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
593 fppar->added_space_bottom = lyxlayout.fill_bottom ?
594 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
595 if (lyxlayout.margintype == MARGIN_MANUAL)
596 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
597 if (lyxlayout.labeltype != LABEL_BIBLIO
599 delete fppar->bibkey;
605 cur.par(cur.par()->Next());
608 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
610 cur.par()->SetLayout(bview->buffer()->params, layout);
611 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
613 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
615 LyXParagraph * fppar = cur.par();
617 fppar->added_space_top = lyxlayout.fill_top ?
618 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
619 fppar->added_space_bottom = lyxlayout.fill_bottom ?
620 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
621 if (lyxlayout.margintype == MARGIN_MANUAL)
622 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
623 if (lyxlayout.labeltype != LABEL_BIBLIO
625 delete fppar->bibkey;
634 // set layout over selection and make a total rebreak of those paragraphs
635 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
637 LyXCursor tmpcursor = cursor; /* store the current cursor */
639 // if there is no selection just set the layout
640 // of the current paragraph */
642 sel_start_cursor = cursor; // dummy selection
643 sel_end_cursor = cursor;
646 endpar = SetLayout(bview, cursor, sel_start_cursor,
647 sel_end_cursor, layout);
648 RedoParagraphs(bview, sel_start_cursor, endpar);
650 // we have to reset the selection, because the
651 // geometry could have changed
652 SetCursor(bview, sel_start_cursor.par(),
653 sel_start_cursor.pos(), false);
655 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
657 UpdateCounters(bview, cursor.row());
660 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
664 // increment depth over selection and
665 // make a total rebreak of those paragraphs
666 void LyXText::IncDepth(BufferView * bview)
668 // If there is no selection, just use the current paragraph
670 sel_start_cursor = cursor; // dummy selection
671 sel_end_cursor = cursor;
674 // We end at the next paragraph with depth 0
675 LyXParagraph * endpar =
677 sel_end_cursor.par()->LastPhysicalPar()->Next();
679 sel_end_cursor.par()->Next();
681 LyXParagraph * undoendpar = endpar;
683 if (endpar && endpar->GetDepth()) {
684 while (endpar && endpar->GetDepth()) {
686 endpar = endpar->LastPhysicalPar()->Next();
688 endpar = endpar->Next();
694 endpar = endpar->Next(); // because of parindents etc.
697 SetUndo(bview->buffer(), Undo::EDIT,
700 .par()->ParFromPos(sel_start_cursor.pos())->previous,
702 sel_start_cursor.par()->previous,
706 LyXCursor tmpcursor = cursor; // store the current cursor
708 // ok we have a selection. This is always between sel_start_cursor
709 // and sel_end cursor
710 cursor = sel_start_cursor;
712 bool anything_changed = false;
715 // NOTE: you can't change the depth of a bibliography entry
718 cursor.par()->footnoteflag ==
719 sel_start_cursor.par()->footnoteflag &&
721 textclasslist.Style(bview->buffer()->params.textclass,
722 cursor.par()->GetLayout()
723 ).labeltype != LABEL_BIBLIO) {
724 LyXParagraph * prev =
726 cursor.par()->FirstPhysicalPar()->Previous();
728 cursor.par()->Previous();
731 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
732 || (prev->GetDepth() == cursor.par()->GetDepth()
733 && textclasslist.Style(bview->buffer()->params.textclass,
734 prev->GetLayout()).isEnvironment()))) {
736 cursor.par()->FirstPhysicalPar()->depth++;
738 cursor.par()->depth++;
740 anything_changed = true;
743 if (cursor.par() == sel_end_cursor.par())
745 cursor.par(cursor.par()->Next());
748 // if nothing changed set all depth to 0
749 if (!anything_changed) {
750 cursor = sel_start_cursor;
751 while (cursor.par() != sel_end_cursor.par()) {
753 cursor.par()->FirstPhysicalPar()->depth = 0;
755 cursor.par()->depth = 0;
757 cursor.par(cursor.par()->Next());
760 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
761 cursor.par()->FirstPhysicalPar()->depth = 0;
763 cursor.par()->depth = 0;
767 RedoParagraphs(bview, sel_start_cursor, endpar);
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());
774 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
775 UpdateCounters(bview, cursor.row());
778 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
782 // decrement depth over selection and
783 // make a total rebreak of those paragraphs
784 void LyXText::DecDepth(BufferView * bview)
786 // if there is no selection just set the layout
787 // of the current paragraph
789 sel_start_cursor = cursor; // dummy selection
790 sel_end_cursor = cursor;
793 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
795 LyXParagraph * endpar = sel_end_cursor.par()->Next();
797 LyXParagraph * undoendpar = endpar;
799 if (endpar && endpar->GetDepth()) {
800 while (endpar && endpar->GetDepth()) {
802 endpar = endpar->LastPhysicalPar()->Next();
804 endpar = endpar->Next();
810 endpar = endpar->Next(); // because of parindents etc.
813 SetUndo(bview->buffer(), Undo::EDIT,
816 .par()->ParFromPos(sel_start_cursor.pos())->previous,
818 sel_start_cursor.par()->previous,
822 LyXCursor tmpcursor = cursor; // store the current cursor
824 // ok we have a selection. This is always between sel_start_cursor
825 // and sel_end cursor
826 cursor = sel_start_cursor;
830 if (cursor.par()->footnoteflag ==
831 sel_start_cursor.par()->footnoteflag) {
832 if (cursor.par()->FirstPhysicalPar()->depth)
833 cursor.par()->FirstPhysicalPar()->depth--;
836 if (cursor.par()->depth)
837 cursor.par()->depth--;
839 if (cursor.par() == sel_end_cursor.par())
841 cursor.par(cursor.par()->Next());
844 RedoParagraphs(bview, sel_start_cursor, endpar);
846 // we have to reset the selection, because the
847 // geometry could have changed
848 SetCursor(bview, sel_start_cursor.par(),
849 sel_start_cursor.pos());
851 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
852 UpdateCounters(bview, cursor.row());
855 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
859 // set font over selection and make a total rebreak of those paragraphs
860 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
862 // if there is no selection just set the current_font
864 // Determine basis font
866 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
868 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
870 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
871 // Update current font
872 real_current_font.update(font,
873 bview->buffer()->params.language_info,
876 // Reduce to implicit settings
877 current_font = real_current_font;
878 current_font.reduce(layoutfont);
879 // And resolve it completely
880 real_current_font.realize(layoutfont);
884 LyXCursor tmpcursor = cursor; // store the current cursor
886 // ok we have a selection. This is always between sel_start_cursor
887 // and sel_end cursor
889 SetUndo(bview->buffer(), Undo::EDIT,
891 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
892 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next
894 sel_start_cursor.par()->previous,
895 sel_end_cursor.par()->next
898 cursor = sel_start_cursor;
899 while (cursor.par() != sel_end_cursor.par() ||
902 cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag &&
904 cursor.pos() < sel_end_cursor.pos()))
906 if (cursor.pos() < cursor.par()->Last()
908 && cursor.par()->footnoteflag
909 == sel_start_cursor.par()->footnoteflag
912 // an open footnote should behave
914 LyXFont newfont = GetFont(bview->buffer(),
915 cursor.par(), cursor.pos());
917 bview->buffer()->params.language_info,
919 SetCharFont(bview->buffer(),
920 cursor.par(), cursor.pos(), newfont);
921 cursor.pos(cursor.pos() + 1);
924 cursor.par(cursor.par()->Next());
928 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
930 // we have to reset the selection, because the
931 // geometry could have changed
932 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
934 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
937 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
938 tmpcursor.boundary());
942 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
944 Row * tmprow = cur.row();
945 int y = cur.y() - tmprow->baseline();
947 SetHeightOfRow(bview, tmprow);
949 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
951 LyXParagraph * first_phys_par = tmprow->par();
953 // find the first row of the paragraph
954 if (first_phys_par != tmprow->par())
955 while (tmprow->previous()
956 && tmprow->previous()->par() != first_phys_par) {
957 tmprow = tmprow->previous();
958 y -= tmprow->height();
959 SetHeightOfRow(bview, tmprow);
961 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
962 tmprow = tmprow->previous();
963 y -= tmprow->height();
964 SetHeightOfRow(bview, tmprow);
967 // we can set the refreshing parameters now
968 status = LyXText::NEED_MORE_REFRESH;
970 refresh_row = tmprow;
971 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
975 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
977 Row * tmprow = cur.row();
979 int y = cur.y() - tmprow->baseline();
980 SetHeightOfRow(bview, tmprow);
982 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
984 LyXParagraph * first_phys_par = tmprow->par();
986 // find the first row of the paragraph
987 if (first_phys_par != tmprow->par())
988 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
989 tmprow = tmprow->previous();
990 y -= tmprow->height();
992 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
993 tmprow = tmprow->previous();
994 y -= tmprow->height();
997 // we can set the refreshing parameters now
998 if (status == LyXText::UNCHANGED || y < refresh_y) {
1000 refresh_row = tmprow;
1002 status = LyXText::NEED_MORE_REFRESH;
1003 SetCursor(bview, cur.par(), cur.pos());
1007 /* deletes and inserts again all paragaphs between the cursor
1008 * and the specified par
1009 * This function is needed after SetLayout and SetFont etc. */
1010 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
1011 LyXParagraph const * endpar) const
1014 LyXParagraph * tmppar = 0, * first_phys_par = 0;
1016 Row * tmprow = cur.row();
1018 int y = cur.y() - tmprow->baseline();
1020 if (!tmprow->previous()){
1021 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
1024 first_phys_par = tmprow->par()->FirstPhysicalPar();
1026 first_phys_par = tmprow->par();
1028 // find the first row of the paragraph
1029 if (first_phys_par != tmprow->par())
1030 while (tmprow->previous() &&
1031 (tmprow->previous()->par() != first_phys_par)) {
1032 tmprow = tmprow->previous();
1033 y -= tmprow->height();
1035 while (tmprow->previous()
1036 && tmprow->previous()->par() == first_phys_par) {
1037 tmprow = tmprow->previous();
1038 y -= tmprow->height();
1042 // we can set the refreshing parameters now
1043 status = LyXText::NEED_MORE_REFRESH;
1045 refresh_row = tmprow->previous(); /* the real refresh row will
1046 be deleted, so I store
1047 the previous here */
1050 tmppar = tmprow->next()->par();
1053 while (tmppar != endpar) {
1054 RemoveRow(tmprow->next());
1056 tmppar = tmprow->next()->par();
1061 // remove the first one
1062 tmprow2 = tmprow; /* this is because tmprow->previous()
1064 tmprow = tmprow->previous();
1067 tmppar = first_phys_par;
1071 InsertParagraph(bview, tmppar, tmprow);
1074 while (tmprow->next() && tmprow->next()->par() == tmppar)
1075 tmprow = tmprow->next();
1076 tmppar = tmppar->Next();
1078 } while (tmppar != endpar);
1080 // this is because of layout changes
1082 refresh_y -= refresh_row->height();
1083 SetHeightOfRow(bview, refresh_row);
1085 refresh_row = firstrow;
1087 SetHeightOfRow(bview, refresh_row);
1090 if (tmprow && tmprow->next())
1091 SetHeightOfRow(bview, tmprow->next());
1095 bool LyXText::FullRebreak(BufferView * bview)
1101 if (need_break_row) {
1102 BreakAgain(bview, need_break_row);
1110 /* important for the screen */
1113 /* the cursor set functions have a special mechanism. When they
1114 * realize, that you left an empty paragraph, they will delete it.
1115 * They also delete the corresponding row */
1117 // need the selection cursor:
1118 void LyXText::SetSelection()
1121 last_sel_cursor = sel_cursor;
1122 sel_start_cursor = sel_cursor;
1123 sel_end_cursor = sel_cursor;
1128 // first the toggling area
1129 if (cursor.y() < last_sel_cursor.y()
1130 || (cursor.y() == last_sel_cursor.y()
1131 && cursor.x() < last_sel_cursor.x())) {
1132 toggle_end_cursor = last_sel_cursor;
1133 toggle_cursor = cursor;
1135 toggle_end_cursor = cursor;
1136 toggle_cursor = last_sel_cursor;
1139 last_sel_cursor = cursor;
1141 // and now the whole selection
1143 if (sel_cursor.par() == cursor.par())
1144 if (sel_cursor.pos() < cursor.pos()) {
1145 sel_end_cursor = cursor;
1146 sel_start_cursor = sel_cursor;
1148 sel_end_cursor = sel_cursor;
1149 sel_start_cursor = cursor;
1151 else if (sel_cursor.y() < cursor.y() ||
1152 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1153 sel_end_cursor = cursor;
1154 sel_start_cursor = sel_cursor;
1157 sel_end_cursor = sel_cursor;
1158 sel_start_cursor = cursor;
1161 // a selection with no contents is not a selection
1162 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1163 sel_start_cursor.pos() == sel_end_cursor.pos())
1168 string const LyXText::selectionAsString(Buffer const * buffer) const
1170 if (!selection) return string();
1173 // Special handling if the whole selection is within one paragraph
1174 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1175 result += sel_start_cursor.par()->String(buffer,
1176 sel_start_cursor.pos(),
1177 sel_end_cursor.pos());
1181 // The selection spans more than one paragraph
1183 // First paragraph in selection
1184 result += sel_start_cursor.par()->String(buffer,
1185 sel_start_cursor.pos(),
1186 sel_start_cursor.par()->Last())
1189 // The paragraphs in between (if any)
1190 LyXCursor tmpcur(sel_start_cursor);
1191 tmpcur.par(tmpcur.par()->Next());
1192 while (tmpcur.par() != sel_end_cursor.par()) {
1193 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1194 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1197 // Last paragraph in selection
1198 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1204 void LyXText::ClearSelection() const
1211 void LyXText::CursorHome(BufferView * bview) const
1213 SetCursor(bview, cursor.par(), cursor.row()->pos());
1217 void LyXText::CursorEnd(BufferView * bview) const
1219 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1220 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1222 if (cursor.par()->Last() &&
1223 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1224 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1225 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1227 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1232 void LyXText::CursorTop(BufferView * bview) const
1234 while (cursor.par()->Previous())
1235 cursor.par(cursor.par()->Previous());
1236 SetCursor(bview, cursor.par(), 0);
1240 void LyXText::CursorBottom(BufferView * bview) const
1242 while (cursor.par()->Next())
1243 cursor.par(cursor.par()->Next());
1244 SetCursor(bview, cursor.par(), cursor.par()->Last());
1248 /* returns a pointer to the row near the specified y-coordinate
1249 * (relative to the whole text). y is set to the real beginning
1251 Row * LyXText::GetRowNearY(int & y) const
1253 Row * tmprow = firstrow;
1256 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1257 tmpy += tmprow->height();
1258 tmprow = tmprow->next();
1261 y = tmpy; // return the real y
1266 void LyXText::ToggleFree(BufferView * bview,
1267 LyXFont const & font, bool toggleall)
1269 // If the mask is completely neutral, tell user
1270 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1271 // Could only happen with user style
1272 bview->owner()->getMiniBuffer()
1273 ->Set(_("No font change defined. Use Character under"
1274 " the Layout menu to define font change."));
1278 // Try implicit word selection
1279 // If there is a change in the language the implicit word selection
1281 LyXCursor resetCursor = cursor;
1282 bool implicitSelection = (font.language() == ignore_language
1283 && font.number() == LyXFont::IGNORE)
1284 ? SelectWordWhenUnderCursor(bview) : false;
1287 SetFont(bview, font, toggleall);
1289 /* Implicit selections are cleared afterwards and cursor is set to the
1290 original position. */
1291 if (implicitSelection) {
1293 cursor = resetCursor;
1294 SetCursor(bview, cursor.par(), cursor.pos());
1295 sel_cursor = cursor;
1300 LyXParagraph::size_type
1301 LyXText::BeginningOfMainBody(Buffer const * buf,
1302 LyXParagraph const * par) const
1304 if (textclasslist.Style(buf->params.textclass,
1305 par->GetLayout()).labeltype != LABEL_MANUAL)
1308 return par->BeginningOfMainBody();
1313 /* if there is a selection, reset every environment you can find
1314 * in the selection, otherwise just the environment you are in */
1315 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1317 LyXParagraph * tmppar, * firsttmppar;
1321 /* is is only allowed, if the cursor is IN an open footnote.
1322 * Otherwise it is too dangerous */
1323 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1326 SetUndo(bview->buffer(), Undo::FINISH,
1327 cursor.par()->PreviousBeforeFootnote()->previous,
1328 cursor.par()->NextAfterFootnote()->next);
1330 /* ok, move to the beginning of the footnote. */
1331 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1332 cursor.par(cursor.par()->Previous());
1334 SetCursor(bview, cursor.par(), cursor.par()->Last());
1335 /* this is just faster than using CursorLeft(); */
1337 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1338 tmppar = firsttmppar;
1339 /* tmppar is now the paragraph right before the footnote */
1341 bool first_footnote_par_is_not_empty = tmppar->next->size();
1344 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1345 tmppar = tmppar->next; /* I use next instead of Next(),
1346 * because there cannot be any
1347 * footnotes in a footnote
1349 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1351 /* remember the captions and empty paragraphs */
1352 if ((textclasslist.Style(bview->buffer()->params.textclass,
1353 tmppar->GetLayout())
1354 .labeltype == LABEL_SENSITIVE)
1356 tmppar->SetLayout(bview->buffer()->params, 0);
1359 // now we will paste the ex-footnote, if the layouts allow it
1360 // first restore the layout of the paragraph right behind
1363 tmppar->next->MakeSameLayout(cursor.par());
1366 if (!tmppar->GetLayout()
1368 && (!tmppar->Next()->Last()
1369 || tmppar->Next()->HasSameLayout(tmppar)))) {
1370 if (tmppar->Next()->Last()
1371 && tmppar->Next()->IsLineSeparator(0))
1372 tmppar->Next()->Erase(0);
1373 tmppar->PasteParagraph(bview->buffer()->params);
1376 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1377 * by the pasting of the beginning */
1379 /* then the beginning */
1380 /* if there is no space between the text and the footnote, so we insert
1382 * (only if the previous par and the footnotepar are not empty!) */
1383 if (!firsttmppar->next->GetLayout()
1384 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1385 if (firsttmppar->size()
1386 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1387 && first_footnote_par_is_not_empty) {
1388 firsttmppar->next->InsertChar(0, ' ');
1390 firsttmppar->PasteParagraph(bview->buffer()->params);
1393 /* now redo the paragaphs */
1394 RedoParagraphs(bview, cursor, tmppar);
1396 SetCursor(bview, cursor.par(), cursor.pos());
1398 /* sometimes it can happen, that there is a counter change */
1399 Row * row = cursor.row();
1400 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1402 UpdateCounters(bview, row);
1410 /* the DTP switches for paragraphs. LyX will store them in the
1411 * first physicla paragraph. When a paragraph is broken, the top settings
1412 * rest, the bottom settings are given to the new one. So I can make shure,
1413 * they do not duplicate themself and you cannnot make dirty things with
1416 void LyXText::SetParagraph(BufferView * bview,
1417 bool line_top, bool line_bottom,
1418 bool pagebreak_top, bool pagebreak_bottom,
1419 VSpace const & space_top,
1420 VSpace const & space_bottom,
1422 string labelwidthstring,
1425 LyXCursor tmpcursor = cursor;
1427 sel_start_cursor = cursor;
1428 sel_end_cursor = cursor;
1431 // make sure that the depth behind the selection are restored, too
1433 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1435 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1437 LyXParagraph * undoendpar = endpar;
1439 if (endpar && endpar->GetDepth()) {
1440 while (endpar && endpar->GetDepth()) {
1442 endpar = endpar->LastPhysicalPar()->Next();
1444 endpar = endpar->Next();
1446 undoendpar = endpar;
1450 endpar = endpar->Next(); // because of parindents etc.
1453 SetUndo(bview->buffer(), Undo::EDIT,
1456 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1458 sel_start_cursor.par()->previous,
1463 LyXParagraph * tmppar = sel_end_cursor.par();
1465 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1466 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1468 while (tmppar != sel_start_cursor.par()->Previous()) {
1469 SetCursor(bview, tmppar, 0);
1471 status = LyXText::NEED_MORE_REFRESH;
1472 refresh_row = cursor.row();
1473 refresh_y = cursor.y() - cursor.row()->baseline();
1475 if (cursor.par()->footnoteflag ==
1476 sel_start_cursor.par()->footnoteflag) {
1478 cursor.par()->line_top = line_top;
1479 cursor.par()->line_bottom = line_bottom;
1480 cursor.par()->pagebreak_top = pagebreak_top;
1481 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1482 cursor.par()->added_space_top = space_top;
1483 cursor.par()->added_space_bottom = space_bottom;
1484 // does the layout allow the new alignment?
1485 if (align == LYX_ALIGN_LAYOUT)
1486 align = textclasslist
1487 .Style(bview->buffer()->params.textclass,
1488 cursor.par()->GetLayout()).align;
1489 if (align & textclasslist
1490 .Style(bview->buffer()->params.textclass,
1491 cursor.par()->GetLayout()).alignpossible) {
1492 if (align == textclasslist
1493 .Style(bview->buffer()->params.textclass,
1494 cursor.par()->GetLayout()).align)
1495 cursor.par()->align = LYX_ALIGN_LAYOUT;
1497 cursor.par()->align = align;
1499 cursor.par()->SetLabelWidthString(labelwidthstring);
1500 cursor.par()->noindent = noindent;
1504 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1506 tmppar = cursor.par()->Previous();
1510 RedoParagraphs(bview, sel_start_cursor, endpar);
1513 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1514 sel_cursor = cursor;
1515 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1517 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1519 bview->updateInset(inset_owner, true);
1523 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1524 string const & width,
1525 string const & widthp,
1526 int alignment, bool hfill,
1527 bool start_minipage)
1529 LyXCursor tmpcursor = cursor;
1530 LyXParagraph * tmppar;
1532 sel_start_cursor = cursor;
1533 sel_end_cursor = cursor;
1536 // make sure that the depth behind the selection are restored, too
1538 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1540 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1542 LyXParagraph * undoendpar = endpar;
1544 if (endpar && endpar->GetDepth()) {
1545 while (endpar && endpar->GetDepth()) {
1547 endpar = endpar->LastPhysicalPar()->Next();
1549 endpar = endpar->Next();
1551 undoendpar = endpar;
1555 endpar = endpar->Next(); // because of parindents etc.
1558 SetUndo(bview->buffer(), Undo::EDIT,
1561 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1563 sel_start_cursor.par()->previous,
1567 tmppar = sel_end_cursor.par();
1569 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1570 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1572 while(tmppar != sel_start_cursor.par()->Previous()) {
1573 SetCursor(bview, tmppar, 0);
1575 status = LyXText::NEED_MORE_REFRESH;
1576 refresh_row = cursor.row();
1577 refresh_y = cursor.y() - cursor.row()->baseline();
1579 if (cursor.par()->footnoteflag ==
1580 sel_start_cursor.par()->footnoteflag) {
1582 if (type == LyXParagraph::PEXTRA_NONE) {
1583 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1584 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1585 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1588 cursor.par()->SetPExtraType(bview->buffer()->params,
1589 type, width, widthp);
1590 cursor.par()->pextra_hfill = hfill;
1591 cursor.par()->pextra_start_minipage = start_minipage;
1592 cursor.par()->pextra_alignment = alignment;
1596 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1598 tmppar = cursor.par()->Previous();
1601 RedoParagraphs(bview, sel_start_cursor, endpar);
1603 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1604 sel_cursor = cursor;
1605 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1607 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1611 char loweralphaCounter(int n)
1613 if (n < 1 || n > 26)
1621 char alphaCounter(int n)
1623 if (n < 1 || n > 26)
1631 char hebrewCounter(int n)
1633 static const char hebrew[22] = {
1634 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1635 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1636 '÷', 'ø', 'ù', 'ú'
1638 if (n < 1 || n > 22)
1646 string const romanCounter(int n)
1648 static char const * roman[20] = {
1649 "i", "ii", "iii", "iv", "v",
1650 "vi", "vii", "viii", "ix", "x",
1651 "xi", "xii", "xiii", "xiv", "xv",
1652 "xvi", "xvii", "xviii", "xix", "xx"
1654 if (n < 1 || n > 20)
1661 // set the counter of a paragraph. This includes the labels
1662 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1665 // this is only relevant for the beginning of paragraph
1666 par = par->FirstPhysicalPar();
1668 LyXLayout const & layout =
1669 textclasslist.Style(buf->params.textclass,
1672 LyXTextClass const & textclass =
1673 textclasslist.TextClass(buf->params.textclass);
1675 /* copy the prev-counters to this one, unless this is the start of a
1676 footnote or of a bibliography or the very first paragraph */
1679 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1680 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1681 && par->footnotekind == LyXParagraph::FOOTNOTE)
1683 && !(textclasslist.Style(buf->params.textclass,
1684 par->Previous()->GetLayout()
1685 ).labeltype != LABEL_BIBLIO
1686 && layout.labeltype == LABEL_BIBLIO)) {
1687 for (int i = 0; i < 10; ++i) {
1688 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1691 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1693 par->appendix = par->Previous()->appendix;
1695 if (!par->appendix && par->start_of_appendix){
1696 par->appendix = true;
1697 for (int i = 0; i < 10; ++i) {
1698 par->setCounter(i, 0);
1702 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1703 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1705 par->enumdepth = par->Previous()->enumdepth;
1706 par->itemdepth = par->Previous()->itemdepth;
1709 for (int i = 0; i < 10; ++i) {
1710 par->setCounter(i, 0);
1712 par->appendix = par->start_of_appendix;
1718 // if this is an open marginnote and this is the first
1719 // entry in the marginnote and the enclosing
1720 // environment is an enum/item then correct for the
1721 // LaTeX behaviour (ARRae)
1722 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1723 && par->footnotekind == LyXParagraph::MARGIN
1725 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1726 && (par->PreviousBeforeFootnote()
1727 && textclasslist.Style(buf->params.textclass,
1728 par->PreviousBeforeFootnote()->GetLayout()
1729 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1730 // Any itemize or enumerate environment in a marginnote
1731 // that is embedded in an itemize or enumerate
1732 // paragraph is seen by LaTeX as being at a deeper
1733 // level within that enclosing itemization/enumeration
1734 // even if there is a "standard" layout at the start of
1740 /* Maybe we have to increment the enumeration depth.
1741 * BUT, enumeration in a footnote is considered in isolation from its
1742 * surrounding paragraph so don't increment if this is the
1743 * first line of the footnote
1744 * AND, bibliographies can't have their depth changed ie. they
1745 * are always of depth 0
1748 && par->Previous()->GetDepth() < par->GetDepth()
1749 && textclasslist.Style(buf->params.textclass,
1750 par->Previous()->GetLayout()
1751 ).labeltype == LABEL_COUNTER_ENUMI
1752 && par->enumdepth < 3
1754 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1755 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1756 && par->footnotekind == LyXParagraph::FOOTNOTE)
1758 && layout.labeltype != LABEL_BIBLIO) {
1762 /* Maybe we have to decrement the enumeration depth, see note above */
1764 && par->Previous()->GetDepth() > par->GetDepth()
1766 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1767 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1768 && par->footnotekind == LyXParagraph::FOOTNOTE)
1770 && layout.labeltype != LABEL_BIBLIO) {
1771 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1772 par->setCounter(6 + par->enumdepth,
1773 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1774 /* reset the counters.
1775 * A depth change is like a breaking layout
1777 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1778 par->setCounter(i, 0);
1781 if (!par->labelstring.empty()) {
1782 par->labelstring.erase();
1785 if (layout.margintype == MARGIN_MANUAL) {
1786 if (par->labelwidthstring.empty()) {
1787 par->SetLabelWidthString(layout.labelstring());
1790 par->SetLabelWidthString(string());
1793 /* is it a layout that has an automatic label ? */
1794 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1796 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1797 if (i >= 0 && i<= buf->params.secnumdepth) {
1798 par->incCounter(i); // increment the counter
1800 // Is there a label? Useful for Chapter layout
1801 if (!par->appendix){
1802 if (!layout.labelstring().empty())
1803 par->labelstring = layout.labelstring();
1805 par->labelstring.erase();
1807 if (!layout.labelstring_appendix().empty())
1808 par->labelstring = layout.labelstring_appendix();
1810 par->labelstring.erase();
1813 std::ostringstream s;
1815 if (!par->appendix) {
1816 switch (2 * LABEL_COUNTER_CHAPTER -
1817 textclass.maxcounter() + i) {
1818 case LABEL_COUNTER_CHAPTER:
1819 s << par->getCounter(i);
1821 case LABEL_COUNTER_SECTION:
1822 s << par->getCounter(i - 1) << '.'
1823 << par->getCounter(i);
1825 case LABEL_COUNTER_SUBSECTION:
1826 s << par->getCounter(i - 2) << '.'
1827 << par->getCounter(i - 1) << '.'
1828 << par->getCounter(i);
1830 case LABEL_COUNTER_SUBSUBSECTION:
1831 s << par->getCounter(i - 3) << '.'
1832 << par->getCounter(i - 2) << '.'
1833 << par->getCounter(i - 1) << '.'
1834 << par->getCounter(i);
1837 case LABEL_COUNTER_PARAGRAPH:
1838 s << par->getCounter(i - 4) << '.'
1839 << par->getCounter(i - 3) << '.'
1840 << par->getCounter(i - 2) << '.'
1841 << par->getCounter(i - 1) << '.'
1842 << par->getCounter(i);
1844 case LABEL_COUNTER_SUBPARAGRAPH:
1845 s << par->getCounter(i - 5) << '.'
1846 << par->getCounter(i - 4) << '.'
1847 << par->getCounter(i - 3) << '.'
1848 << par->getCounter(i - 2) << '.'
1849 << par->getCounter(i - 1) << '.'
1850 << par->getCounter(i);
1854 // Can this ever be reached? And in the
1855 // case it is, how can this be correct?
1857 s << par->getCounter(i) << '.';
1860 } else { // appendix
1861 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1862 case LABEL_COUNTER_CHAPTER:
1863 if (par->isRightToLeftPar(buf->params))
1864 s << hebrewCounter(par->getCounter(i));
1866 s << alphaCounter(par->getCounter(i));
1868 case LABEL_COUNTER_SECTION:
1869 if (par->isRightToLeftPar(buf->params))
1870 s << hebrewCounter(par->getCounter(i - 1));
1872 s << alphaCounter(par->getCounter(i - 1));
1875 << par->getCounter(i);
1878 case LABEL_COUNTER_SUBSECTION:
1879 if (par->isRightToLeftPar(buf->params))
1880 s << hebrewCounter(par->getCounter(i - 2));
1882 s << alphaCounter(par->getCounter(i - 2));
1885 << par->getCounter(i-1) << '.'
1886 << par->getCounter(i);
1889 case LABEL_COUNTER_SUBSUBSECTION:
1890 if (par->isRightToLeftPar(buf->params))
1891 s << hebrewCounter(par->getCounter(i-3));
1893 s << alphaCounter(par->getCounter(i-3));
1896 << par->getCounter(i-2) << '.'
1897 << par->getCounter(i-1) << '.'
1898 << par->getCounter(i);
1901 case LABEL_COUNTER_PARAGRAPH:
1902 if (par->isRightToLeftPar(buf->params))
1903 s << hebrewCounter(par->getCounter(i-4));
1905 s << alphaCounter(par->getCounter(i-4));
1908 << par->getCounter(i-3) << '.'
1909 << par->getCounter(i-2) << '.'
1910 << par->getCounter(i-1) << '.'
1911 << par->getCounter(i);
1914 case LABEL_COUNTER_SUBPARAGRAPH:
1915 if (par->isRightToLeftPar(buf->params))
1916 s << hebrewCounter(par->getCounter(i-5));
1918 s << alphaCounter(par->getCounter(i-5));
1921 << par->getCounter(i-4) << '.'
1922 << par->getCounter(i-3) << '.'
1923 << par->getCounter(i-2) << '.'
1924 << par->getCounter(i-1) << '.'
1925 << par->getCounter(i);
1929 // Can this ever be reached? And in the
1930 // case it is, how can this be correct?
1932 s << par->getCounter(i) << '.';
1938 par->labelstring += s.str().c_str();
1939 // We really want to remove the c_str as soon as
1942 for (i++; i < 10; ++i) {
1943 // reset the following counters
1944 par->setCounter(i, 0);
1946 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1947 for (i++; i < 10; ++i) {
1948 // reset the following counters
1949 par->setCounter(i, 0);
1951 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1952 par->incCounter(i + par->enumdepth);
1953 int number = par->getCounter(i + par->enumdepth);
1955 std::ostringstream s;
1957 switch (par->enumdepth) {
1959 if (par->isRightToLeftPar(buf->params))
1961 << hebrewCounter(number)
1965 << loweralphaCounter(number)
1969 if (par->isRightToLeftPar(buf->params))
1970 s << '.' << romanCounter(number);
1972 s << romanCounter(number) << '.';
1975 if (par->isRightToLeftPar(buf->params))
1977 << alphaCounter(number);
1979 s << alphaCounter(number)
1983 if (par->isRightToLeftPar(buf->params))
1990 par->labelstring = s.str().c_str();
1991 // we really want to get rid of that c_str()
1993 for (i += par->enumdepth + 1; i < 10; ++i)
1994 par->setCounter(i, 0); /* reset the following counters */
1997 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1998 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2000 int number = par->getCounter(i);
2002 InsetCommandParams p( "bibitem" );
2003 par->bibkey = new InsetBibKey(p);
2005 par->bibkey->setCounter(number);
2006 par->labelstring = layout.labelstring();
2008 // In biblio should't be following counters but...
2010 string s = layout.labelstring();
2012 // the caption hack:
2013 if (layout.labeltype == LABEL_SENSITIVE) {
2014 bool isOK (par->InInset() && par->InInset()->owner() &&
2015 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2017 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2018 && (par->footnotekind == LyXParagraph::FIG
2019 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2020 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2021 ? ":øåéà " : "Figure:";
2022 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2023 && (par->footnotekind == LyXParagraph::TAB
2024 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2025 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2026 ? ":äìáè" : "Table:";
2027 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2028 && par->footnotekind == LyXParagraph::ALGORITHM) {
2029 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2030 ? ":Ãúéøåâìà " : "Algorithm:";
2034 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2036 = floatList.getType(tmp->type());
2037 // We should get the correct number here too.
2038 s = fl.name + " #:";
2040 /* par->SetLayout(0);
2041 s = layout->labelstring; */
2042 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2043 ? " :úåòîùî øñç" : "Senseless: ";
2046 par->labelstring = s;
2048 /* reset the enumeration counter. They are always resetted
2049 * when there is any other layout between */
2050 for (int i = 6 + par->enumdepth; i < 10; ++i)
2051 par->setCounter(i, 0);
2056 /* Updates all counters BEHIND the row. Changed paragraphs
2057 * with a dynamic left margin will be rebroken. */
2058 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2065 if (row->par()->next
2067 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2071 par = row->par()->LastPhysicalPar()->Next();
2073 par = row->par()->Next();
2076 par = row->par()->next;
2081 while (row->par() != par)
2084 SetCounter(bview->buffer(), par);
2086 /* now check for the headline layouts. remember that they
2087 * have a dynamic left margin */
2092 ( textclasslist.Style(bview->buffer()->params.textclass,
2093 par->layout).margintype == MARGIN_DYNAMIC
2094 || textclasslist.Style(bview->buffer()->params.textclass,
2095 par->layout).labeltype == LABEL_SENSITIVE)
2098 /* Rebreak the paragraph */
2099 RemoveParagraph(row);
2100 AppendParagraph(bview, row);
2103 /* think about the damned open footnotes! */
2104 while (par->Next() &&
2105 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2106 || par->Next()->IsDummy())){
2108 if (par->IsDummy()) {
2109 while (row->par() != par)
2111 RemoveParagraph(row);
2112 AppendParagraph(bview, row);
2118 par = par->LastPhysicalPar()->Next();
2127 /* insets an inset. */
2128 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2130 if (!cursor.par()->InsertInsetAllowed(inset))
2132 SetUndo(bview->buffer(), Undo::INSERT,
2134 cursor.par()->ParFromPos(cursor.pos())->previous,
2135 cursor.par()->ParFromPos(cursor.pos())->next
2137 cursor.par()->previous,
2141 cursor.par()->InsertInset(cursor.pos(), inset);
2142 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2143 * The character will not be inserted a
2146 // if we enter a text-inset the cursor should be to the left side
2147 // of it! This couldn't happen before as Undo was not handled inside
2148 // inset now after the Undo LyX tries to call inset->Edit(...) again
2149 // and cannot do this as the cursor is behind the inset and GetInset
2150 // does not return the inset!
2151 if (inset->IsTextInset()) {
2152 if (cursor.par()->isRightToLeftPar(bview->buffer()->params))
2161 void LyXText::copyEnvironmentType()
2163 copylayouttype = cursor.par()->GetLayout();
2167 void LyXText::pasteEnvironmentType(BufferView * bview)
2169 SetLayout(bview, copylayouttype);
2173 void LyXText::CutSelection(BufferView * bview, bool doclear)
2175 // Stuff what we got on the clipboard. Even if there is no selection.
2177 // There is a problem with having the stuffing here in that the
2178 // larger the selection the slower LyX will get. This can be
2179 // solved by running the line below only when the selection has
2180 // finished. The solution used currently just works, to make it
2181 // faster we need to be more clever and probably also have more
2182 // calls to stuffClipboard. (Lgb)
2183 bview->stuffClipboard(selectionAsString(bview->buffer()));
2185 // This doesn't make sense, if there is no selection
2189 // OK, we have a selection. This is always between sel_start_cursor
2190 // and sel_end cursor
2192 // Check whether there are half footnotes in the selection
2193 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2194 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2195 LyXParagraph * tmppar = sel_start_cursor.par();
2196 while (tmppar != sel_end_cursor.par()){
2197 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2198 WriteAlert(_("Impossible operation"),
2199 _("Don't know what to do with half floats."),
2203 tmppar = tmppar->Next();
2208 // make sure that the depth behind the selection are restored, too
2210 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2212 LyXParagraph * endpar = sel_end_cursor.par()->Next();
2214 LyXParagraph * undoendpar = endpar;
2216 if (endpar && endpar->GetDepth()) {
2217 while (endpar && endpar->GetDepth()) {
2219 endpar = endpar->LastPhysicalPar()->Next();
2221 endpar = endpar->Next();
2223 undoendpar = endpar;
2225 } else if (endpar) {
2226 endpar = endpar->Next(); // because of parindents etc.
2229 SetUndo(bview->buffer(), Undo::DELETE,
2232 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2234 sel_start_cursor.par()->previous,
2240 // there are two cases: cut only within one paragraph or
2241 // more than one paragraph
2243 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2244 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2246 if (sel_start_cursor.par() == sel_end_cursor.par())
2249 // only within one paragraph
2250 endpar = sel_start_cursor.par();
2251 int pos = sel_end_cursor.pos();
2252 cap.cutSelection(sel_start_cursor.par(), &endpar,
2253 sel_start_cursor.pos(), pos,
2254 bview->buffer()->params.textclass, doclear);
2255 sel_end_cursor.pos(pos);
2257 endpar = sel_end_cursor.par();
2259 int pos = sel_end_cursor.pos();
2260 cap.cutSelection(sel_start_cursor.par(), &endpar,
2261 sel_start_cursor.pos(), pos,
2262 bview->buffer()->params.textclass, doclear);
2264 sel_end_cursor.par(endpar);
2265 sel_end_cursor.pos(pos);
2266 cursor.pos(sel_end_cursor.pos());
2268 endpar = endpar->Next();
2270 // sometimes necessary
2272 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2274 RedoParagraphs(bview, sel_start_cursor, endpar);
2277 cursor = sel_start_cursor;
2278 SetCursor(bview, cursor.par(), cursor.pos());
2279 sel_cursor = cursor;
2280 UpdateCounters(bview, cursor.row());
2284 void LyXText::CopySelection(BufferView * bview)
2286 // Stuff what we got on the clipboard. Even if there is no selection.
2288 // There is a problem with having the stuffing here in that the
2289 // larger the selection the slower LyX will get. This can be
2290 // solved by running the line below only when the selection has
2291 // finished. The solution used currently just works, to make it
2292 // faster we need to be more clever and probably also have more
2293 // calls to stuffClipboard. (Lgb)
2294 bview->stuffClipboard(selectionAsString(bview->buffer()));
2296 // this doesnt make sense, if there is no selection
2300 // ok we have a selection. This is always between sel_start_cursor
2301 // and sel_end cursor
2304 /* check wether there are half footnotes in the selection */
2305 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2306 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2307 LyXParagraph * tmppar = sel_start_cursor.par();
2308 while (tmppar != sel_end_cursor.par()) {
2309 if (tmppar->footnoteflag !=
2310 sel_end_cursor.par()->footnoteflag) {
2311 WriteAlert(_("Impossible operation"),
2312 _("Don't know what to do"
2313 " with half floats."),
2317 tmppar = tmppar->Next();
2322 // copy behind a space if there is one
2323 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2324 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2325 && (sel_start_cursor.par() != sel_end_cursor.par()
2326 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2327 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2331 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2332 sel_start_cursor.pos(), sel_end_cursor.pos(),
2333 bview->buffer()->params.textclass);
2337 void LyXText::PasteSelection(BufferView * bview)
2341 // this does not make sense, if there is nothing to paste
2342 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2345 SetUndo(bview->buffer(), Undo::INSERT,
2347 cursor.par()->ParFromPos(cursor.pos())->previous,
2348 cursor.par()->ParFromPos(cursor.pos())->next
2350 cursor.par()->previous,
2355 LyXParagraph * endpar;
2356 LyXParagraph * actpar = cursor.par();
2358 int pos = cursor.pos();
2359 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2361 RedoParagraphs(bview, cursor, endpar);
2363 SetCursor(bview, cursor.par(), cursor.pos());
2366 sel_cursor = cursor;
2367 SetCursor(bview, actpar, pos);
2369 UpdateCounters(bview, cursor.row());
2373 // returns a pointer to the very first LyXParagraph
2374 LyXParagraph * LyXText::FirstParagraph() const
2376 return OwnerParagraph();
2380 // returns true if the specified string is at the specified position
2381 bool LyXText::IsStringInText(LyXParagraph * par,
2382 LyXParagraph::size_type pos,
2383 string const & str) const
2388 LyXParagraph::size_type i = 0;
2389 while (pos + i < par->Last()
2390 && string::size_type(i) < str.length()
2391 && str[i] == par->GetChar(pos + i)) {
2394 if (str.length() == string::size_type(i))
2400 // sets the selection over the number of characters of string, no check!!
2401 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2403 sel_cursor = cursor;
2404 for (int i = 0; str[i]; ++i)
2410 // simple replacing. The font of the first selected character is used
2411 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2414 SetCursorParUndo(bview->buffer());
2417 if (!selection) { // create a dummy selection
2418 sel_end_cursor = cursor;
2419 sel_start_cursor = cursor;
2422 // Get font setting before we cut
2423 LyXParagraph::size_type pos = sel_end_cursor.pos();
2424 LyXFont const font = sel_start_cursor.par()
2425 ->GetFontSettings(bview->buffer()->params,
2426 sel_start_cursor.pos());
2428 // Insert the new string
2429 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2430 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2434 // Cut the selection
2435 CutSelection(bview);
2441 // if the string can be found: return true and set the cursor to
2443 bool LyXText::SearchForward(BufferView * bview, string const & str) const
2445 LyXParagraph * par = cursor.par();
2446 LyXParagraph::size_type pos = cursor.pos();
2447 while (par && !IsStringInText(par, pos, str)) {
2448 if (pos < par->Last() - 1)
2456 SetCursor(bview, par, pos);
2464 bool LyXText::SearchBackward(BufferView * bview, string const & str) const
2466 LyXParagraph * par = cursor.par();
2467 int pos = cursor.pos();
2473 // We skip empty paragraphs (Asger)
2475 par = par->Previous();
2477 pos = par->Last() - 1;
2478 } while (par && pos < 0);
2480 } while (par && !IsStringInText(par, pos, str));
2483 SetCursor(bview, par, pos);
2490 // needed to insert the selection
2491 void LyXText::InsertStringA(BufferView * bview, string const & str)
2493 LyXParagraph * par = cursor.par();
2494 LyXParagraph::size_type pos = cursor.pos();
2495 LyXParagraph::size_type a = 0;
2496 LyXParagraph * endpar = cursor.par()->Next();
2498 SetCursorParUndo(bview->buffer());
2501 textclasslist.Style(bview->buffer()->params.textclass,
2502 cursor.par()->GetLayout()).isEnvironment();
2503 // only to be sure, should not be neccessary
2506 // insert the string, don't insert doublespace
2507 string::size_type i = 0;
2508 while (i < str.length()) {
2509 if (str[i] != '\n') {
2511 && i + 1 < str.length() && str[i + 1] != ' '
2512 && pos && par->GetChar(pos - 1)!= ' ') {
2513 par->InsertChar(pos, ' ', current_font);
2515 } else if (str[i] == ' ') {
2516 InsetSpecialChar * new_inset =
2517 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2518 if (par->InsertInsetAllowed(new_inset)) {
2519 par->InsertInset(pos, new_inset,
2525 } else if (str[i] == '\t') {
2526 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2527 InsetSpecialChar * new_inset =
2528 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2529 if (par->InsertInsetAllowed(new_inset)) {
2530 par->InsertInset(pos, new_inset,
2537 } else if (str[i] != 13 &&
2538 // Ignore unprintables
2539 (str[i] & 127) >= ' ') {
2540 par->InsertChar(pos, str[i], current_font);
2544 if (!par->size()) { // par is empty
2545 InsetSpecialChar * new_inset =
2546 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2547 if (par->InsertInsetAllowed(new_inset)) {
2548 par->InsertInset(pos,
2556 par->BreakParagraph(bview->buffer()->params, pos, flag);
2563 RedoParagraphs(bview, cursor, endpar);
2564 SetCursor(bview, cursor.par(), cursor.pos());
2565 sel_cursor = cursor;
2566 SetCursor(bview, par, pos);
2571 /* turns double-CR to single CR, others where converted into one blank and 13s
2572 * that are ignored .Double spaces are also converted into one. Spaces at
2573 * the beginning of a paragraph are forbidden. tabs are converted into one
2574 * space. then InsertStringA is called */
2575 void LyXText::InsertStringB(BufferView * bview, string const & s)
2578 string::size_type i = 1;
2579 while (i < str.length()) {
2582 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2584 if (str[i] == '\n' && i + 1 < str.length()) {
2585 if (str[i + 1] != '\n') {
2586 if (str[i - 1] != ' ')
2591 while (i + 1 < str.length()
2592 && (str[i + 1] == ' '
2593 || str[i + 1] == '\t'
2594 || str[i + 1] == '\n'
2595 || str[i + 1] == 13)) {
2602 InsertStringA(bview, str);
2606 bool LyXText::GotoNextError(BufferView * bview) const
2608 LyXCursor res = cursor;
2610 if (res.pos() < res.par()->Last() - 1) {
2611 res.pos(res.pos() + 1);
2613 res.par(res.par()->Next());
2617 } while (res.par() &&
2618 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2619 && res.par()->GetInset(res.pos())->AutoDelete()));
2622 SetCursor(bview, res.par(), res.pos());
2629 bool LyXText::GotoNextNote(BufferView * bview) const
2631 LyXCursor res = cursor;
2633 if (res.pos() < res.par()->Last() - 1) {
2634 res.pos(res.pos() + 1);
2636 res.par(res.par()->Next());
2640 } while (res.par() &&
2641 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2642 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2645 SetCursor(bview, res.par(), res.pos());
2652 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2653 LyXParagraph::size_type pos)
2655 LyXCursor tmpcursor;
2658 LyXParagraph::size_type z;
2659 Row * row = GetRow(par, pos, y);
2661 // is there a break one row above
2662 if (row->previous() && row->previous()->par() == row->par()) {
2663 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2664 if ( z >= row->pos()) {
2665 // set the dimensions of the row above
2666 y -= row->previous()->height();
2668 refresh_row = row->previous();
2669 status = LyXText::NEED_MORE_REFRESH;
2671 BreakAgain(bview, row->previous());
2673 // set the cursor again. Otherwise
2674 // dangling pointers are possible
2675 SetCursor(bview, cursor.par(), cursor.pos());
2676 sel_cursor = cursor;
2681 int const tmpheight = row->height();
2682 LyXParagraph::size_type const tmplast = RowLast(row);
2686 BreakAgain(bview, row);
2687 if (row->height() == tmpheight && RowLast(row) == tmplast)
2688 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2690 status = LyXText::NEED_MORE_REFRESH;
2692 // check the special right address boxes
2693 if (textclasslist.Style(bview->buffer()->params.textclass,
2694 par->GetLayout()).margintype
2695 == MARGIN_RIGHT_ADDRESS_BOX) {
2702 RedoDrawingOfParagraph(bview, tmpcursor);
2705 // set the cursor again. Otherwise dangling pointers are possible
2706 // also set the selection
2710 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2711 sel_cursor = cursor;
2712 SetCursorIntern(bview, sel_start_cursor.par(),
2713 sel_start_cursor.pos());
2714 sel_start_cursor = cursor;
2715 SetCursorIntern(bview, sel_end_cursor.par(),
2716 sel_end_cursor.pos());
2717 sel_end_cursor = cursor;
2718 SetCursorIntern(bview, last_sel_cursor.par(),
2719 last_sel_cursor.pos());
2720 last_sel_cursor = cursor;
2723 SetCursorIntern(bview, cursor.par(), cursor.pos());
2727 // returns false if inset wasn't found
2728 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2730 // first check the current paragraph
2731 int pos = cursor.par()->GetPositionOfInset(inset);
2733 CheckParagraph(bview, cursor.par(), pos);
2737 // check every paragraph
2739 LyXParagraph * par = FirstParagraph();
2742 // make sure the paragraph is open
2743 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2745 pos = par->GetPositionOfInset(inset);
2747 CheckParagraph(bview, par, pos);
2760 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2761 LyXParagraph::size_type pos,
2762 bool setfont, bool boundary) const
2764 LyXCursor old_cursor = cursor;
2765 SetCursorIntern(bview, par, pos, setfont, boundary);
2766 DeleteEmptyParagraphMechanism(bview, old_cursor);
2770 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2771 LyXParagraph::size_type pos, bool boundary) const
2774 // correct the cursor position if impossible
2775 if (pos > par->Last()){
2776 LyXParagraph * tmppar = par->ParFromPos(pos);
2777 pos = par->PositionInParFromPos(pos);
2780 if (par->IsDummy() && par->previous &&
2781 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2782 while (par->previous &&
2783 ((par->previous->IsDummy() &&
2784 (par->previous->previous->footnoteflag ==
2785 LyXParagraph::CLOSED_FOOTNOTE)) ||
2786 (par->previous->footnoteflag ==
2787 LyXParagraph::CLOSED_FOOTNOTE))) {
2788 par = par->previous ;
2789 if (par->IsDummy() &&
2790 (par->previous->footnoteflag ==
2791 LyXParagraph::CLOSED_FOOTNOTE))
2792 pos += par->size() + 1;
2794 if (par->previous) {
2795 par = par->previous;
2797 pos += par->size() + 1;
2802 cur.boundary(boundary);
2804 /* get the cursor y position in text */
2806 Row * row = GetRow(par, pos, y);
2807 /* y is now the beginning of the cursor row */
2808 y += row->baseline();
2809 /* y is now the cursor baseline */
2812 /* now get the cursors x position */
2814 float fill_separator, fill_hfill, fill_label_hfill;
2815 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2817 LyXParagraph::size_type cursor_vpos = 0;
2818 LyXParagraph::size_type last = RowLastPrintable(row);
2820 if (pos > last + 1) // This shouldn't happen.
2822 else if (pos < row->pos())
2825 if (last < row->pos())
2826 cursor_vpos = row->pos();
2827 else if (pos > last && !boundary)
2828 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2829 ? row->pos() : last + 1;
2830 else if (pos > row->pos() &&
2831 (pos > last || boundary))
2832 /// Place cursor after char at (logical) position pos - 1
2833 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2834 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2836 /// Place cursor before char at (logical) position pos
2837 cursor_vpos = (bidi_level(pos) % 2 == 0)
2838 ? log2vis(pos) : log2vis(pos) + 1;
2840 LyXParagraph::size_type main_body =
2841 BeginningOfMainBody(bview->buffer(), row->par());
2842 if ((main_body > 0) &&
2843 ((main_body-1 > last) ||
2844 !row->par()->IsLineSeparator(main_body-1)))
2847 for (LyXParagraph::size_type vpos = row->pos();
2848 vpos < cursor_vpos; ++vpos) {
2849 pos = vis2log(vpos);
2850 if (main_body > 0 && pos == main_body - 1) {
2851 x += fill_label_hfill +
2852 lyxfont::width(textclasslist.Style(
2853 bview->buffer()->params.textclass,
2854 row->par()->GetLayout())
2856 GetFont(bview->buffer(), row->par(), -2));
2857 if (row->par()->IsLineSeparator(main_body-1))
2858 x -= SingleWidth(bview, row->par(),main_body-1);
2860 if (HfillExpansion(bview->buffer(), row, pos)) {
2861 x += SingleWidth(bview, row->par(), pos);
2862 if (pos >= main_body)
2865 x += fill_label_hfill;
2866 } else if (row->par()->IsSeparator(pos)) {
2867 x += SingleWidth(bview, row->par(), pos);
2868 if (pos >= main_body)
2869 x += fill_separator;
2871 x += SingleWidth(bview, row->par(), pos);
2880 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2881 LyXParagraph::size_type pos,
2882 bool setfont, bool boundary) const
2884 SetCursor(bview, cursor, par, pos, boundary);
2886 SetCurrentFont(bview);
2890 void LyXText::SetCurrentFont(BufferView * bview) const
2892 LyXParagraph::size_type pos = cursor.pos();
2893 if (cursor.boundary() && pos > 0)
2897 if (pos == cursor.par()->Last())
2899 else if (cursor.par()->IsSeparator(pos)) {
2900 if (pos > cursor.row()->pos() &&
2901 bidi_level(pos) % 2 ==
2902 bidi_level(pos - 1) % 2)
2904 else if (pos + 1 < cursor.par()->Last())
2910 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2911 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2913 if (cursor.pos() == cursor.par()->Last() &&
2914 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2915 !cursor.boundary()) {
2916 Language const * lang =
2917 cursor.par()->getParLanguage(bview->buffer()->params);
2918 current_font.setLanguage(lang);
2919 real_current_font.setLanguage(lang);
2924 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2926 LyXCursor old_cursor = cursor;
2928 /* get the row first */
2930 Row * row = GetRowNearY(y);
2931 cursor.par(row->par());
2934 int column = GetColumnNearX(bview, row, x, bound);
2935 cursor.pos(row->pos() + column);
2937 cursor.y(y + row->baseline());
2939 cursor.boundary(bound);
2940 SetCurrentFont(bview);
2941 DeleteEmptyParagraphMechanism(bview, old_cursor);
2945 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2948 /* get the row first */
2950 Row * row = GetRowNearY(y);
2952 int column = GetColumnNearX(bview, row, x, bound);
2954 cur.par(row->par());
2955 cur.pos(row->pos() + column);
2957 cur.y(y + row->baseline());
2959 cur.boundary(bound);
2963 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2965 if (cursor.pos() > 0) {
2966 bool boundary = cursor.boundary();
2967 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2968 if (!internal && !boundary &&
2969 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2970 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2971 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2972 LyXParagraph * par = cursor.par()->Previous();
2973 SetCursor(bview, par, par->Last());
2978 void LyXText::CursorRight(BufferView * bview, bool internal) const
2980 if (!internal && cursor.boundary() &&
2981 !cursor.par()->IsNewline(cursor.pos()))
2982 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2983 else if (cursor.pos() < cursor.par()->Last()) {
2984 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2986 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2987 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2988 } else if (cursor.par()->Next())
2989 SetCursor(bview, cursor.par()->Next(), 0);
2993 void LyXText::CursorUp(BufferView * bview) const
2995 SetCursorFromCoordinates(bview, cursor.x_fix(),
2996 cursor.y() - cursor.row()->baseline() - 1);
3000 void LyXText::CursorDown(BufferView * bview) const
3002 SetCursorFromCoordinates(bview, cursor.x_fix(),
3003 cursor.y() - cursor.row()->baseline()
3004 + cursor.row()->height() + 1);
3008 void LyXText::CursorUpParagraph(BufferView * bview) const
3010 if (cursor.pos() > 0) {
3011 SetCursor(bview, cursor.par(), 0);
3013 else if (cursor.par()->Previous()) {
3014 SetCursor(bview, cursor.par()->Previous(), 0);
3019 void LyXText::CursorDownParagraph(BufferView * bview) const
3021 if (cursor.par()->Next()) {
3022 SetCursor(bview, cursor.par()->Next(), 0);
3024 SetCursor(bview, cursor.par(), cursor.par()->Last());
3029 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3030 LyXCursor const & old_cursor) const
3032 // Would be wrong to delete anything if we have a selection.
3033 if (selection) return;
3035 // We allow all kinds of "mumbo-jumbo" when freespacing.
3036 if (textclasslist.Style(bview->buffer()->params.textclass,
3037 old_cursor.par()->GetLayout()).free_spacing)
3040 bool deleted = false;
3042 /* Ok I'll put some comments here about what is missing.
3043 I have fixed BackSpace (and thus Delete) to not delete
3044 double-spaces automagically. I have also changed Cut,
3045 Copy and Paste to hopefully do some sensible things.
3046 There are still some small problems that can lead to
3047 double spaces stored in the document file or space at
3048 the beginning of paragraphs. This happens if you have
3049 the cursor betwenn to spaces and then save. Or if you
3050 cut and paste and the selection have a space at the
3051 beginning and then save right after the paste. I am
3052 sure none of these are very hard to fix, but I will
3053 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3054 that I can get some feedback. (Lgb)
3057 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3058 // delete the LineSeparator.
3061 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3062 // delete the LineSeparator.
3065 // If the pos around the old_cursor were spaces, delete one of them.
3066 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3067 // Only if the cursor has really moved
3069 if (old_cursor.pos() > 0
3070 && old_cursor.pos() < old_cursor.par()->Last()
3071 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3072 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3073 old_cursor.par()->Erase(old_cursor.pos() - 1);
3074 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3076 if (old_cursor.par() == cursor.par() &&
3077 cursor.pos() > old_cursor.pos()) {
3078 SetCursorIntern(bview, cursor.par(),
3081 SetCursorIntern(bview, cursor.par(),
3087 // Do not delete empty paragraphs with keepempty set.
3088 if ((textclasslist.Style(bview->buffer()->params.textclass,
3089 old_cursor.par()->GetLayout())).keepempty)
3092 LyXCursor tmpcursor;
3094 if (old_cursor.par() != cursor.par()) {
3095 if ( (old_cursor.par()->Last() == 0
3096 || (old_cursor.par()->Last() == 1
3097 && old_cursor.par()->IsLineSeparator(0)))
3099 && old_cursor.par()->FirstPhysicalPar()
3100 == old_cursor.par()->LastPhysicalPar()
3103 // ok, we will delete anything
3105 // make sure that you do not delete any environments
3108 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3109 !(old_cursor.row()->previous()
3110 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3111 && !(old_cursor.row()->next()
3112 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3113 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3114 && ((old_cursor.row()->previous()
3115 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3116 || (old_cursor.row()->next()
3117 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3120 status = LyXText::NEED_MORE_REFRESH;
3123 if (old_cursor.row()->previous()) {
3124 refresh_row = old_cursor.row()->previous();
3125 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3127 cursor = old_cursor; // that undo can restore the right cursor position
3128 LyXParagraph * endpar = old_cursor.par()->next;
3129 if (endpar && endpar->GetDepth()) {
3130 while (endpar && endpar->GetDepth()) {
3132 endpar = endpar->LastPhysicalPar()->Next();
3134 endpar = endpar->Next();
3138 SetUndo(bview->buffer(), Undo::DELETE,
3139 old_cursor.par()->previous,
3144 RemoveRow(old_cursor.row());
3145 if (OwnerParagraph() == old_cursor.par()) {
3146 OwnerParagraph(OwnerParagraph()->next);
3149 delete old_cursor.par();
3151 /* Breakagain the next par. Needed
3152 * because of the parindent that
3153 * can occur or dissappear. The
3154 * next row can change its height,
3155 * if there is another layout before */
3156 if (refresh_row->next()) {
3157 BreakAgain(bview, refresh_row->next());
3158 UpdateCounters(bview, refresh_row);
3160 SetHeightOfRow(bview, refresh_row);
3162 refresh_row = old_cursor.row()->next();
3163 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3166 cursor = old_cursor; // that undo can restore the right cursor position
3167 LyXParagraph * endpar = old_cursor.par()->next;
3168 if (endpar && endpar->GetDepth()) {
3169 while (endpar && endpar->GetDepth()) {
3171 endpar = endpar->LastPhysicalPar()->Next();
3173 endpar = endpar->Next();
3177 SetUndo(bview->buffer(), Undo::DELETE,
3178 old_cursor.par()->previous,
3183 RemoveRow(old_cursor.row());
3185 if (OwnerParagraph() == old_cursor.par()) {
3186 OwnerParagraph(OwnerParagraph()->next);
3188 delete old_cursor.par();
3190 /* Breakagain the next par. Needed
3191 because of the parindent that can
3192 occur or dissappear.
3193 The next row can change its height,
3194 if there is another layout before
3197 BreakAgain(bview, refresh_row);
3198 UpdateCounters(bview, refresh_row->previous());
3204 SetCursorIntern(bview, cursor.par(), cursor.pos());
3206 if (sel_cursor.par() == old_cursor.par()
3207 && sel_cursor.pos() == sel_cursor.pos()) {
3208 // correct selection
3209 sel_cursor = cursor;
3216 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3217 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3219 SetCursorIntern(bview, cursor.par(), cursor.pos());
3220 sel_cursor = cursor;
3227 LyXParagraph * LyXText::GetParFromID(int id)
3229 LyXParagraph * result = FirstParagraph();
3230 while (result && result->id() != id)
3231 result = result->next;
3237 bool LyXText::TextUndo(BufferView * bview)
3241 // returns false if no undo possible
3242 Undo * undo = bview->buffer()->undostack.pop();
3246 bview->buffer()->redostack
3247 .push(CreateUndo(bview->buffer(), undo->kind,
3248 GetParFromID(undo->number_of_before_par),
3249 GetParFromID(undo->number_of_behind_par)));
3251 return TextHandleUndo(bview, undo);
3255 bool LyXText::TextRedo(BufferView * bview)
3259 // returns false if no redo possible
3260 Undo * undo = bview->buffer()->redostack.pop();
3264 bview->buffer()->undostack
3265 .push(CreateUndo(bview->buffer(), undo->kind,
3266 GetParFromID(undo->number_of_before_par),
3267 GetParFromID(undo->number_of_behind_par)));
3269 return TextHandleUndo(bview, undo);
3273 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3277 // returns false if no undo possible
3278 bool result = false;
3280 LyXParagraph * before =
3281 GetParFromID(undo->number_of_before_par);
3282 LyXParagraph * behind =
3283 GetParFromID(undo->number_of_behind_par);
3284 LyXParagraph * tmppar;
3285 LyXParagraph * tmppar2;
3286 LyXParagraph * endpar;
3287 LyXParagraph * tmppar5;
3289 // if there's no before take the beginning
3290 // of the document for redoing
3292 SetCursorIntern(bview, FirstParagraph(), 0);
3294 // replace the paragraphs with the undo informations
3296 LyXParagraph * tmppar3 = undo->par;
3297 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3298 LyXParagraph * tmppar4 = tmppar3;
3300 while (tmppar4->next)
3301 tmppar4 = tmppar4->next;
3302 } // get last undo par
3304 // now remove the old text if there is any
3305 if (before != behind || (!behind && !before)){
3307 tmppar5 = before->next;
3309 tmppar5 = OwnerParagraph();
3311 while (tmppar5 && tmppar5 != behind){
3313 tmppar5 = tmppar5->next;
3314 // a memory optimization for edit: Only layout information
3315 // is stored in the undo. So restore the text informations.
3316 if (undo->kind == Undo::EDIT) {
3317 tmppar2->setContentsFromPar(tmppar);
3318 tmppar->clearContents();
3319 tmppar2 = tmppar2->next;
3324 // put the new stuff in the list if there is one
3327 before->next = tmppar3;
3329 OwnerParagraph(tmppar3);
3330 tmppar3->previous = before;
3333 OwnerParagraph(behind);
3336 tmppar4->next = behind;
3338 behind->previous = tmppar4;
3342 // Set the cursor for redoing
3345 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3347 SetCursorIntern(bview, before, 0);
3350 // check wether before points to a closed float and open it if necessary
3351 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3352 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3354 while (tmppar4->previous &&
3355 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3356 tmppar4 = tmppar4->previous;
3357 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3358 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3359 tmppar4 = tmppar4->next;
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;
3377 // calculate the endpar for redoing the paragraphs.
3380 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3381 endpar = behind->LastPhysicalPar()->Next();
3383 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3385 endpar = behind->Next();
3390 tmppar = GetParFromID(undo->number_of_cursor_par);
3391 RedoParagraphs(bview, cursor, endpar);
3393 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3394 UpdateCounters(bview, cursor.row());
3404 void LyXText::FinishUndo()
3408 // makes sure the next operation will be stored
3409 undo_finished = true;
3413 void LyXText::FreezeUndo()
3417 // this is dangerous and for internal use only
3422 void LyXText::UnFreezeUndo()
3426 // this is dangerous and for internal use only
3427 undo_frozen = false;
3431 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3432 LyXParagraph const * before,
3433 LyXParagraph const * behind) const
3438 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3439 buf->redostack.clear();
3443 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3444 LyXParagraph const * before, LyXParagraph const * behind)
3448 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3452 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3453 LyXParagraph const * before,
3454 LyXParagraph const * behind) const
3459 int before_number = -1;
3460 int behind_number = -1;
3462 before_number = before->id();
3464 behind_number = behind->id();
3465 // Undo::EDIT and Undo::FINISH are
3466 // always finished. (no overlapping there)
3467 // overlapping only with insert and delete inside one paragraph:
3468 // Nobody wants all removed character
3469 // appear one by one when undoing.
3470 // EDIT is special since only layout information, not the
3471 // contents of a paragaph are stored.
3472 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3473 // check wether storing is needed
3474 if (!buf->undostack.empty() &&
3475 buf->undostack.top()->kind == kind &&
3476 buf->undostack.top()->number_of_before_par == before_number &&
3477 buf->undostack.top()->number_of_behind_par == behind_number ){
3482 // create a new Undo
3483 LyXParagraph * undopar;
3484 LyXParagraph * tmppar;
3485 LyXParagraph * tmppar2;
3487 LyXParagraph * start = 0;
3488 LyXParagraph * end = 0;
3491 start = before->next;
3493 start = FirstParagraph();
3495 end = behind->previous;
3497 end = FirstParagraph();
3503 && start != end->next
3504 && (before != behind || (!before && !behind))) {
3506 tmppar2 = tmppar->Clone();
3507 tmppar2->id(tmppar->id());
3509 // a memory optimization: Just store the layout information
3511 if (kind == Undo::EDIT){
3512 //tmppar2->text.clear();
3513 tmppar2->clearContents();
3518 while (tmppar != end && tmppar->next) {
3519 tmppar = tmppar->next;
3520 tmppar2->next = tmppar->Clone();
3521 tmppar2->next->id(tmppar->id());
3522 // a memory optimization: Just store the layout
3523 // information when only edit
3524 if (kind == Undo::EDIT){
3525 //tmppar2->next->text.clear();
3526 tmppar2->clearContents();
3528 tmppar2->next->previous = tmppar2;
3529 tmppar2 = tmppar2->next;
3533 undopar = 0; // nothing to replace (undo of delete maybe)
3536 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3537 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3539 int cursor_par = cursor.par()->id();
3540 int cursor_pos = cursor.pos();
3543 Undo * undo = new Undo(kind,
3544 before_number, behind_number,
3545 cursor_par, cursor_pos,
3548 undo_finished = false;
3553 void LyXText::SetCursorParUndo(Buffer * buf)
3557 SetUndo(buf, Undo::FINISH,
3559 cursor.par()->ParFromPos(cursor.pos())->previous,
3560 cursor.par()->ParFromPos(cursor.pos())->next
3562 cursor.par()->previous,
3569 void LyXText::toggleAppendix(BufferView * bview)
3572 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3574 LyXParagraph * par = cursor.par();
3576 bool start = !par->start_of_appendix;
3578 // ensure that we have only one start_of_appendix in this document
3579 LyXParagraph * tmp = FirstParagraph();
3580 for (; tmp; tmp = tmp->next)
3581 tmp->start_of_appendix = 0;
3582 par->start_of_appendix = start;
3584 // we can set the refreshing parameters now
3585 status = LyXText::NEED_MORE_REFRESH;
3587 refresh_row = 0; // not needed for full update
3588 UpdateCounters(bview, 0);
3589 SetCursor(bview, cursor.par(), cursor.pos());
3593 LyXParagraph * LyXText::OwnerParagraph() const
3596 return inset_owner->par;
3598 return bv_owner->buffer()->paragraph;
3602 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3605 inset_owner->par = p;
3607 bv_owner->buffer()->paragraph = p;