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 false, cursor.boundary());
2679 sel_cursor = cursor;
2684 int const tmpheight = row->height();
2685 LyXParagraph::size_type const tmplast = RowLast(row);
2689 BreakAgain(bview, row);
2690 if (row->height() == tmpheight && RowLast(row) == tmplast)
2691 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2693 status = LyXText::NEED_MORE_REFRESH;
2695 // check the special right address boxes
2696 if (textclasslist.Style(bview->buffer()->params.textclass,
2697 par->GetLayout()).margintype
2698 == MARGIN_RIGHT_ADDRESS_BOX) {
2705 RedoDrawingOfParagraph(bview, tmpcursor);
2708 // set the cursor again. Otherwise dangling pointers are possible
2709 // also set the selection
2713 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2714 false, sel_cursor.boundary());
2715 sel_cursor = cursor;
2716 SetCursorIntern(bview, sel_start_cursor.par(),
2717 sel_start_cursor.pos(),
2718 false, sel_start_cursor.boundary());
2719 sel_start_cursor = cursor;
2720 SetCursorIntern(bview, sel_end_cursor.par(),
2721 sel_end_cursor.pos(),
2722 false, sel_end_cursor.boundary());
2723 sel_end_cursor = cursor;
2724 SetCursorIntern(bview, last_sel_cursor.par(),
2725 last_sel_cursor.pos(),
2726 false, last_sel_cursor.boundary());
2727 last_sel_cursor = cursor;
2730 SetCursorIntern(bview, cursor.par(), cursor.pos(),
2731 false, cursor.boundary());
2735 // returns false if inset wasn't found
2736 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2738 // first check the current paragraph
2739 int pos = cursor.par()->GetPositionOfInset(inset);
2741 CheckParagraph(bview, cursor.par(), pos);
2745 // check every paragraph
2747 LyXParagraph * par = FirstParagraph();
2750 // make sure the paragraph is open
2751 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2753 pos = par->GetPositionOfInset(inset);
2755 CheckParagraph(bview, par, pos);
2768 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2769 LyXParagraph::size_type pos,
2770 bool setfont, bool boundary) const
2772 LyXCursor old_cursor = cursor;
2773 SetCursorIntern(bview, par, pos, setfont, boundary);
2774 DeleteEmptyParagraphMechanism(bview, old_cursor);
2778 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2779 LyXParagraph::size_type pos, bool boundary) const
2782 // correct the cursor position if impossible
2783 if (pos > par->Last()){
2784 LyXParagraph * tmppar = par->ParFromPos(pos);
2785 pos = par->PositionInParFromPos(pos);
2788 if (par->IsDummy() && par->previous &&
2789 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2790 while (par->previous &&
2791 ((par->previous->IsDummy() &&
2792 (par->previous->previous->footnoteflag ==
2793 LyXParagraph::CLOSED_FOOTNOTE)) ||
2794 (par->previous->footnoteflag ==
2795 LyXParagraph::CLOSED_FOOTNOTE))) {
2796 par = par->previous ;
2797 if (par->IsDummy() &&
2798 (par->previous->footnoteflag ==
2799 LyXParagraph::CLOSED_FOOTNOTE))
2800 pos += par->size() + 1;
2802 if (par->previous) {
2803 par = par->previous;
2805 pos += par->size() + 1;
2810 cur.boundary(boundary);
2812 /* get the cursor y position in text */
2814 Row * row = GetRow(par, pos, y);
2815 /* y is now the beginning of the cursor row */
2816 y += row->baseline();
2817 /* y is now the cursor baseline */
2820 /* now get the cursors x position */
2822 float fill_separator, fill_hfill, fill_label_hfill;
2823 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2825 LyXParagraph::size_type cursor_vpos = 0;
2826 LyXParagraph::size_type last = RowLastPrintable(row);
2828 if (pos > last + 1) // This shouldn't happen.
2830 else if (pos < row->pos())
2833 if (last < row->pos())
2834 cursor_vpos = row->pos();
2835 else if (pos > last && !boundary)
2836 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2837 ? row->pos() : last + 1;
2838 else if (pos > row->pos() &&
2839 (pos > last || boundary))
2840 /// Place cursor after char at (logical) position pos - 1
2841 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2842 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2844 /// Place cursor before char at (logical) position pos
2845 cursor_vpos = (bidi_level(pos) % 2 == 0)
2846 ? log2vis(pos) : log2vis(pos) + 1;
2848 LyXParagraph::size_type main_body =
2849 BeginningOfMainBody(bview->buffer(), row->par());
2850 if ((main_body > 0) &&
2851 ((main_body-1 > last) ||
2852 !row->par()->IsLineSeparator(main_body-1)))
2855 for (LyXParagraph::size_type vpos = row->pos();
2856 vpos < cursor_vpos; ++vpos) {
2857 pos = vis2log(vpos);
2858 if (main_body > 0 && pos == main_body - 1) {
2859 x += fill_label_hfill +
2860 lyxfont::width(textclasslist.Style(
2861 bview->buffer()->params.textclass,
2862 row->par()->GetLayout())
2864 GetFont(bview->buffer(), row->par(), -2));
2865 if (row->par()->IsLineSeparator(main_body-1))
2866 x -= SingleWidth(bview, row->par(),main_body-1);
2868 if (HfillExpansion(bview->buffer(), row, pos)) {
2869 x += SingleWidth(bview, row->par(), pos);
2870 if (pos >= main_body)
2873 x += fill_label_hfill;
2874 } else if (row->par()->IsSeparator(pos)) {
2875 x += SingleWidth(bview, row->par(), pos);
2876 if (pos >= main_body)
2877 x += fill_separator;
2879 x += SingleWidth(bview, row->par(), pos);
2888 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2889 LyXParagraph::size_type pos,
2890 bool setfont, bool boundary) const
2892 SetCursor(bview, cursor, par, pos, boundary);
2894 SetCurrentFont(bview);
2898 void LyXText::SetCurrentFont(BufferView * bview) const
2900 LyXParagraph::size_type pos = cursor.pos();
2901 if (cursor.boundary() && pos > 0)
2905 if (pos == cursor.par()->Last())
2907 else if (cursor.par()->IsSeparator(pos)) {
2908 if (pos > cursor.row()->pos() &&
2909 bidi_level(pos) % 2 ==
2910 bidi_level(pos - 1) % 2)
2912 else if (pos + 1 < cursor.par()->Last())
2918 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2919 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2921 if (cursor.pos() == cursor.par()->Last() &&
2922 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2923 !cursor.boundary()) {
2924 Language const * lang =
2925 cursor.par()->getParLanguage(bview->buffer()->params);
2926 current_font.setLanguage(lang);
2927 real_current_font.setLanguage(lang);
2932 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2934 LyXCursor old_cursor = cursor;
2936 /* get the row first */
2938 Row * row = GetRowNearY(y);
2939 cursor.par(row->par());
2942 int column = GetColumnNearX(bview, row, x, bound);
2943 cursor.pos(row->pos() + column);
2945 cursor.y(y + row->baseline());
2947 cursor.boundary(bound);
2948 SetCurrentFont(bview);
2949 DeleteEmptyParagraphMechanism(bview, old_cursor);
2953 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2956 /* get the row first */
2958 Row * row = GetRowNearY(y);
2960 int column = GetColumnNearX(bview, row, x, bound);
2962 cur.par(row->par());
2963 cur.pos(row->pos() + column);
2965 cur.y(y + row->baseline());
2967 cur.boundary(bound);
2971 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2973 if (cursor.pos() > 0) {
2974 bool boundary = cursor.boundary();
2975 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2976 if (!internal && !boundary &&
2977 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2978 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2979 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2980 LyXParagraph * par = cursor.par()->Previous();
2981 SetCursor(bview, par, par->Last());
2986 void LyXText::CursorRight(BufferView * bview, bool internal) const
2988 if (!internal && cursor.boundary() &&
2989 !cursor.par()->IsNewline(cursor.pos()))
2990 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2991 else if (cursor.pos() < cursor.par()->Last()) {
2992 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2994 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2995 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2996 } else if (cursor.par()->Next())
2997 SetCursor(bview, cursor.par()->Next(), 0);
3001 void LyXText::CursorUp(BufferView * bview) const
3003 SetCursorFromCoordinates(bview, cursor.x_fix(),
3004 cursor.y() - cursor.row()->baseline() - 1);
3008 void LyXText::CursorDown(BufferView * bview) const
3010 SetCursorFromCoordinates(bview, cursor.x_fix(),
3011 cursor.y() - cursor.row()->baseline()
3012 + cursor.row()->height() + 1);
3016 void LyXText::CursorUpParagraph(BufferView * bview) const
3018 if (cursor.pos() > 0) {
3019 SetCursor(bview, cursor.par(), 0);
3021 else if (cursor.par()->Previous()) {
3022 SetCursor(bview, cursor.par()->Previous(), 0);
3027 void LyXText::CursorDownParagraph(BufferView * bview) const
3029 if (cursor.par()->Next()) {
3030 SetCursor(bview, cursor.par()->Next(), 0);
3032 SetCursor(bview, cursor.par(), cursor.par()->Last());
3037 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3038 LyXCursor const & old_cursor) const
3040 // Would be wrong to delete anything if we have a selection.
3041 if (selection) return;
3043 // We allow all kinds of "mumbo-jumbo" when freespacing.
3044 if (textclasslist.Style(bview->buffer()->params.textclass,
3045 old_cursor.par()->GetLayout()).free_spacing)
3048 bool deleted = false;
3050 /* Ok I'll put some comments here about what is missing.
3051 I have fixed BackSpace (and thus Delete) to not delete
3052 double-spaces automagically. I have also changed Cut,
3053 Copy and Paste to hopefully do some sensible things.
3054 There are still some small problems that can lead to
3055 double spaces stored in the document file or space at
3056 the beginning of paragraphs. This happens if you have
3057 the cursor betwenn to spaces and then save. Or if you
3058 cut and paste and the selection have a space at the
3059 beginning and then save right after the paste. I am
3060 sure none of these are very hard to fix, but I will
3061 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3062 that I can get some feedback. (Lgb)
3065 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3066 // delete the LineSeparator.
3069 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3070 // delete the LineSeparator.
3073 // If the pos around the old_cursor were spaces, delete one of them.
3074 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3075 // Only if the cursor has really moved
3077 if (old_cursor.pos() > 0
3078 && old_cursor.pos() < old_cursor.par()->Last()
3079 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3080 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3081 old_cursor.par()->Erase(old_cursor.pos() - 1);
3082 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3084 if (old_cursor.par() == cursor.par() &&
3085 cursor.pos() > old_cursor.pos()) {
3086 SetCursorIntern(bview, cursor.par(),
3089 SetCursorIntern(bview, cursor.par(),
3095 // Do not delete empty paragraphs with keepempty set.
3096 if ((textclasslist.Style(bview->buffer()->params.textclass,
3097 old_cursor.par()->GetLayout())).keepempty)
3100 LyXCursor tmpcursor;
3102 if (old_cursor.par() != cursor.par()) {
3103 if ((old_cursor.par()->Last() == 0
3104 || (old_cursor.par()->Last() == 1
3105 && old_cursor.par()->IsLineSeparator(0)))
3107 && old_cursor.par()->FirstPhysicalPar()
3108 == old_cursor.par()->LastPhysicalPar()
3111 // ok, we will delete anything
3113 // make sure that you do not delete any environments
3116 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3117 !(old_cursor.row()->previous()
3118 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3119 && !(old_cursor.row()->next()
3120 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3121 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3122 && ((old_cursor.row()->previous()
3123 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3124 || (old_cursor.row()->next()
3125 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3128 status = LyXText::NEED_MORE_REFRESH;
3131 if (old_cursor.row()->previous()) {
3132 refresh_row = old_cursor.row()->previous();
3133 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3135 cursor = old_cursor; // that undo can restore the right cursor position
3136 LyXParagraph * endpar = old_cursor.par()->next;
3137 if (endpar && endpar->GetDepth()) {
3138 while (endpar && endpar->GetDepth()) {
3140 endpar = endpar->LastPhysicalPar()->Next();
3142 endpar = endpar->Next();
3146 SetUndo(bview->buffer(), Undo::DELETE,
3147 old_cursor.par()->previous,
3152 RemoveRow(old_cursor.row());
3153 if (OwnerParagraph() == old_cursor.par()) {
3154 OwnerParagraph(OwnerParagraph()->next);
3157 delete old_cursor.par();
3159 /* Breakagain the next par. Needed
3160 * because of the parindent that
3161 * can occur or dissappear. The
3162 * next row can change its height,
3163 * if there is another layout before */
3164 if (refresh_row->next()) {
3165 BreakAgain(bview, refresh_row->next());
3166 UpdateCounters(bview, refresh_row);
3168 SetHeightOfRow(bview, refresh_row);
3170 refresh_row = old_cursor.row()->next();
3171 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3174 cursor = old_cursor; // that undo can restore the right cursor position
3175 LyXParagraph * endpar = old_cursor.par()->next;
3176 if (endpar && endpar->GetDepth()) {
3177 while (endpar && endpar->GetDepth()) {
3179 endpar = endpar->LastPhysicalPar()->Next();
3181 endpar = endpar->Next();
3185 SetUndo(bview->buffer(), Undo::DELETE,
3186 old_cursor.par()->previous,
3191 RemoveRow(old_cursor.row());
3193 if (OwnerParagraph() == old_cursor.par()) {
3194 OwnerParagraph(OwnerParagraph()->next);
3196 delete old_cursor.par();
3198 /* Breakagain the next par. Needed
3199 because of the parindent that can
3200 occur or dissappear.
3201 The next row can change its height,
3202 if there is another layout before
3205 BreakAgain(bview, refresh_row);
3206 UpdateCounters(bview, refresh_row->previous());
3212 SetCursorIntern(bview, cursor.par(), cursor.pos());
3214 if (sel_cursor.par() == old_cursor.par()
3215 && sel_cursor.pos() == sel_cursor.pos()) {
3216 // correct selection
3217 sel_cursor = cursor;
3224 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3225 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3227 SetCursorIntern(bview, cursor.par(), cursor.pos());
3228 sel_cursor = cursor;
3235 LyXParagraph * LyXText::GetParFromID(int id)
3237 LyXParagraph * result = FirstParagraph();
3238 while (result && result->id() != id)
3239 result = result->next;
3245 bool LyXText::TextUndo(BufferView * bview)
3249 // returns false if no undo possible
3250 Undo * undo = bview->buffer()->undostack.pop();
3254 bview->buffer()->redostack
3255 .push(CreateUndo(bview->buffer(), undo->kind,
3256 GetParFromID(undo->number_of_before_par),
3257 GetParFromID(undo->number_of_behind_par)));
3259 return TextHandleUndo(bview, undo);
3263 bool LyXText::TextRedo(BufferView * bview)
3267 // returns false if no redo possible
3268 Undo * undo = bview->buffer()->redostack.pop();
3272 bview->buffer()->undostack
3273 .push(CreateUndo(bview->buffer(), undo->kind,
3274 GetParFromID(undo->number_of_before_par),
3275 GetParFromID(undo->number_of_behind_par)));
3277 return TextHandleUndo(bview, undo);
3281 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3285 // returns false if no undo possible
3286 bool result = false;
3288 LyXParagraph * before =
3289 GetParFromID(undo->number_of_before_par);
3290 LyXParagraph * behind =
3291 GetParFromID(undo->number_of_behind_par);
3292 LyXParagraph * tmppar;
3293 LyXParagraph * tmppar2;
3294 LyXParagraph * endpar;
3295 LyXParagraph * tmppar5;
3297 // if there's no before take the beginning
3298 // of the document for redoing
3300 SetCursorIntern(bview, FirstParagraph(), 0);
3302 // replace the paragraphs with the undo informations
3304 LyXParagraph * tmppar3 = undo->par;
3305 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3306 LyXParagraph * tmppar4 = tmppar3;
3308 while (tmppar4->next)
3309 tmppar4 = tmppar4->next;
3310 } // get last undo par
3312 // now remove the old text if there is any
3313 if (before != behind || (!behind && !before)){
3315 tmppar5 = before->next;
3317 tmppar5 = OwnerParagraph();
3319 while (tmppar5 && tmppar5 != behind){
3321 tmppar5 = tmppar5->next;
3322 // a memory optimization for edit: Only layout information
3323 // is stored in the undo. So restore the text informations.
3324 if (undo->kind == Undo::EDIT) {
3325 tmppar2->setContentsFromPar(tmppar);
3326 tmppar->clearContents();
3327 tmppar2 = tmppar2->next;
3332 // put the new stuff in the list if there is one
3335 before->next = tmppar3;
3337 OwnerParagraph(tmppar3);
3338 tmppar3->previous = before;
3341 OwnerParagraph(behind);
3344 tmppar4->next = behind;
3346 behind->previous = tmppar4;
3350 // Set the cursor for redoing
3353 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3355 SetCursorIntern(bview, before, 0);
3358 // check wether before points to a closed float and open it if necessary
3359 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3360 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3362 while (tmppar4->previous &&
3363 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3364 tmppar4 = tmppar4->previous;
3365 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3366 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3367 tmppar4 = tmppar4->next;
3374 // open a cosed footnote at the end if necessary
3375 if (behind && behind->previous &&
3376 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3377 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3378 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3379 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3380 behind = behind->next;
3385 // calculate the endpar for redoing the paragraphs.
3388 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3389 endpar = behind->LastPhysicalPar()->Next();
3391 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3393 endpar = behind->Next();
3398 tmppar = GetParFromID(undo->number_of_cursor_par);
3399 RedoParagraphs(bview, cursor, endpar);
3401 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3402 UpdateCounters(bview, cursor.row());
3412 void LyXText::FinishUndo()
3416 // makes sure the next operation will be stored
3417 undo_finished = true;
3421 void LyXText::FreezeUndo()
3425 // this is dangerous and for internal use only
3430 void LyXText::UnFreezeUndo()
3434 // this is dangerous and for internal use only
3435 undo_frozen = false;
3439 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3440 LyXParagraph const * before,
3441 LyXParagraph const * behind) const
3446 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3447 buf->redostack.clear();
3451 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3452 LyXParagraph const * before, LyXParagraph const * behind)
3456 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3460 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3461 LyXParagraph const * before,
3462 LyXParagraph const * behind) const
3467 int before_number = -1;
3468 int behind_number = -1;
3470 before_number = before->id();
3472 behind_number = behind->id();
3473 // Undo::EDIT and Undo::FINISH are
3474 // always finished. (no overlapping there)
3475 // overlapping only with insert and delete inside one paragraph:
3476 // Nobody wants all removed character
3477 // appear one by one when undoing.
3478 // EDIT is special since only layout information, not the
3479 // contents of a paragaph are stored.
3480 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3481 // check wether storing is needed
3482 if (!buf->undostack.empty() &&
3483 buf->undostack.top()->kind == kind &&
3484 buf->undostack.top()->number_of_before_par == before_number &&
3485 buf->undostack.top()->number_of_behind_par == behind_number ){
3490 // create a new Undo
3491 LyXParagraph * undopar;
3492 LyXParagraph * tmppar;
3493 LyXParagraph * tmppar2;
3495 LyXParagraph * start = 0;
3496 LyXParagraph * end = 0;
3499 start = before->next;
3501 start = FirstParagraph();
3503 end = behind->previous;
3505 end = FirstParagraph();
3510 if (start && end && (start != end->next) &&
3511 ((before != behind) || (!before && !behind)))
3514 tmppar2 = tmppar->Clone();
3515 tmppar2->id(tmppar->id());
3517 // a memory optimization: Just store the layout information
3519 if (kind == Undo::EDIT){
3520 //tmppar2->text.clear();
3521 tmppar2->clearContents();
3526 while (tmppar != end && tmppar->next) {
3527 tmppar = tmppar->next;
3528 tmppar2->next = tmppar->Clone();
3529 tmppar2->next->id(tmppar->id());
3530 // a memory optimization: Just store the layout
3531 // information when only edit
3532 if (kind == Undo::EDIT){
3533 //tmppar2->next->text.clear();
3534 tmppar2->clearContents();
3536 tmppar2->next->previous = tmppar2;
3537 tmppar2 = tmppar2->next;
3541 undopar = 0; // nothing to replace (undo of delete maybe)
3544 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3545 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3547 int cursor_par = cursor.par()->id();
3548 int cursor_pos = cursor.pos();
3551 Undo * undo = new Undo(kind,
3552 before_number, behind_number,
3553 cursor_par, cursor_pos,
3556 undo_finished = false;
3561 void LyXText::SetCursorParUndo(Buffer * buf)
3565 SetUndo(buf, Undo::FINISH,
3567 cursor.par()->ParFromPos(cursor.pos())->previous,
3568 cursor.par()->ParFromPos(cursor.pos())->next
3570 cursor.par()->previous,
3577 void LyXText::toggleAppendix(BufferView * bview)
3580 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3582 LyXParagraph * par = cursor.par();
3584 bool start = !par->start_of_appendix;
3586 // ensure that we have only one start_of_appendix in this document
3587 LyXParagraph * tmp = FirstParagraph();
3588 for (; tmp; tmp = tmp->next)
3589 tmp->start_of_appendix = 0;
3590 par->start_of_appendix = start;
3592 // we can set the refreshing parameters now
3593 status = LyXText::NEED_MORE_REFRESH;
3595 refresh_row = 0; // not needed for full update
3596 UpdateCounters(bview, 0);
3597 SetCursor(bview, cursor.par(), cursor.pos());
3601 LyXParagraph * LyXText::OwnerParagraph() const
3604 return inset_owner->par;
3606 return bv_owner->buffer()->paragraph;
3610 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3613 inset_owner->par = p;
3615 bv_owner->buffer()->paragraph = p;