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 ? SelectWordWhenUnderCursor(bview) : false;
1286 SetFont(bview, font, toggleall);
1288 /* Implicit selections are cleared afterwards and cursor is set to the
1289 original position. */
1290 if (implicitSelection) {
1292 cursor = resetCursor;
1293 SetCursor(bview, cursor.par(), cursor.pos());
1294 sel_cursor = cursor;
1299 LyXParagraph::size_type
1300 LyXText::BeginningOfMainBody(Buffer const * buf,
1301 LyXParagraph const * par) const
1303 if (textclasslist.Style(buf->params.textclass,
1304 par->GetLayout()).labeltype != LABEL_MANUAL)
1307 return par->BeginningOfMainBody();
1312 /* if there is a selection, reset every environment you can find
1313 * in the selection, otherwise just the environment you are in */
1314 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1316 LyXParagraph * tmppar, * firsttmppar;
1320 /* is is only allowed, if the cursor is IN an open footnote.
1321 * Otherwise it is too dangerous */
1322 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1325 SetUndo(bview->buffer(), Undo::FINISH,
1326 cursor.par()->PreviousBeforeFootnote()->previous,
1327 cursor.par()->NextAfterFootnote()->next);
1329 /* ok, move to the beginning of the footnote. */
1330 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1331 cursor.par(cursor.par()->Previous());
1333 SetCursor(bview, cursor.par(), cursor.par()->Last());
1334 /* this is just faster than using CursorLeft(); */
1336 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1337 tmppar = firsttmppar;
1338 /* tmppar is now the paragraph right before the footnote */
1340 bool first_footnote_par_is_not_empty = tmppar->next->size();
1343 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1344 tmppar = tmppar->next; /* I use next instead of Next(),
1345 * because there cannot be any
1346 * footnotes in a footnote
1348 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1350 /* remember the captions and empty paragraphs */
1351 if ((textclasslist.Style(bview->buffer()->params.textclass,
1352 tmppar->GetLayout())
1353 .labeltype == LABEL_SENSITIVE)
1355 tmppar->SetLayout(bview->buffer()->params, 0);
1358 // now we will paste the ex-footnote, if the layouts allow it
1359 // first restore the layout of the paragraph right behind
1362 tmppar->next->MakeSameLayout(cursor.par());
1365 if (!tmppar->GetLayout()
1367 && (!tmppar->Next()->Last()
1368 || tmppar->Next()->HasSameLayout(tmppar)))) {
1369 if (tmppar->Next()->Last()
1370 && tmppar->Next()->IsLineSeparator(0))
1371 tmppar->Next()->Erase(0);
1372 tmppar->PasteParagraph(bview->buffer()->params);
1375 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1376 * by the pasting of the beginning */
1378 /* then the beginning */
1379 /* if there is no space between the text and the footnote, so we insert
1381 * (only if the previous par and the footnotepar are not empty!) */
1382 if (!firsttmppar->next->GetLayout()
1383 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1384 if (firsttmppar->size()
1385 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1386 && first_footnote_par_is_not_empty) {
1387 firsttmppar->next->InsertChar(0, ' ');
1389 firsttmppar->PasteParagraph(bview->buffer()->params);
1392 /* now redo the paragaphs */
1393 RedoParagraphs(bview, cursor, tmppar);
1395 SetCursor(bview, cursor.par(), cursor.pos());
1397 /* sometimes it can happen, that there is a counter change */
1398 Row * row = cursor.row();
1399 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1401 UpdateCounters(bview, row);
1409 /* the DTP switches for paragraphs. LyX will store them in the
1410 * first physicla paragraph. When a paragraph is broken, the top settings
1411 * rest, the bottom settings are given to the new one. So I can make shure,
1412 * they do not duplicate themself and you cannnot make dirty things with
1415 void LyXText::SetParagraph(BufferView * bview,
1416 bool line_top, bool line_bottom,
1417 bool pagebreak_top, bool pagebreak_bottom,
1418 VSpace const & space_top,
1419 VSpace const & space_bottom,
1421 string labelwidthstring,
1424 LyXCursor tmpcursor = cursor;
1426 sel_start_cursor = cursor;
1427 sel_end_cursor = cursor;
1430 // make sure that the depth behind the selection are restored, too
1432 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1434 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1436 LyXParagraph * undoendpar = endpar;
1438 if (endpar && endpar->GetDepth()) {
1439 while (endpar && endpar->GetDepth()) {
1441 endpar = endpar->LastPhysicalPar()->Next();
1443 endpar = endpar->Next();
1445 undoendpar = endpar;
1449 endpar = endpar->Next(); // because of parindents etc.
1452 SetUndo(bview->buffer(), Undo::EDIT,
1455 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1457 sel_start_cursor.par()->previous,
1462 LyXParagraph * tmppar = sel_end_cursor.par();
1464 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1465 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1467 while (tmppar != sel_start_cursor.par()->Previous()) {
1468 SetCursor(bview, tmppar, 0);
1470 status = LyXText::NEED_MORE_REFRESH;
1471 refresh_row = cursor.row();
1472 refresh_y = cursor.y() - cursor.row()->baseline();
1474 if (cursor.par()->footnoteflag ==
1475 sel_start_cursor.par()->footnoteflag) {
1477 cursor.par()->line_top = line_top;
1478 cursor.par()->line_bottom = line_bottom;
1479 cursor.par()->pagebreak_top = pagebreak_top;
1480 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1481 cursor.par()->added_space_top = space_top;
1482 cursor.par()->added_space_bottom = space_bottom;
1483 // does the layout allow the new alignment?
1484 if (align == LYX_ALIGN_LAYOUT)
1485 align = textclasslist
1486 .Style(bview->buffer()->params.textclass,
1487 cursor.par()->GetLayout()).align;
1488 if (align & textclasslist
1489 .Style(bview->buffer()->params.textclass,
1490 cursor.par()->GetLayout()).alignpossible) {
1491 if (align == textclasslist
1492 .Style(bview->buffer()->params.textclass,
1493 cursor.par()->GetLayout()).align)
1494 cursor.par()->align = LYX_ALIGN_LAYOUT;
1496 cursor.par()->align = align;
1498 cursor.par()->SetLabelWidthString(labelwidthstring);
1499 cursor.par()->noindent = noindent;
1503 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1505 tmppar = cursor.par()->Previous();
1509 RedoParagraphs(bview, sel_start_cursor, endpar);
1512 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1513 sel_cursor = cursor;
1514 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1516 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1518 bview->updateInset(inset_owner, true);
1522 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1523 string const & width,
1524 string const & widthp,
1525 int alignment, bool hfill,
1526 bool start_minipage)
1528 LyXCursor tmpcursor = cursor;
1529 LyXParagraph * tmppar;
1531 sel_start_cursor = cursor;
1532 sel_end_cursor = cursor;
1535 // make sure that the depth behind the selection are restored, too
1537 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1539 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1541 LyXParagraph * undoendpar = endpar;
1543 if (endpar && endpar->GetDepth()) {
1544 while (endpar && endpar->GetDepth()) {
1546 endpar = endpar->LastPhysicalPar()->Next();
1548 endpar = endpar->Next();
1550 undoendpar = endpar;
1554 endpar = endpar->Next(); // because of parindents etc.
1557 SetUndo(bview->buffer(), Undo::EDIT,
1560 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1562 sel_start_cursor.par()->previous,
1566 tmppar = sel_end_cursor.par();
1568 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1569 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1571 while(tmppar != sel_start_cursor.par()->Previous()) {
1572 SetCursor(bview, tmppar, 0);
1574 status = LyXText::NEED_MORE_REFRESH;
1575 refresh_row = cursor.row();
1576 refresh_y = cursor.y() - cursor.row()->baseline();
1578 if (cursor.par()->footnoteflag ==
1579 sel_start_cursor.par()->footnoteflag) {
1581 if (type == LyXParagraph::PEXTRA_NONE) {
1582 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1583 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1584 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1587 cursor.par()->SetPExtraType(bview->buffer()->params,
1588 type, width, widthp);
1589 cursor.par()->pextra_hfill = hfill;
1590 cursor.par()->pextra_start_minipage = start_minipage;
1591 cursor.par()->pextra_alignment = alignment;
1595 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1597 tmppar = cursor.par()->Previous();
1600 RedoParagraphs(bview, sel_start_cursor, endpar);
1602 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1603 sel_cursor = cursor;
1604 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1606 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1610 char loweralphaCounter(int n)
1612 if (n < 1 || n > 26)
1620 char alphaCounter(int n)
1622 if (n < 1 || n > 26)
1630 char hebrewCounter(int n)
1632 static const char hebrew[22] = {
1633 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1634 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1635 '÷', 'ø', 'ù', 'ú'
1637 if (n < 1 || n > 22)
1645 string const romanCounter(int n)
1647 static char const * roman[20] = {
1648 "i", "ii", "iii", "iv", "v",
1649 "vi", "vii", "viii", "ix", "x",
1650 "xi", "xii", "xiii", "xiv", "xv",
1651 "xvi", "xvii", "xviii", "xix", "xx"
1653 if (n < 1 || n > 20)
1660 // set the counter of a paragraph. This includes the labels
1661 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1664 // this is only relevant for the beginning of paragraph
1665 par = par->FirstPhysicalPar();
1667 LyXLayout const & layout =
1668 textclasslist.Style(buf->params.textclass,
1671 LyXTextClass const & textclass =
1672 textclasslist.TextClass(buf->params.textclass);
1674 /* copy the prev-counters to this one, unless this is the start of a
1675 footnote or of a bibliography or the very first paragraph */
1678 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1679 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1680 && par->footnotekind == LyXParagraph::FOOTNOTE)
1682 && !(textclasslist.Style(buf->params.textclass,
1683 par->Previous()->GetLayout()
1684 ).labeltype != LABEL_BIBLIO
1685 && layout.labeltype == LABEL_BIBLIO)) {
1686 for (int i = 0; i < 10; ++i) {
1687 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1690 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1692 par->appendix = par->Previous()->appendix;
1694 if (!par->appendix && par->start_of_appendix){
1695 par->appendix = true;
1696 for (int i = 0; i < 10; ++i) {
1697 par->setCounter(i, 0);
1701 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1702 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1704 par->enumdepth = par->Previous()->enumdepth;
1705 par->itemdepth = par->Previous()->itemdepth;
1708 for (int i = 0; i < 10; ++i) {
1709 par->setCounter(i, 0);
1711 par->appendix = par->start_of_appendix;
1717 // if this is an open marginnote and this is the first
1718 // entry in the marginnote and the enclosing
1719 // environment is an enum/item then correct for the
1720 // LaTeX behaviour (ARRae)
1721 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1722 && par->footnotekind == LyXParagraph::MARGIN
1724 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1725 && (par->PreviousBeforeFootnote()
1726 && textclasslist.Style(buf->params.textclass,
1727 par->PreviousBeforeFootnote()->GetLayout()
1728 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1729 // Any itemize or enumerate environment in a marginnote
1730 // that is embedded in an itemize or enumerate
1731 // paragraph is seen by LaTeX as being at a deeper
1732 // level within that enclosing itemization/enumeration
1733 // even if there is a "standard" layout at the start of
1739 /* Maybe we have to increment the enumeration depth.
1740 * BUT, enumeration in a footnote is considered in isolation from its
1741 * surrounding paragraph so don't increment if this is the
1742 * first line of the footnote
1743 * AND, bibliographies can't have their depth changed ie. they
1744 * are always of depth 0
1747 && par->Previous()->GetDepth() < par->GetDepth()
1748 && textclasslist.Style(buf->params.textclass,
1749 par->Previous()->GetLayout()
1750 ).labeltype == LABEL_COUNTER_ENUMI
1751 && par->enumdepth < 3
1753 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1754 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1755 && par->footnotekind == LyXParagraph::FOOTNOTE)
1757 && layout.labeltype != LABEL_BIBLIO) {
1761 /* Maybe we have to decrement the enumeration depth, see note above */
1763 && par->Previous()->GetDepth() > par->GetDepth()
1765 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1766 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1767 && par->footnotekind == LyXParagraph::FOOTNOTE)
1769 && layout.labeltype != LABEL_BIBLIO) {
1770 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1771 par->setCounter(6 + par->enumdepth,
1772 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1773 /* reset the counters.
1774 * A depth change is like a breaking layout
1776 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1777 par->setCounter(i, 0);
1780 if (!par->labelstring.empty()) {
1781 par->labelstring.erase();
1784 if (layout.margintype == MARGIN_MANUAL) {
1785 if (par->labelwidthstring.empty()) {
1786 par->SetLabelWidthString(layout.labelstring());
1789 par->SetLabelWidthString(string());
1792 /* is it a layout that has an automatic label ? */
1793 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1795 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1796 if (i >= 0 && i<= buf->params.secnumdepth) {
1797 par->incCounter(i); // increment the counter
1799 // Is there a label? Useful for Chapter layout
1800 if (!par->appendix){
1801 if (!layout.labelstring().empty())
1802 par->labelstring = layout.labelstring();
1804 par->labelstring.erase();
1806 if (!layout.labelstring_appendix().empty())
1807 par->labelstring = layout.labelstring_appendix();
1809 par->labelstring.erase();
1812 std::ostringstream s;
1814 if (!par->appendix) {
1815 switch (2 * LABEL_COUNTER_CHAPTER -
1816 textclass.maxcounter() + i) {
1817 case LABEL_COUNTER_CHAPTER:
1818 s << par->getCounter(i);
1820 case LABEL_COUNTER_SECTION:
1821 s << par->getCounter(i - 1) << '.'
1822 << par->getCounter(i);
1824 case LABEL_COUNTER_SUBSECTION:
1825 s << par->getCounter(i - 2) << '.'
1826 << par->getCounter(i - 1) << '.'
1827 << par->getCounter(i);
1829 case LABEL_COUNTER_SUBSUBSECTION:
1830 s << par->getCounter(i - 3) << '.'
1831 << par->getCounter(i - 2) << '.'
1832 << par->getCounter(i - 1) << '.'
1833 << par->getCounter(i);
1836 case LABEL_COUNTER_PARAGRAPH:
1837 s << par->getCounter(i - 4) << '.'
1838 << par->getCounter(i - 3) << '.'
1839 << par->getCounter(i - 2) << '.'
1840 << par->getCounter(i - 1) << '.'
1841 << par->getCounter(i);
1843 case LABEL_COUNTER_SUBPARAGRAPH:
1844 s << par->getCounter(i - 5) << '.'
1845 << par->getCounter(i - 4) << '.'
1846 << par->getCounter(i - 3) << '.'
1847 << par->getCounter(i - 2) << '.'
1848 << par->getCounter(i - 1) << '.'
1849 << par->getCounter(i);
1853 // Can this ever be reached? And in the
1854 // case it is, how can this be correct?
1856 s << par->getCounter(i) << '.';
1859 } else { // appendix
1860 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1861 case LABEL_COUNTER_CHAPTER:
1862 if (par->isRightToLeftPar(buf->params))
1863 s << hebrewCounter(par->getCounter(i));
1865 s << alphaCounter(par->getCounter(i));
1867 case LABEL_COUNTER_SECTION:
1868 if (par->isRightToLeftPar(buf->params))
1869 s << hebrewCounter(par->getCounter(i - 1));
1871 s << alphaCounter(par->getCounter(i - 1));
1874 << par->getCounter(i);
1877 case LABEL_COUNTER_SUBSECTION:
1878 if (par->isRightToLeftPar(buf->params))
1879 s << hebrewCounter(par->getCounter(i - 2));
1881 s << alphaCounter(par->getCounter(i - 2));
1884 << par->getCounter(i-1) << '.'
1885 << par->getCounter(i);
1888 case LABEL_COUNTER_SUBSUBSECTION:
1889 if (par->isRightToLeftPar(buf->params))
1890 s << hebrewCounter(par->getCounter(i-3));
1892 s << alphaCounter(par->getCounter(i-3));
1895 << par->getCounter(i-2) << '.'
1896 << par->getCounter(i-1) << '.'
1897 << par->getCounter(i);
1900 case LABEL_COUNTER_PARAGRAPH:
1901 if (par->isRightToLeftPar(buf->params))
1902 s << hebrewCounter(par->getCounter(i-4));
1904 s << alphaCounter(par->getCounter(i-4));
1907 << par->getCounter(i-3) << '.'
1908 << par->getCounter(i-2) << '.'
1909 << par->getCounter(i-1) << '.'
1910 << par->getCounter(i);
1913 case LABEL_COUNTER_SUBPARAGRAPH:
1914 if (par->isRightToLeftPar(buf->params))
1915 s << hebrewCounter(par->getCounter(i-5));
1917 s << alphaCounter(par->getCounter(i-5));
1920 << par->getCounter(i-4) << '.'
1921 << par->getCounter(i-3) << '.'
1922 << par->getCounter(i-2) << '.'
1923 << par->getCounter(i-1) << '.'
1924 << par->getCounter(i);
1928 // Can this ever be reached? And in the
1929 // case it is, how can this be correct?
1931 s << par->getCounter(i) << '.';
1937 par->labelstring += s.str().c_str();
1938 // We really want to remove the c_str as soon as
1941 for (i++; i < 10; ++i) {
1942 // reset the following counters
1943 par->setCounter(i, 0);
1945 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1946 for (i++; i < 10; ++i) {
1947 // reset the following counters
1948 par->setCounter(i, 0);
1950 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1951 par->incCounter(i + par->enumdepth);
1952 int number = par->getCounter(i + par->enumdepth);
1954 std::ostringstream s;
1956 switch (par->enumdepth) {
1958 if (par->isRightToLeftPar(buf->params))
1960 << hebrewCounter(number)
1964 << loweralphaCounter(number)
1968 if (par->isRightToLeftPar(buf->params))
1969 s << '.' << romanCounter(number);
1971 s << romanCounter(number) << '.';
1974 if (par->isRightToLeftPar(buf->params))
1976 << alphaCounter(number);
1978 s << alphaCounter(number)
1982 if (par->isRightToLeftPar(buf->params))
1989 par->labelstring = s.str().c_str();
1990 // we really want to get rid of that c_str()
1992 for (i += par->enumdepth + 1; i < 10; ++i)
1993 par->setCounter(i, 0); /* reset the following counters */
1996 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1997 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1999 int number = par->getCounter(i);
2001 InsetCommandParams p( "bibitem" );
2002 par->bibkey = new InsetBibKey(p);
2004 par->bibkey->setCounter(number);
2005 par->labelstring = layout.labelstring();
2007 // In biblio should't be following counters but...
2009 string s = layout.labelstring();
2011 // the caption hack:
2012 if (layout.labeltype == LABEL_SENSITIVE) {
2013 bool isOK (par->InInset() && par->InInset()->owner() &&
2014 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2016 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2017 && (par->footnotekind == LyXParagraph::FIG
2018 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2019 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2020 ? ":øåéà " : "Figure:";
2021 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2022 && (par->footnotekind == LyXParagraph::TAB
2023 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2024 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2025 ? ":äìáè" : "Table:";
2026 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2027 && par->footnotekind == LyXParagraph::ALGORITHM) {
2028 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2029 ? ":Ãúéøåâìà " : "Algorithm:";
2033 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2035 = floatList.getType(tmp->type());
2036 // We should get the correct number here too.
2037 s = fl.name + " #:";
2039 /* par->SetLayout(0);
2040 s = layout->labelstring; */
2041 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2042 ? " :úåòîùî øñç" : "Senseless: ";
2045 par->labelstring = s;
2047 /* reset the enumeration counter. They are always resetted
2048 * when there is any other layout between */
2049 for (int i = 6 + par->enumdepth; i < 10; ++i)
2050 par->setCounter(i, 0);
2055 /* Updates all counters BEHIND the row. Changed paragraphs
2056 * with a dynamic left margin will be rebroken. */
2057 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2064 if (row->par()->next
2066 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2070 par = row->par()->LastPhysicalPar()->Next();
2072 par = row->par()->Next();
2075 par = row->par()->next;
2080 while (row->par() != par)
2083 SetCounter(bview->buffer(), par);
2085 /* now check for the headline layouts. remember that they
2086 * have a dynamic left margin */
2091 ( textclasslist.Style(bview->buffer()->params.textclass,
2092 par->layout).margintype == MARGIN_DYNAMIC
2093 || textclasslist.Style(bview->buffer()->params.textclass,
2094 par->layout).labeltype == LABEL_SENSITIVE)
2097 /* Rebreak the paragraph */
2098 RemoveParagraph(row);
2099 AppendParagraph(bview, row);
2102 /* think about the damned open footnotes! */
2103 while (par->Next() &&
2104 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2105 || par->Next()->IsDummy())){
2107 if (par->IsDummy()) {
2108 while (row->par() != par)
2110 RemoveParagraph(row);
2111 AppendParagraph(bview, row);
2117 par = par->LastPhysicalPar()->Next();
2126 /* insets an inset. */
2127 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2129 if (!cursor.par()->InsertInsetAllowed(inset))
2131 SetUndo(bview->buffer(), Undo::INSERT,
2133 cursor.par()->ParFromPos(cursor.pos())->previous,
2134 cursor.par()->ParFromPos(cursor.pos())->next
2136 cursor.par()->previous,
2140 cursor.par()->InsertInset(cursor.pos(), inset);
2141 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2142 * The character will not be inserted a
2145 // if we enter a text-inset the cursor should be to the left side
2146 // of it! This couldn't happen before as Undo was not handled inside
2147 // inset now after the Undo LyX tries to call inset->Edit(...) again
2148 // and cannot do this as the cursor is behind the inset and GetInset
2149 // does not return the inset!
2150 if (inset->IsTextInset()) {
2151 if (cursor.par()->isRightToLeftPar(bview->buffer()->params))
2160 void LyXText::copyEnvironmentType()
2162 copylayouttype = cursor.par()->GetLayout();
2166 void LyXText::pasteEnvironmentType(BufferView * bview)
2168 SetLayout(bview, copylayouttype);
2172 void LyXText::CutSelection(BufferView * bview, bool doclear)
2174 // Stuff what we got on the clipboard. Even if there is no selection.
2176 // There is a problem with having the stuffing here in that the
2177 // larger the selection the slower LyX will get. This can be
2178 // solved by running the line below only when the selection has
2179 // finished. The solution used currently just works, to make it
2180 // faster we need to be more clever and probably also have more
2181 // calls to stuffClipboard. (Lgb)
2182 bview->stuffClipboard(selectionAsString(bview->buffer()));
2184 // This doesn't make sense, if there is no selection
2188 // OK, we have a selection. This is always between sel_start_cursor
2189 // and sel_end cursor
2191 // Check whether there are half footnotes in the selection
2192 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2193 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2194 LyXParagraph * tmppar = sel_start_cursor.par();
2195 while (tmppar != sel_end_cursor.par()){
2196 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2197 WriteAlert(_("Impossible operation"),
2198 _("Don't know what to do with half floats."),
2202 tmppar = tmppar->Next();
2207 // make sure that the depth behind the selection are restored, too
2209 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2211 LyXParagraph * endpar = sel_end_cursor.par()->Next();
2213 LyXParagraph * undoendpar = endpar;
2215 if (endpar && endpar->GetDepth()) {
2216 while (endpar && endpar->GetDepth()) {
2218 endpar = endpar->LastPhysicalPar()->Next();
2220 endpar = endpar->Next();
2222 undoendpar = endpar;
2224 } else if (endpar) {
2225 endpar = endpar->Next(); // because of parindents etc.
2228 SetUndo(bview->buffer(), Undo::DELETE,
2231 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2233 sel_start_cursor.par()->previous,
2239 // there are two cases: cut only within one paragraph or
2240 // more than one paragraph
2242 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2243 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2245 if (sel_start_cursor.par() == sel_end_cursor.par())
2248 // only within one paragraph
2249 endpar = sel_start_cursor.par();
2250 int pos = sel_end_cursor.pos();
2251 cap.cutSelection(sel_start_cursor.par(), &endpar,
2252 sel_start_cursor.pos(), pos,
2253 bview->buffer()->params.textclass, doclear);
2254 sel_end_cursor.pos(pos);
2256 endpar = sel_end_cursor.par();
2258 int pos = sel_end_cursor.pos();
2259 cap.cutSelection(sel_start_cursor.par(), &endpar,
2260 sel_start_cursor.pos(), pos,
2261 bview->buffer()->params.textclass, doclear);
2263 sel_end_cursor.par(endpar);
2264 sel_end_cursor.pos(pos);
2265 cursor.pos(sel_end_cursor.pos());
2267 endpar = endpar->Next();
2269 // sometimes necessary
2271 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2273 RedoParagraphs(bview, sel_start_cursor, endpar);
2276 cursor = sel_start_cursor;
2277 SetCursor(bview, cursor.par(), cursor.pos());
2278 sel_cursor = cursor;
2279 UpdateCounters(bview, cursor.row());
2283 void LyXText::CopySelection(BufferView * bview)
2285 // Stuff what we got on the clipboard. Even if there is no selection.
2287 // There is a problem with having the stuffing here in that the
2288 // larger the selection the slower LyX will get. This can be
2289 // solved by running the line below only when the selection has
2290 // finished. The solution used currently just works, to make it
2291 // faster we need to be more clever and probably also have more
2292 // calls to stuffClipboard. (Lgb)
2293 bview->stuffClipboard(selectionAsString(bview->buffer()));
2295 // this doesnt make sense, if there is no selection
2299 // ok we have a selection. This is always between sel_start_cursor
2300 // and sel_end cursor
2303 /* check wether there are half footnotes in the selection */
2304 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2305 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2306 LyXParagraph * tmppar = sel_start_cursor.par();
2307 while (tmppar != sel_end_cursor.par()) {
2308 if (tmppar->footnoteflag !=
2309 sel_end_cursor.par()->footnoteflag) {
2310 WriteAlert(_("Impossible operation"),
2311 _("Don't know what to do"
2312 " with half floats."),
2316 tmppar = tmppar->Next();
2321 // copy behind a space if there is one
2322 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2323 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2324 && (sel_start_cursor.par() != sel_end_cursor.par()
2325 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2326 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2330 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2331 sel_start_cursor.pos(), sel_end_cursor.pos(),
2332 bview->buffer()->params.textclass);
2336 void LyXText::PasteSelection(BufferView * bview)
2340 // this does not make sense, if there is nothing to paste
2341 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2344 SetUndo(bview->buffer(), Undo::INSERT,
2346 cursor.par()->ParFromPos(cursor.pos())->previous,
2347 cursor.par()->ParFromPos(cursor.pos())->next
2349 cursor.par()->previous,
2354 LyXParagraph * endpar;
2355 LyXParagraph * actpar = cursor.par();
2357 int pos = cursor.pos();
2358 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2360 RedoParagraphs(bview, cursor, endpar);
2362 SetCursor(bview, cursor.par(), cursor.pos());
2365 sel_cursor = cursor;
2366 SetCursor(bview, actpar, pos);
2368 UpdateCounters(bview, cursor.row());
2372 // returns a pointer to the very first LyXParagraph
2373 LyXParagraph * LyXText::FirstParagraph() const
2375 return OwnerParagraph();
2379 // returns true if the specified string is at the specified position
2380 bool LyXText::IsStringInText(LyXParagraph * par,
2381 LyXParagraph::size_type pos,
2382 string const & str) const
2387 LyXParagraph::size_type i = 0;
2388 while (pos + i < par->Last()
2389 && string::size_type(i) < str.length()
2390 && str[i] == par->GetChar(pos + i)) {
2393 if (str.length() == string::size_type(i))
2399 // sets the selection over the number of characters of string, no check!!
2400 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2402 sel_cursor = cursor;
2403 for (int i = 0; str[i]; ++i)
2409 // simple replacing. The font of the first selected character is used
2410 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2413 SetCursorParUndo(bview->buffer());
2416 if (!selection) { // create a dummy selection
2417 sel_end_cursor = cursor;
2418 sel_start_cursor = cursor;
2421 // Get font setting before we cut
2422 LyXParagraph::size_type pos = sel_end_cursor.pos();
2423 LyXFont const font = sel_start_cursor.par()
2424 ->GetFontSettings(bview->buffer()->params,
2425 sel_start_cursor.pos());
2427 // Insert the new string
2428 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2429 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2433 // Cut the selection
2434 CutSelection(bview);
2440 // if the string can be found: return true and set the cursor to
2442 bool LyXText::SearchForward(BufferView * bview, string const & str) const
2444 LyXParagraph * par = cursor.par();
2445 LyXParagraph::size_type pos = cursor.pos();
2446 while (par && !IsStringInText(par, pos, str)) {
2447 if (pos < par->Last() - 1)
2455 SetCursor(bview, par, pos);
2463 bool LyXText::SearchBackward(BufferView * bview, string const & str) const
2465 LyXParagraph * par = cursor.par();
2466 int pos = cursor.pos();
2472 // We skip empty paragraphs (Asger)
2474 par = par->Previous();
2476 pos = par->Last() - 1;
2477 } while (par && pos < 0);
2479 } while (par && !IsStringInText(par, pos, str));
2482 SetCursor(bview, par, pos);
2489 // needed to insert the selection
2490 void LyXText::InsertStringA(BufferView * bview, string const & str)
2492 LyXParagraph * par = cursor.par();
2493 LyXParagraph::size_type pos = cursor.pos();
2494 LyXParagraph::size_type a = 0;
2495 LyXParagraph * endpar = cursor.par()->Next();
2497 SetCursorParUndo(bview->buffer());
2500 textclasslist.Style(bview->buffer()->params.textclass,
2501 cursor.par()->GetLayout()).isEnvironment();
2502 // only to be sure, should not be neccessary
2505 // insert the string, don't insert doublespace
2506 string::size_type i = 0;
2507 while (i < str.length()) {
2508 if (str[i] != '\n') {
2510 && i + 1 < str.length() && str[i + 1] != ' '
2511 && pos && par->GetChar(pos - 1)!= ' ') {
2512 par->InsertChar(pos, ' ', current_font);
2514 } else if (str[i] == ' ') {
2515 InsetSpecialChar * new_inset =
2516 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2517 if (par->InsertInsetAllowed(new_inset)) {
2518 par->InsertInset(pos, new_inset,
2524 } else if (str[i] == '\t') {
2525 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2526 InsetSpecialChar * new_inset =
2527 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2528 if (par->InsertInsetAllowed(new_inset)) {
2529 par->InsertInset(pos, new_inset,
2536 } else if (str[i] != 13 &&
2537 // Ignore unprintables
2538 (str[i] & 127) >= ' ') {
2539 par->InsertChar(pos, str[i], current_font);
2543 if (!par->size()) { // par is empty
2544 InsetSpecialChar * new_inset =
2545 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2546 if (par->InsertInsetAllowed(new_inset)) {
2547 par->InsertInset(pos,
2555 par->BreakParagraph(bview->buffer()->params, pos, flag);
2562 RedoParagraphs(bview, cursor, endpar);
2563 SetCursor(bview, cursor.par(), cursor.pos());
2564 sel_cursor = cursor;
2565 SetCursor(bview, par, pos);
2570 /* turns double-CR to single CR, others where converted into one blank and 13s
2571 * that are ignored .Double spaces are also converted into one. Spaces at
2572 * the beginning of a paragraph are forbidden. tabs are converted into one
2573 * space. then InsertStringA is called */
2574 void LyXText::InsertStringB(BufferView * bview, string const & s)
2577 string::size_type i = 1;
2578 while (i < str.length()) {
2581 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2583 if (str[i] == '\n' && i + 1 < str.length()) {
2584 if (str[i + 1] != '\n') {
2585 if (str[i - 1] != ' ')
2590 while (i + 1 < str.length()
2591 && (str[i + 1] == ' '
2592 || str[i + 1] == '\t'
2593 || str[i + 1] == '\n'
2594 || str[i + 1] == 13)) {
2601 InsertStringA(bview, str);
2605 bool LyXText::GotoNextError(BufferView * bview) const
2607 LyXCursor res = cursor;
2609 if (res.pos() < res.par()->Last() - 1) {
2610 res.pos(res.pos() + 1);
2612 res.par(res.par()->Next());
2616 } while (res.par() &&
2617 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2618 && res.par()->GetInset(res.pos())->AutoDelete()));
2621 SetCursor(bview, res.par(), res.pos());
2628 bool LyXText::GotoNextNote(BufferView * bview) const
2630 LyXCursor res = cursor;
2632 if (res.pos() < res.par()->Last() - 1) {
2633 res.pos(res.pos() + 1);
2635 res.par(res.par()->Next());
2639 } while (res.par() &&
2640 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2641 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2644 SetCursor(bview, res.par(), res.pos());
2651 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2652 LyXParagraph::size_type pos)
2654 LyXCursor tmpcursor;
2657 LyXParagraph::size_type z;
2658 Row * row = GetRow(par, pos, y);
2660 // is there a break one row above
2661 if (row->previous() && row->previous()->par() == row->par()) {
2662 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2663 if ( z >= row->pos()) {
2664 // set the dimensions of the row above
2665 y -= row->previous()->height();
2667 refresh_row = row->previous();
2668 status = LyXText::NEED_MORE_REFRESH;
2670 BreakAgain(bview, row->previous());
2672 // set the cursor again. Otherwise
2673 // dangling pointers are possible
2674 SetCursor(bview, cursor.par(), cursor.pos());
2675 sel_cursor = cursor;
2680 int const tmpheight = row->height();
2681 LyXParagraph::size_type const tmplast = RowLast(row);
2685 BreakAgain(bview, row);
2686 if (row->height() == tmpheight && RowLast(row) == tmplast)
2687 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2689 status = LyXText::NEED_MORE_REFRESH;
2691 // check the special right address boxes
2692 if (textclasslist.Style(bview->buffer()->params.textclass,
2693 par->GetLayout()).margintype
2694 == MARGIN_RIGHT_ADDRESS_BOX) {
2701 RedoDrawingOfParagraph(bview, tmpcursor);
2704 // set the cursor again. Otherwise dangling pointers are possible
2705 // also set the selection
2709 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2710 sel_cursor = cursor;
2711 SetCursorIntern(bview, sel_start_cursor.par(),
2712 sel_start_cursor.pos());
2713 sel_start_cursor = cursor;
2714 SetCursorIntern(bview, sel_end_cursor.par(),
2715 sel_end_cursor.pos());
2716 sel_end_cursor = cursor;
2717 SetCursorIntern(bview, last_sel_cursor.par(),
2718 last_sel_cursor.pos());
2719 last_sel_cursor = cursor;
2722 SetCursorIntern(bview, cursor.par(), cursor.pos());
2726 // returns false if inset wasn't found
2727 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2729 // first check the current paragraph
2730 int pos = cursor.par()->GetPositionOfInset(inset);
2732 CheckParagraph(bview, cursor.par(), pos);
2736 // check every paragraph
2738 LyXParagraph * par = FirstParagraph();
2741 // make sure the paragraph is open
2742 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2744 pos = par->GetPositionOfInset(inset);
2746 CheckParagraph(bview, par, pos);
2759 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2760 LyXParagraph::size_type pos,
2761 bool setfont, bool boundary) const
2763 LyXCursor old_cursor = cursor;
2764 SetCursorIntern(bview, par, pos, setfont, boundary);
2765 DeleteEmptyParagraphMechanism(bview, old_cursor);
2769 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2770 LyXParagraph::size_type pos, bool boundary) const
2773 // correct the cursor position if impossible
2774 if (pos > par->Last()){
2775 LyXParagraph * tmppar = par->ParFromPos(pos);
2776 pos = par->PositionInParFromPos(pos);
2779 if (par->IsDummy() && par->previous &&
2780 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2781 while (par->previous &&
2782 ((par->previous->IsDummy() &&
2783 (par->previous->previous->footnoteflag ==
2784 LyXParagraph::CLOSED_FOOTNOTE)) ||
2785 (par->previous->footnoteflag ==
2786 LyXParagraph::CLOSED_FOOTNOTE))) {
2787 par = par->previous ;
2788 if (par->IsDummy() &&
2789 (par->previous->footnoteflag ==
2790 LyXParagraph::CLOSED_FOOTNOTE))
2791 pos += par->size() + 1;
2793 if (par->previous) {
2794 par = par->previous;
2796 pos += par->size() + 1;
2801 cur.boundary(boundary);
2803 /* get the cursor y position in text */
2805 Row * row = GetRow(par, pos, y);
2806 /* y is now the beginning of the cursor row */
2807 y += row->baseline();
2808 /* y is now the cursor baseline */
2811 /* now get the cursors x position */
2813 float fill_separator, fill_hfill, fill_label_hfill;
2814 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2816 LyXParagraph::size_type cursor_vpos = 0;
2817 LyXParagraph::size_type last = RowLastPrintable(row);
2819 if (pos > last + 1) // This shouldn't happen.
2821 else if (pos < row->pos())
2824 if (last < row->pos())
2825 cursor_vpos = row->pos();
2826 else if (pos > last && !boundary)
2827 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2828 ? row->pos() : last + 1;
2829 else if (pos > row->pos() &&
2830 (pos > last || boundary))
2831 /// Place cursor after char at (logical) position pos - 1
2832 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2833 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2835 /// Place cursor before char at (logical) position pos
2836 cursor_vpos = (bidi_level(pos) % 2 == 0)
2837 ? log2vis(pos) : log2vis(pos) + 1;
2839 LyXParagraph::size_type main_body =
2840 BeginningOfMainBody(bview->buffer(), row->par());
2841 if ((main_body > 0) &&
2842 ((main_body-1 > last) ||
2843 !row->par()->IsLineSeparator(main_body-1)))
2846 for (LyXParagraph::size_type vpos = row->pos();
2847 vpos < cursor_vpos; ++vpos) {
2848 pos = vis2log(vpos);
2849 if (main_body > 0 && pos == main_body - 1) {
2850 x += fill_label_hfill +
2851 lyxfont::width(textclasslist.Style(
2852 bview->buffer()->params.textclass,
2853 row->par()->GetLayout())
2855 GetFont(bview->buffer(), row->par(), -2));
2856 if (row->par()->IsLineSeparator(main_body-1))
2857 x -= SingleWidth(bview, row->par(),main_body-1);
2859 if (HfillExpansion(bview->buffer(), row, pos)) {
2860 x += SingleWidth(bview, row->par(), pos);
2861 if (pos >= main_body)
2864 x += fill_label_hfill;
2865 } else if (row->par()->IsSeparator(pos)) {
2866 x += SingleWidth(bview, row->par(), pos);
2867 if (pos >= main_body)
2868 x += fill_separator;
2870 x += SingleWidth(bview, row->par(), pos);
2879 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2880 LyXParagraph::size_type pos,
2881 bool setfont, bool boundary) const
2883 SetCursor(bview, cursor, par, pos, boundary);
2885 SetCurrentFont(bview);
2889 void LyXText::SetCurrentFont(BufferView * bview) const
2891 LyXParagraph::size_type pos = cursor.pos();
2892 if (cursor.boundary() && pos > 0)
2896 if (pos == cursor.par()->Last())
2898 else if (cursor.par()->IsSeparator(pos)) {
2899 if (pos > cursor.row()->pos() &&
2900 bidi_level(pos) % 2 ==
2901 bidi_level(pos - 1) % 2)
2903 else if (pos + 1 < cursor.par()->Last())
2909 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2910 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2912 if (cursor.pos() == cursor.par()->Last() &&
2913 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2914 !cursor.boundary()) {
2915 Language const * lang =
2916 cursor.par()->getParLanguage(bview->buffer()->params);
2917 current_font.setLanguage(lang);
2918 real_current_font.setLanguage(lang);
2923 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2925 LyXCursor old_cursor = cursor;
2927 /* get the row first */
2929 Row * row = GetRowNearY(y);
2930 cursor.par(row->par());
2933 int column = GetColumnNearX(bview, row, x, bound);
2934 cursor.pos(row->pos() + column);
2936 cursor.y(y + row->baseline());
2938 cursor.boundary(bound);
2939 SetCurrentFont(bview);
2940 DeleteEmptyParagraphMechanism(bview, old_cursor);
2944 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2947 /* get the row first */
2949 Row * row = GetRowNearY(y);
2951 int column = GetColumnNearX(bview, row, x, bound);
2953 cur.par(row->par());
2954 cur.pos(row->pos() + column);
2956 cur.y(y + row->baseline());
2958 cur.boundary(bound);
2962 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2964 if (cursor.pos() > 0) {
2965 bool boundary = cursor.boundary();
2966 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2967 if (!internal && !boundary &&
2968 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2969 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2970 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2971 LyXParagraph * par = cursor.par()->Previous();
2972 SetCursor(bview, par, par->Last());
2977 void LyXText::CursorRight(BufferView * bview, bool internal) const
2979 if (!internal && cursor.boundary() &&
2980 !cursor.par()->IsNewline(cursor.pos()))
2981 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2982 else if (cursor.pos() < cursor.par()->Last()) {
2983 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2985 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2986 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2987 } else if (cursor.par()->Next())
2988 SetCursor(bview, cursor.par()->Next(), 0);
2992 void LyXText::CursorUp(BufferView * bview) const
2994 SetCursorFromCoordinates(bview, cursor.x_fix(),
2995 cursor.y() - cursor.row()->baseline() - 1);
2999 void LyXText::CursorDown(BufferView * bview) const
3001 SetCursorFromCoordinates(bview, cursor.x_fix(),
3002 cursor.y() - cursor.row()->baseline()
3003 + cursor.row()->height() + 1);
3007 void LyXText::CursorUpParagraph(BufferView * bview) const
3009 if (cursor.pos() > 0) {
3010 SetCursor(bview, cursor.par(), 0);
3012 else if (cursor.par()->Previous()) {
3013 SetCursor(bview, cursor.par()->Previous(), 0);
3018 void LyXText::CursorDownParagraph(BufferView * bview) const
3020 if (cursor.par()->Next()) {
3021 SetCursor(bview, cursor.par()->Next(), 0);
3023 SetCursor(bview, cursor.par(), cursor.par()->Last());
3028 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3029 LyXCursor const & old_cursor) const
3031 // Would be wrong to delete anything if we have a selection.
3032 if (selection) return;
3034 // We allow all kinds of "mumbo-jumbo" when freespacing.
3035 if (textclasslist.Style(bview->buffer()->params.textclass,
3036 old_cursor.par()->GetLayout()).free_spacing)
3039 bool deleted = false;
3041 /* Ok I'll put some comments here about what is missing.
3042 I have fixed BackSpace (and thus Delete) to not delete
3043 double-spaces automagically. I have also changed Cut,
3044 Copy and Paste to hopefully do some sensible things.
3045 There are still some small problems that can lead to
3046 double spaces stored in the document file or space at
3047 the beginning of paragraphs. This happens if you have
3048 the cursor betwenn to spaces and then save. Or if you
3049 cut and paste and the selection have a space at the
3050 beginning and then save right after the paste. I am
3051 sure none of these are very hard to fix, but I will
3052 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3053 that I can get some feedback. (Lgb)
3056 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3057 // delete the LineSeparator.
3060 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3061 // delete the LineSeparator.
3064 // If the pos around the old_cursor were spaces, delete one of them.
3065 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3066 // Only if the cursor has really moved
3068 if (old_cursor.pos() > 0
3069 && old_cursor.pos() < old_cursor.par()->Last()
3070 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3071 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3072 old_cursor.par()->Erase(old_cursor.pos() - 1);
3073 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3075 if (old_cursor.par() == cursor.par() &&
3076 cursor.pos() > old_cursor.pos()) {
3077 SetCursorIntern(bview, cursor.par(),
3080 SetCursorIntern(bview, cursor.par(),
3086 // Do not delete empty paragraphs with keepempty set.
3087 if ((textclasslist.Style(bview->buffer()->params.textclass,
3088 old_cursor.par()->GetLayout())).keepempty)
3091 LyXCursor tmpcursor;
3093 if (old_cursor.par() != cursor.par()) {
3094 if ( (old_cursor.par()->Last() == 0
3095 || (old_cursor.par()->Last() == 1
3096 && old_cursor.par()->IsLineSeparator(0)))
3098 && old_cursor.par()->FirstPhysicalPar()
3099 == old_cursor.par()->LastPhysicalPar()
3102 // ok, we will delete anything
3104 // make sure that you do not delete any environments
3107 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3108 !(old_cursor.row()->previous()
3109 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3110 && !(old_cursor.row()->next()
3111 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3112 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3113 && ((old_cursor.row()->previous()
3114 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3115 || (old_cursor.row()->next()
3116 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3119 status = LyXText::NEED_MORE_REFRESH;
3122 if (old_cursor.row()->previous()) {
3123 refresh_row = old_cursor.row()->previous();
3124 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3126 cursor = old_cursor; // that undo can restore the right cursor position
3127 LyXParagraph * endpar = old_cursor.par()->next;
3128 if (endpar && endpar->GetDepth()) {
3129 while (endpar && endpar->GetDepth()) {
3131 endpar = endpar->LastPhysicalPar()->Next();
3133 endpar = endpar->Next();
3137 SetUndo(bview->buffer(), Undo::DELETE,
3138 old_cursor.par()->previous,
3143 RemoveRow(old_cursor.row());
3144 if (OwnerParagraph() == old_cursor.par()) {
3145 OwnerParagraph(OwnerParagraph()->next);
3148 delete old_cursor.par();
3150 /* Breakagain the next par. Needed
3151 * because of the parindent that
3152 * can occur or dissappear. The
3153 * next row can change its height,
3154 * if there is another layout before */
3155 if (refresh_row->next()) {
3156 BreakAgain(bview, refresh_row->next());
3157 UpdateCounters(bview, refresh_row);
3159 SetHeightOfRow(bview, refresh_row);
3161 refresh_row = old_cursor.row()->next();
3162 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3165 cursor = old_cursor; // that undo can restore the right cursor position
3166 LyXParagraph * endpar = old_cursor.par()->next;
3167 if (endpar && endpar->GetDepth()) {
3168 while (endpar && endpar->GetDepth()) {
3170 endpar = endpar->LastPhysicalPar()->Next();
3172 endpar = endpar->Next();
3176 SetUndo(bview->buffer(), Undo::DELETE,
3177 old_cursor.par()->previous,
3182 RemoveRow(old_cursor.row());
3184 if (OwnerParagraph() == old_cursor.par()) {
3185 OwnerParagraph(OwnerParagraph()->next);
3187 delete old_cursor.par();
3189 /* Breakagain the next par. Needed
3190 because of the parindent that can
3191 occur or dissappear.
3192 The next row can change its height,
3193 if there is another layout before
3196 BreakAgain(bview, refresh_row);
3197 UpdateCounters(bview, refresh_row->previous());
3203 SetCursorIntern(bview, cursor.par(), cursor.pos());
3205 if (sel_cursor.par() == old_cursor.par()
3206 && sel_cursor.pos() == sel_cursor.pos()) {
3207 // correct selection
3208 sel_cursor = cursor;
3215 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3216 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3218 SetCursorIntern(bview, cursor.par(), cursor.pos());
3219 sel_cursor = cursor;
3226 LyXParagraph * LyXText::GetParFromID(int id)
3228 LyXParagraph * result = FirstParagraph();
3229 while (result && result->id() != id)
3230 result = result->next;
3236 bool LyXText::TextUndo(BufferView * bview)
3240 // returns false if no undo possible
3241 Undo * undo = bview->buffer()->undostack.pop();
3245 bview->buffer()->redostack
3246 .push(CreateUndo(bview->buffer(), undo->kind,
3247 GetParFromID(undo->number_of_before_par),
3248 GetParFromID(undo->number_of_behind_par)));
3250 return TextHandleUndo(bview, undo);
3254 bool LyXText::TextRedo(BufferView * bview)
3258 // returns false if no redo possible
3259 Undo * undo = bview->buffer()->redostack.pop();
3263 bview->buffer()->undostack
3264 .push(CreateUndo(bview->buffer(), undo->kind,
3265 GetParFromID(undo->number_of_before_par),
3266 GetParFromID(undo->number_of_behind_par)));
3268 return TextHandleUndo(bview, undo);
3272 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3276 // returns false if no undo possible
3277 bool result = false;
3279 LyXParagraph * before =
3280 GetParFromID(undo->number_of_before_par);
3281 LyXParagraph * behind =
3282 GetParFromID(undo->number_of_behind_par);
3283 LyXParagraph * tmppar;
3284 LyXParagraph * tmppar2;
3285 LyXParagraph * endpar;
3286 LyXParagraph * tmppar5;
3288 // if there's no before take the beginning
3289 // of the document for redoing
3291 SetCursorIntern(bview, FirstParagraph(), 0);
3293 // replace the paragraphs with the undo informations
3295 LyXParagraph * tmppar3 = undo->par;
3296 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3297 LyXParagraph * tmppar4 = tmppar3;
3299 while (tmppar4->next)
3300 tmppar4 = tmppar4->next;
3301 } // get last undo par
3303 // now remove the old text if there is any
3304 if (before != behind || (!behind && !before)){
3306 tmppar5 = before->next;
3308 tmppar5 = OwnerParagraph();
3310 while (tmppar5 && tmppar5 != behind){
3312 tmppar5 = tmppar5->next;
3313 // a memory optimization for edit: Only layout information
3314 // is stored in the undo. So restore the text informations.
3315 if (undo->kind == Undo::EDIT) {
3316 tmppar2->setContentsFromPar(tmppar);
3317 tmppar->clearContents();
3318 tmppar2 = tmppar2->next;
3323 // put the new stuff in the list if there is one
3326 before->next = tmppar3;
3328 OwnerParagraph(tmppar3);
3329 tmppar3->previous = before;
3332 OwnerParagraph(behind);
3335 tmppar4->next = behind;
3337 behind->previous = tmppar4;
3341 // Set the cursor for redoing
3344 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3346 SetCursorIntern(bview, before, 0);
3349 // check wether before points to a closed float and open it if necessary
3350 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3351 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3353 while (tmppar4->previous &&
3354 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3355 tmppar4 = tmppar4->previous;
3356 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3357 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3358 tmppar4 = tmppar4->next;
3365 // open a cosed footnote at the end if necessary
3366 if (behind && behind->previous &&
3367 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3368 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3369 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3370 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3371 behind = behind->next;
3376 // calculate the endpar for redoing the paragraphs.
3379 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3380 endpar = behind->LastPhysicalPar()->Next();
3382 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3384 endpar = behind->Next();
3389 tmppar = GetParFromID(undo->number_of_cursor_par);
3390 RedoParagraphs(bview, cursor, endpar);
3392 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3393 UpdateCounters(bview, cursor.row());
3403 void LyXText::FinishUndo()
3407 // makes sure the next operation will be stored
3408 undo_finished = true;
3412 void LyXText::FreezeUndo()
3416 // this is dangerous and for internal use only
3421 void LyXText::UnFreezeUndo()
3425 // this is dangerous and for internal use only
3426 undo_frozen = false;
3430 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3431 LyXParagraph const * before,
3432 LyXParagraph const * behind) const
3437 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3438 buf->redostack.clear();
3442 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3443 LyXParagraph const * before, LyXParagraph const * behind)
3447 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3451 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3452 LyXParagraph const * before,
3453 LyXParagraph const * behind) const
3458 int before_number = -1;
3459 int behind_number = -1;
3461 before_number = before->id();
3463 behind_number = behind->id();
3464 // Undo::EDIT and Undo::FINISH are
3465 // always finished. (no overlapping there)
3466 // overlapping only with insert and delete inside one paragraph:
3467 // Nobody wants all removed character
3468 // appear one by one when undoing.
3469 // EDIT is special since only layout information, not the
3470 // contents of a paragaph are stored.
3471 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3472 // check wether storing is needed
3473 if (!buf->undostack.empty() &&
3474 buf->undostack.top()->kind == kind &&
3475 buf->undostack.top()->number_of_before_par == before_number &&
3476 buf->undostack.top()->number_of_behind_par == behind_number ){
3481 // create a new Undo
3482 LyXParagraph * undopar;
3483 LyXParagraph * tmppar;
3484 LyXParagraph * tmppar2;
3486 LyXParagraph * start = 0;
3487 LyXParagraph * end = 0;
3490 start = before->next;
3492 start = FirstParagraph();
3494 end = behind->previous;
3496 end = FirstParagraph();
3502 && start != end->next
3503 && (before != behind || (!before && !behind))) {
3505 tmppar2 = tmppar->Clone();
3506 tmppar2->id(tmppar->id());
3508 // a memory optimization: Just store the layout information
3510 if (kind == Undo::EDIT){
3511 //tmppar2->text.clear();
3512 tmppar2->clearContents();
3517 while (tmppar != end && tmppar->next) {
3518 tmppar = tmppar->next;
3519 tmppar2->next = tmppar->Clone();
3520 tmppar2->next->id(tmppar->id());
3521 // a memory optimization: Just store the layout
3522 // information when only edit
3523 if (kind == Undo::EDIT){
3524 //tmppar2->next->text.clear();
3525 tmppar2->clearContents();
3527 tmppar2->next->previous = tmppar2;
3528 tmppar2 = tmppar2->next;
3532 undopar = 0; // nothing to replace (undo of delete maybe)
3535 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3536 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3538 int cursor_par = cursor.par()->id();
3539 int cursor_pos = cursor.pos();
3542 Undo * undo = new Undo(kind,
3543 before_number, behind_number,
3544 cursor_par, cursor_pos,
3547 undo_finished = false;
3552 void LyXText::SetCursorParUndo(Buffer * buf)
3556 SetUndo(buf, Undo::FINISH,
3558 cursor.par()->ParFromPos(cursor.pos())->previous,
3559 cursor.par()->ParFromPos(cursor.pos())->next
3561 cursor.par()->previous,
3568 void LyXText::toggleAppendix(BufferView * bview)
3571 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3573 LyXParagraph * par = cursor.par();
3575 bool start = !par->start_of_appendix;
3577 // ensure that we have only one start_of_appendix in this document
3578 LyXParagraph * tmp = FirstParagraph();
3579 for (; tmp; tmp = tmp->next)
3580 tmp->start_of_appendix = 0;
3581 par->start_of_appendix = start;
3583 // we can set the refreshing parameters now
3584 status = LyXText::NEED_MORE_REFRESH;
3586 refresh_row = 0; // not needed for full update
3587 UpdateCounters(bview, 0);
3588 SetCursor(bview, cursor.par(), cursor.pos());
3592 LyXParagraph * LyXText::OwnerParagraph() const
3595 return inset_owner->par;
3597 return bv_owner->buffer()->paragraph;
3601 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3604 inset_owner->par = p;
3606 bv_owner->buffer()->paragraph = p;