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,
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,
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
1207 status = LyXText::NEED_MORE_REFRESH;
1213 void LyXText::CursorHome(BufferView * bview) const
1215 SetCursor(bview, cursor.par(), cursor.row()->pos());
1219 void LyXText::CursorEnd(BufferView * bview) const
1221 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1222 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1224 if (cursor.par()->Last() &&
1225 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1226 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1227 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1229 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1234 void LyXText::CursorTop(BufferView * bview) const
1236 while (cursor.par()->Previous())
1237 cursor.par(cursor.par()->Previous());
1238 SetCursor(bview, cursor.par(), 0);
1242 void LyXText::CursorBottom(BufferView * bview) const
1244 while (cursor.par()->Next())
1245 cursor.par(cursor.par()->Next());
1246 SetCursor(bview, cursor.par(), cursor.par()->Last());
1250 /* returns a pointer to the row near the specified y-coordinate
1251 * (relative to the whole text). y is set to the real beginning
1253 Row * LyXText::GetRowNearY(int & y) const
1255 Row * tmprow = firstrow;
1258 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1259 tmpy += tmprow->height();
1260 tmprow = tmprow->next();
1263 y = tmpy; // return the real y
1268 void LyXText::ToggleFree(BufferView * bview,
1269 LyXFont const & font, bool toggleall)
1271 // If the mask is completely neutral, tell user
1272 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1273 // Could only happen with user style
1274 bview->owner()->getMiniBuffer()
1275 ->Set(_("No font change defined. Use Character under"
1276 " the Layout menu to define font change."));
1280 // Try implicit word selection
1281 // If there is a change in the language the implicit word selection
1283 LyXCursor resetCursor = cursor;
1284 bool implicitSelection = (font.language() == ignore_language
1285 && font.number() == LyXFont::IGNORE)
1286 ? SelectWordWhenUnderCursor(bview) : false;
1289 SetFont(bview, font, toggleall);
1291 /* Implicit selections are cleared afterwards and cursor is set to the
1292 original position. */
1293 if (implicitSelection) {
1295 cursor = resetCursor;
1296 SetCursor(bview, cursor.par(), cursor.pos());
1297 sel_cursor = cursor;
1302 LyXParagraph::size_type
1303 LyXText::BeginningOfMainBody(Buffer const * buf,
1304 LyXParagraph const * par) const
1306 if (textclasslist.Style(buf->params.textclass,
1307 par->GetLayout()).labeltype != LABEL_MANUAL)
1310 return par->BeginningOfMainBody();
1315 /* if there is a selection, reset every environment you can find
1316 * in the selection, otherwise just the environment you are in */
1317 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1319 LyXParagraph * tmppar, * firsttmppar;
1323 /* is is only allowed, if the cursor is IN an open footnote.
1324 * Otherwise it is too dangerous */
1325 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1328 SetUndo(bview->buffer(), Undo::FINISH,
1329 cursor.par()->PreviousBeforeFootnote()->previous,
1330 cursor.par()->NextAfterFootnote()->next);
1332 /* ok, move to the beginning of the footnote. */
1333 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1334 cursor.par(cursor.par()->Previous());
1336 SetCursor(bview, cursor.par(), cursor.par()->Last());
1337 /* this is just faster than using CursorLeft(); */
1339 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1340 tmppar = firsttmppar;
1341 /* tmppar is now the paragraph right before the footnote */
1343 bool first_footnote_par_is_not_empty = tmppar->next->size();
1346 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1347 tmppar = tmppar->next; /* I use next instead of Next(),
1348 * because there cannot be any
1349 * footnotes in a footnote
1351 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1353 /* remember the captions and empty paragraphs */
1354 if ((textclasslist.Style(bview->buffer()->params.textclass,
1355 tmppar->GetLayout())
1356 .labeltype == LABEL_SENSITIVE)
1358 tmppar->SetLayout(bview->buffer()->params, 0);
1361 // now we will paste the ex-footnote, if the layouts allow it
1362 // first restore the layout of the paragraph right behind
1365 tmppar->next->MakeSameLayout(cursor.par());
1368 if (!tmppar->GetLayout()
1370 && (!tmppar->Next()->Last()
1371 || tmppar->Next()->HasSameLayout(tmppar)))) {
1372 if (tmppar->Next()->Last()
1373 && tmppar->Next()->IsLineSeparator(0))
1374 tmppar->Next()->Erase(0);
1375 tmppar->PasteParagraph(bview->buffer()->params);
1378 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1379 * by the pasting of the beginning */
1381 /* then the beginning */
1382 /* if there is no space between the text and the footnote, so we insert
1384 * (only if the previous par and the footnotepar are not empty!) */
1385 if (!firsttmppar->next->GetLayout()
1386 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1387 if (firsttmppar->size()
1388 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1389 && first_footnote_par_is_not_empty) {
1390 firsttmppar->next->InsertChar(0, ' ');
1392 firsttmppar->PasteParagraph(bview->buffer()->params);
1395 /* now redo the paragaphs */
1396 RedoParagraphs(bview, cursor, tmppar);
1398 SetCursor(bview, cursor.par(), cursor.pos());
1400 /* sometimes it can happen, that there is a counter change */
1401 Row * row = cursor.row();
1402 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1404 UpdateCounters(bview, row);
1412 /* the DTP switches for paragraphs. LyX will store them in the
1413 * first physicla paragraph. When a paragraph is broken, the top settings
1414 * rest, the bottom settings are given to the new one. So I can make shure,
1415 * they do not duplicate themself and you cannnot make dirty things with
1418 void LyXText::SetParagraph(BufferView * bview,
1419 bool line_top, bool line_bottom,
1420 bool pagebreak_top, bool pagebreak_bottom,
1421 VSpace const & space_top,
1422 VSpace const & space_bottom,
1424 string labelwidthstring,
1427 LyXCursor tmpcursor = cursor;
1429 sel_start_cursor = cursor;
1430 sel_end_cursor = cursor;
1433 // make sure that the depth behind the selection are restored, too
1435 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1437 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1439 LyXParagraph * undoendpar = endpar;
1441 if (endpar && endpar->GetDepth()) {
1442 while (endpar && endpar->GetDepth()) {
1444 endpar = endpar->LastPhysicalPar()->Next();
1446 endpar = endpar->Next();
1448 undoendpar = endpar;
1452 endpar = endpar->Next(); // because of parindents etc.
1455 SetUndo(bview->buffer(), Undo::EDIT,
1458 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1460 sel_start_cursor.par()->previous,
1465 LyXParagraph * tmppar = sel_end_cursor.par();
1467 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1468 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1470 while (tmppar != sel_start_cursor.par()->Previous()) {
1471 SetCursor(bview, tmppar, 0);
1473 status = LyXText::NEED_MORE_REFRESH;
1474 refresh_row = cursor.row();
1475 refresh_y = cursor.y() - cursor.row()->baseline();
1477 if (cursor.par()->footnoteflag ==
1478 sel_start_cursor.par()->footnoteflag) {
1480 cursor.par()->line_top = line_top;
1481 cursor.par()->line_bottom = line_bottom;
1482 cursor.par()->pagebreak_top = pagebreak_top;
1483 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1484 cursor.par()->added_space_top = space_top;
1485 cursor.par()->added_space_bottom = space_bottom;
1486 // does the layout allow the new alignment?
1487 if (align == LYX_ALIGN_LAYOUT)
1488 align = textclasslist
1489 .Style(bview->buffer()->params.textclass,
1490 cursor.par()->GetLayout()).align;
1491 if (align & textclasslist
1492 .Style(bview->buffer()->params.textclass,
1493 cursor.par()->GetLayout()).alignpossible) {
1494 if (align == textclasslist
1495 .Style(bview->buffer()->params.textclass,
1496 cursor.par()->GetLayout()).align)
1497 cursor.par()->align = LYX_ALIGN_LAYOUT;
1499 cursor.par()->align = align;
1501 cursor.par()->SetLabelWidthString(labelwidthstring);
1502 cursor.par()->noindent = noindent;
1506 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1508 tmppar = cursor.par()->Previous();
1512 RedoParagraphs(bview, sel_start_cursor, endpar);
1515 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1516 sel_cursor = cursor;
1517 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1519 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1521 bview->updateInset(inset_owner, true);
1525 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1526 string const & width,
1527 string const & widthp,
1528 int alignment, bool hfill,
1529 bool start_minipage)
1531 LyXCursor tmpcursor = cursor;
1532 LyXParagraph * tmppar;
1534 sel_start_cursor = cursor;
1535 sel_end_cursor = cursor;
1538 // make sure that the depth behind the selection are restored, too
1540 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1542 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1544 LyXParagraph * undoendpar = endpar;
1546 if (endpar && endpar->GetDepth()) {
1547 while (endpar && endpar->GetDepth()) {
1549 endpar = endpar->LastPhysicalPar()->Next();
1551 endpar = endpar->Next();
1553 undoendpar = endpar;
1557 endpar = endpar->Next(); // because of parindents etc.
1560 SetUndo(bview->buffer(), Undo::EDIT,
1563 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1565 sel_start_cursor.par()->previous,
1569 tmppar = sel_end_cursor.par();
1571 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1572 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1574 while(tmppar != sel_start_cursor.par()->Previous()) {
1575 SetCursor(bview, tmppar, 0);
1577 status = LyXText::NEED_MORE_REFRESH;
1578 refresh_row = cursor.row();
1579 refresh_y = cursor.y() - cursor.row()->baseline();
1581 if (cursor.par()->footnoteflag ==
1582 sel_start_cursor.par()->footnoteflag) {
1584 if (type == LyXParagraph::PEXTRA_NONE) {
1585 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1586 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1587 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1590 cursor.par()->SetPExtraType(bview->buffer()->params,
1591 type, width, widthp);
1592 cursor.par()->pextra_hfill = hfill;
1593 cursor.par()->pextra_start_minipage = start_minipage;
1594 cursor.par()->pextra_alignment = alignment;
1598 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1600 tmppar = cursor.par()->Previous();
1603 RedoParagraphs(bview, sel_start_cursor, endpar);
1605 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1606 sel_cursor = cursor;
1607 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1609 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1613 char loweralphaCounter(int n)
1615 if (n < 1 || n > 26)
1623 char alphaCounter(int n)
1625 if (n < 1 || n > 26)
1633 char hebrewCounter(int n)
1635 static const char hebrew[22] = {
1636 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1637 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1638 '÷', 'ø', 'ù', 'ú'
1640 if (n < 1 || n > 22)
1648 string const romanCounter(int n)
1650 static char const * roman[20] = {
1651 "i", "ii", "iii", "iv", "v",
1652 "vi", "vii", "viii", "ix", "x",
1653 "xi", "xii", "xiii", "xiv", "xv",
1654 "xvi", "xvii", "xviii", "xix", "xx"
1656 if (n < 1 || n > 20)
1663 // set the counter of a paragraph. This includes the labels
1664 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1667 // this is only relevant for the beginning of paragraph
1668 par = par->FirstPhysicalPar();
1670 LyXLayout const & layout =
1671 textclasslist.Style(buf->params.textclass,
1674 LyXTextClass const & textclass =
1675 textclasslist.TextClass(buf->params.textclass);
1677 /* copy the prev-counters to this one, unless this is the start of a
1678 footnote or of a bibliography or the very first paragraph */
1681 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1682 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1683 && par->footnotekind == LyXParagraph::FOOTNOTE)
1685 && !(textclasslist.Style(buf->params.textclass,
1686 par->Previous()->GetLayout()
1687 ).labeltype != LABEL_BIBLIO
1688 && layout.labeltype == LABEL_BIBLIO)) {
1689 for (int i = 0; i < 10; ++i) {
1690 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1693 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1695 par->appendix = par->Previous()->appendix;
1697 if (!par->appendix && par->start_of_appendix){
1698 par->appendix = true;
1699 for (int i = 0; i < 10; ++i) {
1700 par->setCounter(i, 0);
1704 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1705 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1707 par->enumdepth = par->Previous()->enumdepth;
1708 par->itemdepth = par->Previous()->itemdepth;
1711 for (int i = 0; i < 10; ++i) {
1712 par->setCounter(i, 0);
1714 par->appendix = par->start_of_appendix;
1720 // if this is an open marginnote and this is the first
1721 // entry in the marginnote and the enclosing
1722 // environment is an enum/item then correct for the
1723 // LaTeX behaviour (ARRae)
1724 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1725 && par->footnotekind == LyXParagraph::MARGIN
1727 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1728 && (par->PreviousBeforeFootnote()
1729 && textclasslist.Style(buf->params.textclass,
1730 par->PreviousBeforeFootnote()->GetLayout()
1731 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1732 // Any itemize or enumerate environment in a marginnote
1733 // that is embedded in an itemize or enumerate
1734 // paragraph is seen by LaTeX as being at a deeper
1735 // level within that enclosing itemization/enumeration
1736 // even if there is a "standard" layout at the start of
1742 /* Maybe we have to increment the enumeration depth.
1743 * BUT, enumeration in a footnote is considered in isolation from its
1744 * surrounding paragraph so don't increment if this is the
1745 * first line of the footnote
1746 * AND, bibliographies can't have their depth changed ie. they
1747 * are always of depth 0
1750 && par->Previous()->GetDepth() < par->GetDepth()
1751 && textclasslist.Style(buf->params.textclass,
1752 par->Previous()->GetLayout()
1753 ).labeltype == LABEL_COUNTER_ENUMI
1754 && par->enumdepth < 3
1756 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1757 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1758 && par->footnotekind == LyXParagraph::FOOTNOTE)
1760 && layout.labeltype != LABEL_BIBLIO) {
1764 /* Maybe we have to decrement the enumeration depth, see note above */
1766 && par->Previous()->GetDepth() > par->GetDepth()
1768 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1769 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1770 && par->footnotekind == LyXParagraph::FOOTNOTE)
1772 && layout.labeltype != LABEL_BIBLIO) {
1773 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1774 par->setCounter(6 + par->enumdepth,
1775 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1776 /* reset the counters.
1777 * A depth change is like a breaking layout
1779 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1780 par->setCounter(i, 0);
1783 if (!par->labelstring.empty()) {
1784 par->labelstring.erase();
1787 if (layout.margintype == MARGIN_MANUAL) {
1788 if (par->labelwidthstring.empty()) {
1789 par->SetLabelWidthString(layout.labelstring());
1792 par->SetLabelWidthString(string());
1795 /* is it a layout that has an automatic label ? */
1796 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1798 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1799 if (i >= 0 && i<= buf->params.secnumdepth) {
1800 par->incCounter(i); // increment the counter
1802 // Is there a label? Useful for Chapter layout
1803 if (!par->appendix){
1804 if (!layout.labelstring().empty())
1805 par->labelstring = layout.labelstring();
1807 par->labelstring.erase();
1809 if (!layout.labelstring_appendix().empty())
1810 par->labelstring = layout.labelstring_appendix();
1812 par->labelstring.erase();
1815 std::ostringstream s;
1817 if (!par->appendix) {
1818 switch (2 * LABEL_COUNTER_CHAPTER -
1819 textclass.maxcounter() + i) {
1820 case LABEL_COUNTER_CHAPTER:
1821 s << par->getCounter(i);
1823 case LABEL_COUNTER_SECTION:
1824 s << par->getCounter(i - 1) << '.'
1825 << par->getCounter(i);
1827 case LABEL_COUNTER_SUBSECTION:
1828 s << par->getCounter(i - 2) << '.'
1829 << par->getCounter(i - 1) << '.'
1830 << par->getCounter(i);
1832 case LABEL_COUNTER_SUBSUBSECTION:
1833 s << par->getCounter(i - 3) << '.'
1834 << par->getCounter(i - 2) << '.'
1835 << par->getCounter(i - 1) << '.'
1836 << par->getCounter(i);
1839 case LABEL_COUNTER_PARAGRAPH:
1840 s << par->getCounter(i - 4) << '.'
1841 << par->getCounter(i - 3) << '.'
1842 << par->getCounter(i - 2) << '.'
1843 << par->getCounter(i - 1) << '.'
1844 << par->getCounter(i);
1846 case LABEL_COUNTER_SUBPARAGRAPH:
1847 s << par->getCounter(i - 5) << '.'
1848 << par->getCounter(i - 4) << '.'
1849 << par->getCounter(i - 3) << '.'
1850 << par->getCounter(i - 2) << '.'
1851 << par->getCounter(i - 1) << '.'
1852 << par->getCounter(i);
1856 // Can this ever be reached? And in the
1857 // case it is, how can this be correct?
1859 s << par->getCounter(i) << '.';
1862 } else { // appendix
1863 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1864 case LABEL_COUNTER_CHAPTER:
1865 if (par->isRightToLeftPar(buf->params))
1866 s << hebrewCounter(par->getCounter(i));
1868 s << alphaCounter(par->getCounter(i));
1870 case LABEL_COUNTER_SECTION:
1871 if (par->isRightToLeftPar(buf->params))
1872 s << hebrewCounter(par->getCounter(i - 1));
1874 s << alphaCounter(par->getCounter(i - 1));
1877 << par->getCounter(i);
1880 case LABEL_COUNTER_SUBSECTION:
1881 if (par->isRightToLeftPar(buf->params))
1882 s << hebrewCounter(par->getCounter(i - 2));
1884 s << alphaCounter(par->getCounter(i - 2));
1887 << par->getCounter(i-1) << '.'
1888 << par->getCounter(i);
1891 case LABEL_COUNTER_SUBSUBSECTION:
1892 if (par->isRightToLeftPar(buf->params))
1893 s << hebrewCounter(par->getCounter(i-3));
1895 s << alphaCounter(par->getCounter(i-3));
1898 << par->getCounter(i-2) << '.'
1899 << par->getCounter(i-1) << '.'
1900 << par->getCounter(i);
1903 case LABEL_COUNTER_PARAGRAPH:
1904 if (par->isRightToLeftPar(buf->params))
1905 s << hebrewCounter(par->getCounter(i-4));
1907 s << alphaCounter(par->getCounter(i-4));
1910 << par->getCounter(i-3) << '.'
1911 << par->getCounter(i-2) << '.'
1912 << par->getCounter(i-1) << '.'
1913 << par->getCounter(i);
1916 case LABEL_COUNTER_SUBPARAGRAPH:
1917 if (par->isRightToLeftPar(buf->params))
1918 s << hebrewCounter(par->getCounter(i-5));
1920 s << alphaCounter(par->getCounter(i-5));
1923 << par->getCounter(i-4) << '.'
1924 << par->getCounter(i-3) << '.'
1925 << par->getCounter(i-2) << '.'
1926 << par->getCounter(i-1) << '.'
1927 << par->getCounter(i);
1931 // Can this ever be reached? And in the
1932 // case it is, how can this be correct?
1934 s << par->getCounter(i) << '.';
1940 par->labelstring += s.str().c_str();
1941 // We really want to remove the c_str as soon as
1944 for (i++; i < 10; ++i) {
1945 // reset the following counters
1946 par->setCounter(i, 0);
1948 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1949 for (i++; i < 10; ++i) {
1950 // reset the following counters
1951 par->setCounter(i, 0);
1953 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1954 par->incCounter(i + par->enumdepth);
1955 int number = par->getCounter(i + par->enumdepth);
1957 std::ostringstream s;
1959 switch (par->enumdepth) {
1961 if (par->isRightToLeftPar(buf->params))
1963 << hebrewCounter(number)
1967 << loweralphaCounter(number)
1971 if (par->isRightToLeftPar(buf->params))
1972 s << '.' << romanCounter(number);
1974 s << romanCounter(number) << '.';
1977 if (par->isRightToLeftPar(buf->params))
1979 << alphaCounter(number);
1981 s << alphaCounter(number)
1985 if (par->isRightToLeftPar(buf->params))
1992 par->labelstring = s.str().c_str();
1993 // we really want to get rid of that c_str()
1995 for (i += par->enumdepth + 1; i < 10; ++i)
1996 par->setCounter(i, 0); /* reset the following counters */
1999 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2000 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2002 int number = par->getCounter(i);
2004 InsetCommandParams p( "bibitem" );
2005 par->bibkey = new InsetBibKey(p);
2007 par->bibkey->setCounter(number);
2008 par->labelstring = layout.labelstring();
2010 // In biblio should't be following counters but...
2012 string s = layout.labelstring();
2014 // the caption hack:
2015 if (layout.labeltype == LABEL_SENSITIVE) {
2016 bool isOK (par->InInset() && par->InInset()->owner() &&
2017 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2019 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2020 && (par->footnotekind == LyXParagraph::FIG
2021 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2022 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2023 ? ":øåéà " : "Figure:";
2024 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2025 && (par->footnotekind == LyXParagraph::TAB
2026 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2027 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2028 ? ":äìáè" : "Table:";
2029 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2030 && par->footnotekind == LyXParagraph::ALGORITHM) {
2031 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2032 ? ":Ãúéøåâìà " : "Algorithm:";
2036 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2038 = floatList.getType(tmp->type());
2039 // We should get the correct number here too.
2040 s = fl.name + " #:";
2042 /* par->SetLayout(0);
2043 s = layout->labelstring; */
2044 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2045 ? " :úåòîùî øñç" : "Senseless: ";
2048 par->labelstring = s;
2050 /* reset the enumeration counter. They are always resetted
2051 * when there is any other layout between */
2052 for (int i = 6 + par->enumdepth; i < 10; ++i)
2053 par->setCounter(i, 0);
2058 /* Updates all counters BEHIND the row. Changed paragraphs
2059 * with a dynamic left margin will be rebroken. */
2060 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2067 if (row->par()->next
2069 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2073 par = row->par()->LastPhysicalPar()->Next();
2075 par = row->par()->Next();
2078 par = row->par()->next;
2083 while (row->par() != par)
2086 SetCounter(bview->buffer(), par);
2088 /* now check for the headline layouts. remember that they
2089 * have a dynamic left margin */
2094 ( textclasslist.Style(bview->buffer()->params.textclass,
2095 par->layout).margintype == MARGIN_DYNAMIC
2096 || textclasslist.Style(bview->buffer()->params.textclass,
2097 par->layout).labeltype == LABEL_SENSITIVE)
2100 /* Rebreak the paragraph */
2101 RemoveParagraph(row);
2102 AppendParagraph(bview, row);
2105 /* think about the damned open footnotes! */
2106 while (par->Next() &&
2107 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2108 || par->Next()->IsDummy())){
2110 if (par->IsDummy()) {
2111 while (row->par() != par)
2113 RemoveParagraph(row);
2114 AppendParagraph(bview, row);
2120 par = par->LastPhysicalPar()->Next();
2129 /* insets an inset. */
2130 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2132 if (!cursor.par()->InsertInsetAllowed(inset))
2134 SetUndo(bview->buffer(), Undo::INSERT,
2136 cursor.par()->ParFromPos(cursor.pos())->previous,
2137 cursor.par()->ParFromPos(cursor.pos())->next
2139 cursor.par()->previous,
2143 cursor.par()->InsertInset(cursor.pos(), inset);
2144 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2145 * The character will not be inserted a
2148 // if we enter a text-inset the cursor should be to the left side
2149 // of it! This couldn't happen before as Undo was not handled inside
2150 // inset now after the Undo LyX tries to call inset->Edit(...) again
2151 // and cannot do this as the cursor is behind the inset and GetInset
2152 // does not return the inset!
2153 if (inset->IsTextInset()) {
2154 if (cursor.par()->isRightToLeftPar(bview->buffer()->params))
2163 void LyXText::copyEnvironmentType()
2165 copylayouttype = cursor.par()->GetLayout();
2169 void LyXText::pasteEnvironmentType(BufferView * bview)
2171 SetLayout(bview, copylayouttype);
2175 void LyXText::CutSelection(BufferView * bview, bool doclear)
2177 // Stuff what we got on the clipboard. Even if there is no selection.
2179 // There is a problem with having the stuffing here in that the
2180 // larger the selection the slower LyX will get. This can be
2181 // solved by running the line below only when the selection has
2182 // finished. The solution used currently just works, to make it
2183 // faster we need to be more clever and probably also have more
2184 // calls to stuffClipboard. (Lgb)
2185 bview->stuffClipboard(selectionAsString(bview->buffer()));
2187 // This doesn't make sense, if there is no selection
2191 // OK, we have a selection. This is always between sel_start_cursor
2192 // and sel_end cursor
2194 // Check whether there are half footnotes in the selection
2195 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2196 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2197 LyXParagraph * tmppar = sel_start_cursor.par();
2198 while (tmppar != sel_end_cursor.par()){
2199 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2200 WriteAlert(_("Impossible operation"),
2201 _("Don't know what to do with half floats."),
2205 tmppar = tmppar->Next();
2210 // make sure that the depth behind the selection are restored, too
2212 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2214 LyXParagraph * endpar = sel_end_cursor.par()->Next();
2216 LyXParagraph * undoendpar = endpar;
2218 if (endpar && endpar->GetDepth()) {
2219 while (endpar && endpar->GetDepth()) {
2221 endpar = endpar->LastPhysicalPar()->Next();
2223 endpar = endpar->Next();
2225 undoendpar = endpar;
2227 } else if (endpar) {
2228 endpar = endpar->Next(); // because of parindents etc.
2231 SetUndo(bview->buffer(), Undo::DELETE,
2234 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2236 sel_start_cursor.par()->previous,
2242 // there are two cases: cut only within one paragraph or
2243 // more than one paragraph
2245 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2246 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2248 if (sel_start_cursor.par() == sel_end_cursor.par())
2251 // only within one paragraph
2252 endpar = sel_start_cursor.par();
2253 int pos = sel_end_cursor.pos();
2254 cap.cutSelection(sel_start_cursor.par(), &endpar,
2255 sel_start_cursor.pos(), pos,
2256 bview->buffer()->params.textclass, doclear);
2257 sel_end_cursor.pos(pos);
2259 endpar = sel_end_cursor.par();
2261 int pos = sel_end_cursor.pos();
2262 cap.cutSelection(sel_start_cursor.par(), &endpar,
2263 sel_start_cursor.pos(), pos,
2264 bview->buffer()->params.textclass, doclear);
2266 sel_end_cursor.par(endpar);
2267 sel_end_cursor.pos(pos);
2268 cursor.pos(sel_end_cursor.pos());
2270 endpar = endpar->Next();
2272 // sometimes necessary
2274 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2276 RedoParagraphs(bview, sel_start_cursor, endpar);
2279 cursor = sel_start_cursor;
2280 SetCursor(bview, cursor.par(), cursor.pos());
2281 sel_cursor = cursor;
2282 UpdateCounters(bview, cursor.row());
2286 void LyXText::CopySelection(BufferView * bview)
2288 // Stuff what we got on the clipboard. Even if there is no selection.
2290 // There is a problem with having the stuffing here in that the
2291 // larger the selection the slower LyX will get. This can be
2292 // solved by running the line below only when the selection has
2293 // finished. The solution used currently just works, to make it
2294 // faster we need to be more clever and probably also have more
2295 // calls to stuffClipboard. (Lgb)
2296 bview->stuffClipboard(selectionAsString(bview->buffer()));
2298 // this doesnt make sense, if there is no selection
2302 // ok we have a selection. This is always between sel_start_cursor
2303 // and sel_end cursor
2306 /* check wether there are half footnotes in the selection */
2307 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2308 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2309 LyXParagraph * tmppar = sel_start_cursor.par();
2310 while (tmppar != sel_end_cursor.par()) {
2311 if (tmppar->footnoteflag !=
2312 sel_end_cursor.par()->footnoteflag) {
2313 WriteAlert(_("Impossible operation"),
2314 _("Don't know what to do"
2315 " with half floats."),
2319 tmppar = tmppar->Next();
2324 // copy behind a space if there is one
2325 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2326 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2327 && (sel_start_cursor.par() != sel_end_cursor.par()
2328 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2329 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2333 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2334 sel_start_cursor.pos(), sel_end_cursor.pos(),
2335 bview->buffer()->params.textclass);
2339 void LyXText::PasteSelection(BufferView * bview)
2343 // this does not make sense, if there is nothing to paste
2344 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2347 SetUndo(bview->buffer(), Undo::INSERT,
2349 cursor.par()->ParFromPos(cursor.pos())->previous,
2350 cursor.par()->ParFromPos(cursor.pos())->next
2352 cursor.par()->previous,
2357 LyXParagraph * endpar;
2358 LyXParagraph * actpar = cursor.par();
2360 int pos = cursor.pos();
2361 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2363 RedoParagraphs(bview, cursor, endpar);
2365 SetCursor(bview, cursor.par(), cursor.pos());
2368 sel_cursor = cursor;
2369 SetCursor(bview, actpar, pos);
2371 UpdateCounters(bview, cursor.row());
2375 // returns a pointer to the very first LyXParagraph
2376 LyXParagraph * LyXText::FirstParagraph() const
2378 return OwnerParagraph();
2382 // returns true if the specified string is at the specified position
2383 bool LyXText::IsStringInText(LyXParagraph * par,
2384 LyXParagraph::size_type pos,
2385 string const & str) const
2390 LyXParagraph::size_type i = 0;
2391 while (pos + i < par->Last()
2392 && string::size_type(i) < str.length()
2393 && str[i] == par->GetChar(pos + i)) {
2396 if (str.length() == string::size_type(i))
2402 // sets the selection over the number of characters of string, no check!!
2403 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2405 sel_cursor = cursor;
2406 for (int i = 0; str[i]; ++i)
2412 // simple replacing. The font of the first selected character is used
2413 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2416 SetCursorParUndo(bview->buffer());
2419 if (!selection) { // create a dummy selection
2420 sel_end_cursor = cursor;
2421 sel_start_cursor = cursor;
2424 // Get font setting before we cut
2425 LyXParagraph::size_type pos = sel_end_cursor.pos();
2426 LyXFont const font = sel_start_cursor.par()
2427 ->GetFontSettings(bview->buffer()->params,
2428 sel_start_cursor.pos());
2430 // Insert the new string
2431 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2432 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2436 // Cut the selection
2437 CutSelection(bview);
2443 // if the string can be found: return true and set the cursor to
2445 bool LyXText::SearchForward(BufferView * bview, string const & str) const
2447 LyXParagraph * par = cursor.par();
2448 LyXParagraph::size_type pos = cursor.pos();
2449 while (par && !IsStringInText(par, pos, str)) {
2450 if (pos < par->Last() - 1)
2458 SetCursor(bview, par, pos);
2466 bool LyXText::SearchBackward(BufferView * bview, string const & str) const
2468 LyXParagraph * par = cursor.par();
2469 int pos = cursor.pos();
2475 // We skip empty paragraphs (Asger)
2477 par = par->Previous();
2479 pos = par->Last() - 1;
2480 } while (par && pos < 0);
2482 } while (par && !IsStringInText(par, pos, str));
2485 SetCursor(bview, par, pos);
2492 // needed to insert the selection
2493 void LyXText::InsertStringA(BufferView * bview, string const & str)
2495 LyXParagraph * par = cursor.par();
2496 LyXParagraph::size_type pos = cursor.pos();
2497 LyXParagraph::size_type a = 0;
2498 LyXParagraph * endpar = cursor.par()->Next();
2500 SetCursorParUndo(bview->buffer());
2503 textclasslist.Style(bview->buffer()->params.textclass,
2504 cursor.par()->GetLayout()).isEnvironment();
2505 // only to be sure, should not be neccessary
2508 // insert the string, don't insert doublespace
2509 string::size_type i = 0;
2510 while (i < str.length()) {
2511 if (str[i] != '\n') {
2513 && i + 1 < str.length() && str[i + 1] != ' '
2514 && pos && par->GetChar(pos - 1)!= ' ') {
2515 par->InsertChar(pos, ' ', current_font);
2517 } else if (str[i] == ' ') {
2518 InsetSpecialChar * new_inset =
2519 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2520 if (par->InsertInsetAllowed(new_inset)) {
2521 par->InsertInset(pos, new_inset,
2527 } else if (str[i] == '\t') {
2528 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2529 InsetSpecialChar * new_inset =
2530 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2531 if (par->InsertInsetAllowed(new_inset)) {
2532 par->InsertInset(pos, new_inset,
2539 } else if (str[i] != 13 &&
2540 // Ignore unprintables
2541 (str[i] & 127) >= ' ') {
2542 par->InsertChar(pos, str[i], current_font);
2546 if (!par->size()) { // par is empty
2547 InsetSpecialChar * new_inset =
2548 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2549 if (par->InsertInsetAllowed(new_inset)) {
2550 par->InsertInset(pos,
2558 par->BreakParagraph(bview->buffer()->params, pos, flag);
2565 RedoParagraphs(bview, cursor, endpar);
2566 SetCursor(bview, cursor.par(), cursor.pos());
2567 sel_cursor = cursor;
2568 SetCursor(bview, par, pos);
2573 /* turns double-CR to single CR, others where converted into one blank and 13s
2574 * that are ignored .Double spaces are also converted into one. Spaces at
2575 * the beginning of a paragraph are forbidden. tabs are converted into one
2576 * space. then InsertStringA is called */
2577 void LyXText::InsertStringB(BufferView * bview, string const & s)
2580 string::size_type i = 1;
2581 while (i < str.length()) {
2584 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2586 if (str[i] == '\n' && i + 1 < str.length()) {
2587 if (str[i + 1] != '\n') {
2588 if (str[i - 1] != ' ')
2593 while (i + 1 < str.length()
2594 && (str[i + 1] == ' '
2595 || str[i + 1] == '\t'
2596 || str[i + 1] == '\n'
2597 || str[i + 1] == 13)) {
2604 InsertStringA(bview, str);
2608 bool LyXText::GotoNextError(BufferView * bview) const
2610 LyXCursor res = cursor;
2612 if (res.pos() < res.par()->Last() - 1) {
2613 res.pos(res.pos() + 1);
2615 res.par(res.par()->Next());
2619 } while (res.par() &&
2620 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2621 && res.par()->GetInset(res.pos())->AutoDelete()));
2624 SetCursor(bview, res.par(), res.pos());
2631 bool LyXText::GotoNextNote(BufferView * bview) const
2633 LyXCursor res = cursor;
2635 if (res.pos() < res.par()->Last() - 1) {
2636 res.pos(res.pos() + 1);
2638 res.par(res.par()->Next());
2642 } while (res.par() &&
2643 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2644 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2647 SetCursor(bview, res.par(), res.pos());
2654 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2655 LyXParagraph::size_type pos)
2657 LyXCursor tmpcursor;
2660 LyXParagraph::size_type z;
2661 Row * row = GetRow(par, pos, y);
2663 // is there a break one row above
2664 if (row->previous() && row->previous()->par() == row->par()) {
2665 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2666 if (z >= row->pos()) {
2667 // set the dimensions of the row above
2668 y -= row->previous()->height();
2670 refresh_row = row->previous();
2671 status = LyXText::NEED_MORE_REFRESH;
2673 BreakAgain(bview, row->previous());
2675 // set the cursor again. Otherwise
2676 // dangling pointers are possible
2677 SetCursor(bview, cursor.par(), cursor.pos());
2678 sel_cursor = cursor;
2683 int const tmpheight = row->height();
2684 LyXParagraph::size_type const tmplast = RowLast(row);
2688 BreakAgain(bview, row);
2689 if (row->height() == tmpheight && RowLast(row) == tmplast)
2690 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2692 status = LyXText::NEED_MORE_REFRESH;
2694 // check the special right address boxes
2695 if (textclasslist.Style(bview->buffer()->params.textclass,
2696 par->GetLayout()).margintype
2697 == MARGIN_RIGHT_ADDRESS_BOX) {
2704 RedoDrawingOfParagraph(bview, tmpcursor);
2707 // set the cursor again. Otherwise dangling pointers are possible
2708 // also set the selection
2712 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2713 sel_cursor = cursor;
2714 SetCursorIntern(bview, sel_start_cursor.par(),
2715 sel_start_cursor.pos());
2716 sel_start_cursor = cursor;
2717 SetCursorIntern(bview, sel_end_cursor.par(),
2718 sel_end_cursor.pos());
2719 sel_end_cursor = cursor;
2720 SetCursorIntern(bview, last_sel_cursor.par(),
2721 last_sel_cursor.pos());
2722 last_sel_cursor = cursor;
2725 SetCursorIntern(bview, cursor.par(), cursor.pos());
2729 // returns false if inset wasn't found
2730 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2732 // first check the current paragraph
2733 int pos = cursor.par()->GetPositionOfInset(inset);
2735 CheckParagraph(bview, cursor.par(), pos);
2739 // check every paragraph
2741 LyXParagraph * par = FirstParagraph();
2744 // make sure the paragraph is open
2745 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2747 pos = par->GetPositionOfInset(inset);
2749 CheckParagraph(bview, par, pos);
2762 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2763 LyXParagraph::size_type pos,
2764 bool setfont, bool boundary) const
2766 LyXCursor old_cursor = cursor;
2767 SetCursorIntern(bview, par, pos, setfont, boundary);
2768 DeleteEmptyParagraphMechanism(bview, old_cursor);
2772 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2773 LyXParagraph::size_type pos, bool boundary) const
2776 // correct the cursor position if impossible
2777 if (pos > par->Last()){
2778 LyXParagraph * tmppar = par->ParFromPos(pos);
2779 pos = par->PositionInParFromPos(pos);
2782 if (par->IsDummy() && par->previous &&
2783 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2784 while (par->previous &&
2785 ((par->previous->IsDummy() &&
2786 (par->previous->previous->footnoteflag ==
2787 LyXParagraph::CLOSED_FOOTNOTE)) ||
2788 (par->previous->footnoteflag ==
2789 LyXParagraph::CLOSED_FOOTNOTE))) {
2790 par = par->previous ;
2791 if (par->IsDummy() &&
2792 (par->previous->footnoteflag ==
2793 LyXParagraph::CLOSED_FOOTNOTE))
2794 pos += par->size() + 1;
2796 if (par->previous) {
2797 par = par->previous;
2799 pos += par->size() + 1;
2804 cur.boundary(boundary);
2806 /* get the cursor y position in text */
2808 Row * row = GetRow(par, pos, y);
2809 /* y is now the beginning of the cursor row */
2810 y += row->baseline();
2811 /* y is now the cursor baseline */
2814 /* now get the cursors x position */
2816 float fill_separator, fill_hfill, fill_label_hfill;
2817 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2819 LyXParagraph::size_type cursor_vpos = 0;
2820 LyXParagraph::size_type last = RowLastPrintable(row);
2822 if (pos > last + 1) // This shouldn't happen.
2824 else if (pos < row->pos())
2827 if (last < row->pos())
2828 cursor_vpos = row->pos();
2829 else if (pos > last && !boundary)
2830 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2831 ? row->pos() : last + 1;
2832 else if (pos > row->pos() &&
2833 (pos > last || boundary))
2834 /// Place cursor after char at (logical) position pos - 1
2835 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2836 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2838 /// Place cursor before char at (logical) position pos
2839 cursor_vpos = (bidi_level(pos) % 2 == 0)
2840 ? log2vis(pos) : log2vis(pos) + 1;
2842 LyXParagraph::size_type main_body =
2843 BeginningOfMainBody(bview->buffer(), row->par());
2844 if ((main_body > 0) &&
2845 ((main_body-1 > last) ||
2846 !row->par()->IsLineSeparator(main_body-1)))
2849 for (LyXParagraph::size_type vpos = row->pos();
2850 vpos < cursor_vpos; ++vpos) {
2851 pos = vis2log(vpos);
2852 if (main_body > 0 && pos == main_body - 1) {
2853 x += fill_label_hfill +
2854 lyxfont::width(textclasslist.Style(
2855 bview->buffer()->params.textclass,
2856 row->par()->GetLayout())
2858 GetFont(bview->buffer(), row->par(), -2));
2859 if (row->par()->IsLineSeparator(main_body-1))
2860 x -= SingleWidth(bview, row->par(),main_body-1);
2862 if (HfillExpansion(bview->buffer(), row, pos)) {
2863 x += SingleWidth(bview, row->par(), pos);
2864 if (pos >= main_body)
2867 x += fill_label_hfill;
2868 } else if (row->par()->IsSeparator(pos)) {
2869 x += SingleWidth(bview, row->par(), pos);
2870 if (pos >= main_body)
2871 x += fill_separator;
2873 x += SingleWidth(bview, row->par(), pos);
2882 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2883 LyXParagraph::size_type pos,
2884 bool setfont, bool boundary) const
2886 SetCursor(bview, cursor, par, pos, boundary);
2888 SetCurrentFont(bview);
2892 void LyXText::SetCurrentFont(BufferView * bview) const
2894 LyXParagraph::size_type pos = cursor.pos();
2895 if (cursor.boundary() && pos > 0)
2899 if (pos == cursor.par()->Last())
2901 else if (cursor.par()->IsSeparator(pos)) {
2902 if (pos > cursor.row()->pos() &&
2903 bidi_level(pos) % 2 ==
2904 bidi_level(pos - 1) % 2)
2906 else if (pos + 1 < cursor.par()->Last())
2912 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2913 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2915 if (cursor.pos() == cursor.par()->Last() &&
2916 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2917 !cursor.boundary()) {
2918 Language const * lang =
2919 cursor.par()->getParLanguage(bview->buffer()->params);
2920 current_font.setLanguage(lang);
2921 real_current_font.setLanguage(lang);
2926 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2928 LyXCursor old_cursor = cursor;
2930 /* get the row first */
2932 Row * row = GetRowNearY(y);
2933 cursor.par(row->par());
2936 int column = GetColumnNearX(bview, row, x, bound);
2937 cursor.pos(row->pos() + column);
2939 cursor.y(y + row->baseline());
2941 cursor.boundary(bound);
2942 SetCurrentFont(bview);
2943 DeleteEmptyParagraphMechanism(bview, old_cursor);
2947 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2950 /* get the row first */
2952 Row * row = GetRowNearY(y);
2954 int column = GetColumnNearX(bview, row, x, bound);
2956 cur.par(row->par());
2957 cur.pos(row->pos() + column);
2959 cur.y(y + row->baseline());
2961 cur.boundary(bound);
2965 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2967 if (cursor.pos() > 0) {
2968 bool boundary = cursor.boundary();
2969 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2970 if (!internal && !boundary &&
2971 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2972 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2973 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2974 LyXParagraph * par = cursor.par()->Previous();
2975 SetCursor(bview, par, par->Last());
2980 void LyXText::CursorRight(BufferView * bview, bool internal) const
2982 if (!internal && cursor.boundary() &&
2983 !cursor.par()->IsNewline(cursor.pos()))
2984 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2985 else if (cursor.pos() < cursor.par()->Last()) {
2986 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2988 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2989 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2990 } else if (cursor.par()->Next())
2991 SetCursor(bview, cursor.par()->Next(), 0);
2995 void LyXText::CursorUp(BufferView * bview) const
2997 SetCursorFromCoordinates(bview, cursor.x_fix(),
2998 cursor.y() - cursor.row()->baseline() - 1);
3002 void LyXText::CursorDown(BufferView * bview) const
3004 SetCursorFromCoordinates(bview, cursor.x_fix(),
3005 cursor.y() - cursor.row()->baseline()
3006 + cursor.row()->height() + 1);
3010 void LyXText::CursorUpParagraph(BufferView * bview) const
3012 if (cursor.pos() > 0) {
3013 SetCursor(bview, cursor.par(), 0);
3015 else if (cursor.par()->Previous()) {
3016 SetCursor(bview, cursor.par()->Previous(), 0);
3021 void LyXText::CursorDownParagraph(BufferView * bview) const
3023 if (cursor.par()->Next()) {
3024 SetCursor(bview, cursor.par()->Next(), 0);
3026 SetCursor(bview, cursor.par(), cursor.par()->Last());
3031 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3032 LyXCursor const & old_cursor) const
3034 // Would be wrong to delete anything if we have a selection.
3035 if (selection) return;
3037 // We allow all kinds of "mumbo-jumbo" when freespacing.
3038 if (textclasslist.Style(bview->buffer()->params.textclass,
3039 old_cursor.par()->GetLayout()).free_spacing)
3042 bool deleted = false;
3044 /* Ok I'll put some comments here about what is missing.
3045 I have fixed BackSpace (and thus Delete) to not delete
3046 double-spaces automagically. I have also changed Cut,
3047 Copy and Paste to hopefully do some sensible things.
3048 There are still some small problems that can lead to
3049 double spaces stored in the document file or space at
3050 the beginning of paragraphs. This happens if you have
3051 the cursor betwenn to spaces and then save. Or if you
3052 cut and paste and the selection have a space at the
3053 beginning and then save right after the paste. I am
3054 sure none of these are very hard to fix, but I will
3055 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3056 that I can get some feedback. (Lgb)
3059 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3060 // delete the LineSeparator.
3063 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3064 // delete the LineSeparator.
3067 // If the pos around the old_cursor were spaces, delete one of them.
3068 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3069 // Only if the cursor has really moved
3071 if (old_cursor.pos() > 0
3072 && old_cursor.pos() < old_cursor.par()->Last()
3073 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3074 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3075 old_cursor.par()->Erase(old_cursor.pos() - 1);
3076 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3078 if (old_cursor.par() == cursor.par() &&
3079 cursor.pos() > old_cursor.pos()) {
3080 SetCursorIntern(bview, cursor.par(),
3083 SetCursorIntern(bview, cursor.par(),
3089 // Do not delete empty paragraphs with keepempty set.
3090 if ((textclasslist.Style(bview->buffer()->params.textclass,
3091 old_cursor.par()->GetLayout())).keepempty)
3094 LyXCursor tmpcursor;
3096 if (old_cursor.par() != cursor.par()) {
3097 if ((old_cursor.par()->Last() == 0
3098 || (old_cursor.par()->Last() == 1
3099 && old_cursor.par()->IsLineSeparator(0)))
3101 && old_cursor.par()->FirstPhysicalPar()
3102 == old_cursor.par()->LastPhysicalPar()
3105 // ok, we will delete anything
3107 // make sure that you do not delete any environments
3110 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3111 !(old_cursor.row()->previous()
3112 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3113 && !(old_cursor.row()->next()
3114 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3115 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3116 && ((old_cursor.row()->previous()
3117 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3118 || (old_cursor.row()->next()
3119 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3122 status = LyXText::NEED_MORE_REFRESH;
3125 if (old_cursor.row()->previous()) {
3126 refresh_row = old_cursor.row()->previous();
3127 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3129 cursor = old_cursor; // that undo can restore the right cursor position
3130 LyXParagraph * endpar = old_cursor.par()->next;
3131 if (endpar && endpar->GetDepth()) {
3132 while (endpar && endpar->GetDepth()) {
3134 endpar = endpar->LastPhysicalPar()->Next();
3136 endpar = endpar->Next();
3140 SetUndo(bview->buffer(), Undo::DELETE,
3141 old_cursor.par()->previous,
3146 RemoveRow(old_cursor.row());
3147 if (OwnerParagraph() == old_cursor.par()) {
3148 OwnerParagraph(OwnerParagraph()->next);
3151 delete old_cursor.par();
3153 /* Breakagain the next par. Needed
3154 * because of the parindent that
3155 * can occur or dissappear. The
3156 * next row can change its height,
3157 * if there is another layout before */
3158 if (refresh_row->next()) {
3159 BreakAgain(bview, refresh_row->next());
3160 UpdateCounters(bview, refresh_row);
3162 SetHeightOfRow(bview, refresh_row);
3164 refresh_row = old_cursor.row()->next();
3165 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3168 cursor = old_cursor; // that undo can restore the right cursor position
3169 LyXParagraph * endpar = old_cursor.par()->next;
3170 if (endpar && endpar->GetDepth()) {
3171 while (endpar && endpar->GetDepth()) {
3173 endpar = endpar->LastPhysicalPar()->Next();
3175 endpar = endpar->Next();
3179 SetUndo(bview->buffer(), Undo::DELETE,
3180 old_cursor.par()->previous,
3185 RemoveRow(old_cursor.row());
3187 if (OwnerParagraph() == old_cursor.par()) {
3188 OwnerParagraph(OwnerParagraph()->next);
3190 delete old_cursor.par();
3192 /* Breakagain the next par. Needed
3193 because of the parindent that can
3194 occur or dissappear.
3195 The next row can change its height,
3196 if there is another layout before
3199 BreakAgain(bview, refresh_row);
3200 UpdateCounters(bview, refresh_row->previous());
3206 SetCursorIntern(bview, cursor.par(), cursor.pos());
3208 if (sel_cursor.par() == old_cursor.par()
3209 && sel_cursor.pos() == sel_cursor.pos()) {
3210 // correct selection
3211 sel_cursor = cursor;
3218 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3219 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3221 SetCursorIntern(bview, cursor.par(), cursor.pos());
3222 sel_cursor = cursor;
3229 LyXParagraph * LyXText::GetParFromID(int id)
3231 LyXParagraph * result = FirstParagraph();
3232 while (result && result->id() != id)
3233 result = result->next;
3239 bool LyXText::TextUndo(BufferView * bview)
3243 // returns false if no undo possible
3244 Undo * undo = bview->buffer()->undostack.pop();
3248 bview->buffer()->redostack
3249 .push(CreateUndo(bview->buffer(), undo->kind,
3250 GetParFromID(undo->number_of_before_par),
3251 GetParFromID(undo->number_of_behind_par)));
3253 return TextHandleUndo(bview, undo);
3257 bool LyXText::TextRedo(BufferView * bview)
3261 // returns false if no redo possible
3262 Undo * undo = bview->buffer()->redostack.pop();
3266 bview->buffer()->undostack
3267 .push(CreateUndo(bview->buffer(), undo->kind,
3268 GetParFromID(undo->number_of_before_par),
3269 GetParFromID(undo->number_of_behind_par)));
3271 return TextHandleUndo(bview, undo);
3275 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3279 // returns false if no undo possible
3280 bool result = false;
3282 LyXParagraph * before =
3283 GetParFromID(undo->number_of_before_par);
3284 LyXParagraph * behind =
3285 GetParFromID(undo->number_of_behind_par);
3286 LyXParagraph * tmppar;
3287 LyXParagraph * tmppar2;
3288 LyXParagraph * endpar;
3289 LyXParagraph * tmppar5;
3291 // if there's no before take the beginning
3292 // of the document for redoing
3294 SetCursorIntern(bview, FirstParagraph(), 0);
3296 // replace the paragraphs with the undo informations
3298 LyXParagraph * tmppar3 = undo->par;
3299 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3300 LyXParagraph * tmppar4 = tmppar3;
3302 while (tmppar4->next)
3303 tmppar4 = tmppar4->next;
3304 } // get last undo par
3306 // now remove the old text if there is any
3307 if (before != behind || (!behind && !before)){
3309 tmppar5 = before->next;
3311 tmppar5 = OwnerParagraph();
3313 while (tmppar5 && tmppar5 != behind){
3315 tmppar5 = tmppar5->next;
3316 // a memory optimization for edit: Only layout information
3317 // is stored in the undo. So restore the text informations.
3318 if (undo->kind == Undo::EDIT) {
3319 tmppar2->setContentsFromPar(tmppar);
3320 tmppar->clearContents();
3321 tmppar2 = tmppar2->next;
3326 // put the new stuff in the list if there is one
3329 before->next = tmppar3;
3331 OwnerParagraph(tmppar3);
3332 tmppar3->previous = before;
3335 OwnerParagraph(behind);
3338 tmppar4->next = behind;
3340 behind->previous = tmppar4;
3344 // Set the cursor for redoing
3347 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3349 SetCursorIntern(bview, before, 0);
3352 // check wether before points to a closed float and open it if necessary
3353 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3354 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3356 while (tmppar4->previous &&
3357 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3358 tmppar4 = tmppar4->previous;
3359 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3360 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3361 tmppar4 = tmppar4->next;
3368 // open a cosed footnote at the end if necessary
3369 if (behind && behind->previous &&
3370 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3371 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3372 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3373 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3374 behind = behind->next;
3379 // calculate the endpar for redoing the paragraphs.
3382 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3383 endpar = behind->LastPhysicalPar()->Next();
3385 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3387 endpar = behind->Next();
3392 tmppar = GetParFromID(undo->number_of_cursor_par);
3393 RedoParagraphs(bview, cursor, endpar);
3395 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3396 UpdateCounters(bview, cursor.row());
3406 void LyXText::FinishUndo()
3410 // makes sure the next operation will be stored
3411 undo_finished = true;
3415 void LyXText::FreezeUndo()
3419 // this is dangerous and for internal use only
3424 void LyXText::UnFreezeUndo()
3428 // this is dangerous and for internal use only
3429 undo_frozen = false;
3433 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3434 LyXParagraph const * before,
3435 LyXParagraph const * behind) const
3440 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3441 buf->redostack.clear();
3445 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3446 LyXParagraph const * before, LyXParagraph const * behind)
3450 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3454 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3455 LyXParagraph const * before,
3456 LyXParagraph const * behind) const
3461 int before_number = -1;
3462 int behind_number = -1;
3464 before_number = before->id();
3466 behind_number = behind->id();
3467 // Undo::EDIT and Undo::FINISH are
3468 // always finished. (no overlapping there)
3469 // overlapping only with insert and delete inside one paragraph:
3470 // Nobody wants all removed character
3471 // appear one by one when undoing.
3472 // EDIT is special since only layout information, not the
3473 // contents of a paragaph are stored.
3474 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3475 // check wether storing is needed
3476 if (!buf->undostack.empty() &&
3477 buf->undostack.top()->kind == kind &&
3478 buf->undostack.top()->number_of_before_par == before_number &&
3479 buf->undostack.top()->number_of_behind_par == behind_number ){
3484 // create a new Undo
3485 LyXParagraph * undopar;
3486 LyXParagraph * tmppar;
3487 LyXParagraph * tmppar2;
3489 LyXParagraph * start = 0;
3490 LyXParagraph * end = 0;
3493 start = before->next;
3495 start = FirstParagraph();
3497 end = behind->previous;
3499 end = FirstParagraph();
3505 && start != end->next
3506 && (before != behind || (!before && !behind))) {
3508 tmppar2 = tmppar->Clone();
3509 tmppar2->id(tmppar->id());
3511 // a memory optimization: Just store the layout information
3513 if (kind == Undo::EDIT){
3514 //tmppar2->text.clear();
3515 tmppar2->clearContents();
3520 while (tmppar != end && tmppar->next) {
3521 tmppar = tmppar->next;
3522 tmppar2->next = tmppar->Clone();
3523 tmppar2->next->id(tmppar->id());
3524 // a memory optimization: Just store the layout
3525 // information when only edit
3526 if (kind == Undo::EDIT){
3527 //tmppar2->next->text.clear();
3528 tmppar2->clearContents();
3530 tmppar2->next->previous = tmppar2;
3531 tmppar2 = tmppar2->next;
3535 undopar = 0; // nothing to replace (undo of delete maybe)
3538 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3539 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3541 int cursor_par = cursor.par()->id();
3542 int cursor_pos = cursor.pos();
3545 Undo * undo = new Undo(kind,
3546 before_number, behind_number,
3547 cursor_par, cursor_pos,
3550 undo_finished = false;
3555 void LyXText::SetCursorParUndo(Buffer * buf)
3559 SetUndo(buf, Undo::FINISH,
3561 cursor.par()->ParFromPos(cursor.pos())->previous,
3562 cursor.par()->ParFromPos(cursor.pos())->next
3564 cursor.par()->previous,
3571 void LyXText::toggleAppendix(BufferView * bview)
3574 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3576 LyXParagraph * par = cursor.par();
3578 bool start = !par->start_of_appendix;
3580 // ensure that we have only one start_of_appendix in this document
3581 LyXParagraph * tmp = FirstParagraph();
3582 for (; tmp; tmp = tmp->next)
3583 tmp->start_of_appendix = 0;
3584 par->start_of_appendix = start;
3586 // we can set the refreshing parameters now
3587 status = LyXText::NEED_MORE_REFRESH;
3589 refresh_row = 0; // not needed for full update
3590 UpdateCounters(bview, 0);
3591 SetCursor(bview, cursor.par(), cursor.pos());
3595 LyXParagraph * LyXText::OwnerParagraph() const
3598 return inset_owner->par;
3600 return bv_owner->buffer()->paragraph;
3604 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3607 inset_owner->par = p;
3609 bv_owner->buffer()->paragraph = p;