1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2000 The LyX Team.
9 * ====================================================== */
13 #include FORMS_H_LOCATION
17 #pragma implementation "lyxtext.h"
21 #include "lyxparagraph.h"
22 #include "insets/inseterror.h"
23 #include "insets/insetbib.h"
24 #include "insets/insetspecialchar.h"
25 #include "insets/insettext.h"
26 #include "insets/insetfloat.h"
29 #include "support/textutils.h"
31 #include "minibuffer.h"
33 #include "bufferparams.h"
34 #include "lyx_gui_misc.h"
37 #include "BufferView.h"
40 #include "CutAndPaste.h"
45 #include "FloatList.h"
52 LyXText::LyXText(BufferView * bv)
60 LyXText::LyXText(InsetText * inset)
77 status = LyXText::UNCHANGED;
78 // set cursor at the very top position
79 selection = true; /* these setting is necessary
80 because of the delete-empty-
81 paragraph mechanism in
84 LyXParagraph * par = OwnerParagraph();
85 current_font = GetFont(bv_owner->buffer(), par, 0);
87 InsertParagraph(bv_owner, par, lastrow);
90 SetCursor(bv_owner, firstrow->par(), 0);
92 current_font = LyXFont(LyXFont::ALL_SANE);
98 // no rebreak necessary
101 undo_finished = true;
104 // Default layouttype for copy environment type
108 // Dump all rowinformation:
109 Row * tmprow = firstrow;
110 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
112 lyxerr << tmprow->baseline() << '\t'
113 << tmprow->par << '\t'
114 << tmprow->pos() << '\t'
115 << tmprow->height << '\t'
116 << tmprow->ascent_of_text << '\t'
117 << tmprow->fill << '\n';
118 tmprow = tmprow->next();
125 void LyXText::init(BufferView * bview)
130 LyXParagraph * par = OwnerParagraph();
131 current_font = GetFont(bview->buffer(), par, 0);
133 InsertParagraph(bview, par, lastrow);
136 SetCursorIntern(bview, firstrow->par(), 0);
139 // Dump all rowinformation:
140 Row * tmprow = firstrow;
141 lyxerr << "Width = " << width << endl;
142 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
144 lyxerr << tmprow->baseline() << '\t'
145 << tmprow->par() << '\t'
146 << tmprow->pos() << '\t'
147 << tmprow->height() << '\t'
148 << tmprow->ascent_of_text() << '\t'
149 << tmprow->fill() << '\n';
150 tmprow = tmprow->next();
158 // Delete all rows, this does not touch the paragraphs!
159 Row * tmprow = firstrow;
161 tmprow = firstrow->next();
168 // Gets the fully instantiated font at a given position in a paragraph
169 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
170 // The difference is that this one is used for displaying, and thus we
171 // are allowed to make cosmetic improvements. For instance make footnotes
173 // If position is -1, we get the layout font of the paragraph.
174 // If position is -2, we get the font of the manual label of the paragraph.
175 LyXFont const LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
176 LyXParagraph::size_type pos) const
178 LyXLayout const & layout =
179 textclasslist.Style(buf->params.textclass, par->GetLayout());
181 char par_depth = par->GetDepth();
182 // We specialize the 95% common case:
185 par->footnoteflag == LyXParagraph::NO_FOOTNOTE &&
190 if (layout.labeltype == LABEL_MANUAL
191 && pos < BeginningOfMainBody(buf, par)) {
193 LyXFont f = par->GetFontSettings(buf->params,
195 return f.realize(layout.reslabelfont);
197 LyXFont f = par->GetFontSettings(buf->params, pos);
198 return f.realize(layout.resfont);
203 // process layoutfont for pos == -1 and labelfont for pos < -1
205 return layout.resfont;
207 return layout.reslabelfont;
211 // The uncommon case need not be optimized as much
213 LyXFont layoutfont, tmpfont;
217 if (pos < BeginningOfMainBody(buf, par)) {
219 layoutfont = layout.labelfont;
222 layoutfont = layout.font;
224 tmpfont = par->GetFontSettings(buf->params, pos);
225 tmpfont.realize(layoutfont);
228 // process layoutfont for pos == -1 and labelfont for pos < -1
230 tmpfont = layout.font;
232 tmpfont = layout.labelfont;
235 // Resolve against environment font information
236 while (par && par_depth && !tmpfont.resolved()) {
237 par = par->DepthHook(par_depth - 1);
239 tmpfont.realize(textclasslist.
240 Style(buf->params.textclass,
241 par->GetLayout()).font);
242 par_depth = par->GetDepth();
246 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
249 // Cosmetic improvement: If this is an open footnote, make the font
251 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
252 && par->footnotekind == LyXParagraph::FOOTNOTE) {
260 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
261 LyXParagraph::size_type pos,
265 // Let the insets convert their font
266 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
267 if (par->GetInset(pos))
268 font = par->GetInset(pos)->ConvertFont(font);
271 LyXLayout const & layout =
272 textclasslist.Style(buf->params.textclass,
275 // Get concrete layout font to reduce against
278 if (pos < BeginningOfMainBody(buf, par))
279 layoutfont = layout.labelfont;
281 layoutfont = layout.font;
283 // Realize against environment font information
284 if (par->GetDepth()){
285 LyXParagraph * tp = par;
286 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
287 tp = tp->DepthHook(tp->GetDepth()-1);
289 layoutfont.realize(textclasslist.
290 Style(buf->params.textclass,
291 tp->GetLayout()).font);
295 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
298 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
299 && par->footnotekind == LyXParagraph::FOOTNOTE) {
300 layoutfont.decSize();
303 // Now, reduce font against full layout font
304 font.reduce(layoutfont);
306 par->SetFont(pos, font);
310 /* inserts a new row behind the specified row, increments
311 * the touched counters */
312 void LyXText::InsertRow(Row * row, LyXParagraph * par,
313 LyXParagraph::size_type pos) const
315 Row * tmprow = new Row;
318 tmprow->next(firstrow);
321 tmprow->previous(row);
322 tmprow->next(row->next());
327 tmprow->next()->previous(tmprow);
329 if (tmprow->previous())
330 tmprow->previous()->next(tmprow);
338 ++number_of_rows; // one more row
342 // removes the row and reset the touched counters
343 void LyXText::RemoveRow(Row * row) const
345 /* this must not happen before the currentrow for clear reasons.
346 so the trick is just to set the current row onto the previous
349 GetRow(row->par(), row->pos(), unused_y);
352 row->next()->previous(row->previous());
353 if (!row->previous()) {
354 firstrow = row->next();
356 row->previous()->next(row->next());
359 lastrow = row->previous();
361 height -= row->height(); // the text becomes smaller
364 --number_of_rows; // one row less
368 // remove all following rows of the paragraph of the specified row.
369 void LyXText::RemoveParagraph(Row * row) const
371 LyXParagraph * tmppar = row->par();
375 while (row && row->par() == tmppar) {
376 tmprow = row->next();
383 // insert the specified paragraph behind the specified row
384 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
387 InsertRow(row, par, 0); /* insert a new row, starting
390 SetCounter(bview->buffer(), par); // set the counters
392 // and now append the whole paragraph behind the new row
395 AppendParagraph(bview, firstrow);
397 row->next()->height(0);
398 AppendParagraph(bview, row->next());
404 void LyXText::ToggleFootnote(BufferView * bview)
406 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
408 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
410 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
412 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
413 CloseFootnote(bview);
420 void LyXText::OpenStuff(BufferView * bview)
422 if (cursor.pos() == 0 && cursor.par()->bibkey){
423 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
424 } else if (cursor.pos() < cursor.par()->Last()
425 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
426 && cursor.par()->GetInset(cursor.pos())->Editable()) {
427 bview->owner()->getMiniBuffer()
428 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
429 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
430 SetCursorParUndo(bview->buffer());
431 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
435 ToggleFootnote(bview);
443 void LyXText::CloseFootnote(BufferView * bview)
445 LyXParagraph * tmppar;
446 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
448 // if the cursor is not in an open footnote, or
449 // there is no open footnote in this paragraph, just return.
450 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
453 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
454 bview->owner()->getMiniBuffer()
455 ->Set(_("Nothing to do"));
459 // ok, move the cursor right before the footnote
460 // just a little faster than using CursorRight()
462 cursor.par()->ParFromPos(cursor.pos()) != par;) {
463 cursor.pos(cursor.pos() + 1);
466 // now the cursor is at the beginning of the physical par
467 SetCursor(bview, cursor.par(),
469 cursor.par()->ParFromPos(cursor.pos())->size());
471 /* we are in a footnote, so let us move at the beginning */
472 /* this is just faster than using just CursorLeft() */
474 tmppar = cursor.par();
475 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
476 // just a little bit faster than movin the cursor
477 tmppar = tmppar->Previous();
479 SetCursor(bview, tmppar, tmppar->Last());
482 // the cursor must be exactly before the footnote
483 par = cursor.par()->ParFromPos(cursor.pos());
485 status = LyXText::NEED_MORE_REFRESH;
486 refresh_row = cursor.row();
487 refresh_y = cursor.y() - cursor.row()->baseline();
489 tmppar = cursor.par();
490 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
491 Row * row = cursor.row();
493 tmppar->CloseFootnote(cursor.pos());
495 while (tmppar != endpar) {
496 RemoveRow(row->next());
498 tmppar = row->next()->par();
503 AppendParagraph(bview, cursor.row());
505 SetCursor(bview, cursor.par(), cursor.pos());
509 if (cursor.row()->next())
510 SetHeightOfRow(bview, cursor.row()->next());
515 /* used in setlayout */
516 // Asger is not sure we want to do this...
517 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
521 LyXLayout const & layout =
522 textclasslist.Style(buf->params.textclass, par->GetLayout());
524 LyXFont layoutfont, tmpfont;
525 for (LyXParagraph::size_type pos = 0;
526 pos < par->Last(); ++pos) {
527 if (pos < BeginningOfMainBody(buf, par))
528 layoutfont = layout.labelfont;
530 layoutfont = layout.font;
532 tmpfont = par->GetFontSettings(buf->params, pos);
533 tmpfont.reduce(layoutfont);
534 par->SetFont(pos, tmpfont);
539 LyXParagraph * LyXText::SetLayout(BufferView * bview,
540 LyXCursor & cur, LyXCursor & sstart_cur,
541 LyXCursor & send_cur,
542 LyXTextClass::size_type layout)
545 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
547 LyXParagraph * endpar = send_cur.par()->Next();
549 LyXParagraph * undoendpar = endpar;
551 if (endpar && endpar->GetDepth()) {
552 while (endpar && endpar->GetDepth()) {
554 endpar = endpar->LastPhysicalPar()->Next();
556 endpar = endpar->Next();
561 endpar = endpar->Next(); // because of parindents etc.
564 SetUndo(bview->buffer(), Undo::EDIT,
566 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
568 sstart_cur.par()->previous,
572 /* ok we have a selection. This is always between sstart_cur
573 * and sel_end cursor */
576 LyXLayout const & lyxlayout =
577 textclasslist.Style(bview->buffer()->params.textclass, layout);
579 while (cur.par() != send_cur.par()) {
581 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
583 cur.par()->SetLayout(bview->buffer()->params, layout);
584 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
586 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
588 LyXParagraph * fppar = cur.par();
590 fppar->added_space_top = lyxlayout.fill_top ?
591 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
592 fppar->added_space_bottom = lyxlayout.fill_bottom ?
593 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
594 if (lyxlayout.margintype == MARGIN_MANUAL)
595 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
596 if (lyxlayout.labeltype != LABEL_BIBLIO
598 delete fppar->bibkey;
604 cur.par(cur.par()->Next());
607 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
609 cur.par()->SetLayout(bview->buffer()->params, layout);
610 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
612 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
614 LyXParagraph * fppar = cur.par();
616 fppar->added_space_top = lyxlayout.fill_top ?
617 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
618 fppar->added_space_bottom = lyxlayout.fill_bottom ?
619 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
620 if (lyxlayout.margintype == MARGIN_MANUAL)
621 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
622 if (lyxlayout.labeltype != LABEL_BIBLIO
624 delete fppar->bibkey;
633 // set layout over selection and make a total rebreak of those paragraphs
634 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
636 LyXCursor tmpcursor = cursor; /* store the current cursor */
638 // if there is no selection just set the layout
639 // of the current paragraph */
641 sel_start_cursor = cursor; // dummy selection
642 sel_end_cursor = cursor;
645 endpar = SetLayout(bview, cursor, sel_start_cursor,
646 sel_end_cursor, layout);
647 RedoParagraphs(bview, sel_start_cursor, endpar);
649 // we have to reset the selection, because the
650 // geometry could have changed
651 SetCursor(bview, sel_start_cursor.par(),
652 sel_start_cursor.pos(), false);
654 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
656 UpdateCounters(bview, cursor.row());
659 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
663 // increment depth over selection and
664 // make a total rebreak of those paragraphs
665 void LyXText::IncDepth(BufferView * bview)
667 // If there is no selection, just use the current paragraph
669 sel_start_cursor = cursor; // dummy selection
670 sel_end_cursor = cursor;
673 // We end at the next paragraph with depth 0
674 LyXParagraph * endpar =
676 sel_end_cursor.par()->LastPhysicalPar()->Next();
678 sel_end_cursor.par()->Next();
680 LyXParagraph * undoendpar = endpar;
682 if (endpar && endpar->GetDepth()) {
683 while (endpar && endpar->GetDepth()) {
685 endpar = endpar->LastPhysicalPar()->Next();
687 endpar = endpar->Next();
693 endpar = endpar->Next(); // because of parindents etc.
696 SetUndo(bview->buffer(), Undo::EDIT,
699 .par()->ParFromPos(sel_start_cursor.pos())->previous,
701 sel_start_cursor.par()->previous,
705 LyXCursor tmpcursor = cursor; // store the current cursor
707 // ok we have a selection. This is always between sel_start_cursor
708 // and sel_end cursor
709 cursor = sel_start_cursor;
711 bool anything_changed = false;
714 // NOTE: you can't change the depth of a bibliography entry
717 cursor.par()->footnoteflag ==
718 sel_start_cursor.par()->footnoteflag &&
720 textclasslist.Style(bview->buffer()->params.textclass,
721 cursor.par()->GetLayout()
722 ).labeltype != LABEL_BIBLIO) {
723 LyXParagraph * prev =
725 cursor.par()->FirstPhysicalPar()->Previous();
727 cursor.par()->Previous();
730 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
731 || (prev->GetDepth() == cursor.par()->GetDepth()
732 && textclasslist.Style(bview->buffer()->params.textclass,
733 prev->GetLayout()).isEnvironment()))) {
735 cursor.par()->FirstPhysicalPar()->depth++;
737 cursor.par()->depth++;
739 anything_changed = true;
742 if (cursor.par() == sel_end_cursor.par())
744 cursor.par(cursor.par()->Next());
747 // if nothing changed set all depth to 0
748 if (!anything_changed) {
749 cursor = sel_start_cursor;
750 while (cursor.par() != sel_end_cursor.par()) {
752 cursor.par()->FirstPhysicalPar()->depth = 0;
754 cursor.par()->depth = 0;
756 cursor.par(cursor.par()->Next());
759 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
760 cursor.par()->FirstPhysicalPar()->depth = 0;
762 cursor.par()->depth = 0;
766 RedoParagraphs(bview, sel_start_cursor, endpar);
768 // we have to reset the selection, because the
769 // geometry could have changed
770 SetCursor(bview, sel_start_cursor.par(),
771 sel_start_cursor.pos());
773 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
774 UpdateCounters(bview, cursor.row());
777 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
781 // decrement depth over selection and
782 // make a total rebreak of those paragraphs
783 void LyXText::DecDepth(BufferView * bview)
785 // if there is no selection just set the layout
786 // of the current paragraph
788 sel_start_cursor = cursor; // dummy selection
789 sel_end_cursor = cursor;
792 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
794 LyXParagraph * endpar = sel_end_cursor.par()->Next();
796 LyXParagraph * undoendpar = endpar;
798 if (endpar && endpar->GetDepth()) {
799 while (endpar && endpar->GetDepth()) {
801 endpar = endpar->LastPhysicalPar()->Next();
803 endpar = endpar->Next();
809 endpar = endpar->Next(); // because of parindents etc.
812 SetUndo(bview->buffer(), Undo::EDIT,
815 .par()->ParFromPos(sel_start_cursor.pos())->previous,
817 sel_start_cursor.par()->previous,
821 LyXCursor tmpcursor = cursor; // store the current cursor
823 // ok we have a selection. This is always between sel_start_cursor
824 // and sel_end cursor
825 cursor = sel_start_cursor;
829 if (cursor.par()->footnoteflag ==
830 sel_start_cursor.par()->footnoteflag) {
831 if (cursor.par()->FirstPhysicalPar()->depth)
832 cursor.par()->FirstPhysicalPar()->depth--;
835 if (cursor.par()->depth)
836 cursor.par()->depth--;
838 if (cursor.par() == sel_end_cursor.par())
840 cursor.par(cursor.par()->Next());
843 RedoParagraphs(bview, sel_start_cursor, endpar);
845 // we have to reset the selection, because the
846 // geometry could have changed
847 SetCursor(bview, sel_start_cursor.par(),
848 sel_start_cursor.pos());
850 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
851 UpdateCounters(bview, cursor.row());
854 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
858 // set font over selection and make a total rebreak of those paragraphs
859 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
861 // if there is no selection just set the current_font
863 // Determine basis font
865 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
867 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
869 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
870 // Update current font
871 real_current_font.update(font,
872 bview->buffer()->params.language_info,
875 // Reduce to implicit settings
876 current_font = real_current_font;
877 current_font.reduce(layoutfont);
878 // And resolve it completely
879 real_current_font.realize(layoutfont);
883 LyXCursor tmpcursor = cursor; // store the current cursor
885 // ok we have a selection. This is always between sel_start_cursor
886 // and sel_end cursor
888 SetUndo(bview->buffer(), Undo::EDIT,
890 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
891 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next
893 sel_start_cursor.par()->previous,
894 sel_end_cursor.par()->next
897 cursor = sel_start_cursor;
898 while (cursor.par() != sel_end_cursor.par() ||
901 cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag &&
903 cursor.pos() < sel_end_cursor.pos()))
905 if (cursor.pos() < cursor.par()->Last()
907 && cursor.par()->footnoteflag
908 == sel_start_cursor.par()->footnoteflag
911 // an open footnote should behave
913 LyXFont newfont = GetFont(bview->buffer(),
914 cursor.par(), cursor.pos());
916 bview->buffer()->params.language_info,
918 SetCharFont(bview->buffer(),
919 cursor.par(), cursor.pos(), newfont);
920 cursor.pos(cursor.pos() + 1);
923 cursor.par(cursor.par()->Next());
927 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
929 // we have to reset the selection, because the
930 // geometry could have changed
931 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
933 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
936 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
937 tmpcursor.boundary());
941 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
943 Row * tmprow = cur.row();
944 long y = cur.y() - tmprow->baseline();
946 SetHeightOfRow(bview, tmprow);
948 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
950 LyXParagraph * first_phys_par = tmprow->par();
952 // find the first row of the paragraph
953 if (first_phys_par != tmprow->par())
954 while (tmprow->previous()
955 && tmprow->previous()->par() != first_phys_par) {
956 tmprow = tmprow->previous();
957 y -= tmprow->height();
958 SetHeightOfRow(bview, tmprow);
960 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
961 tmprow = tmprow->previous();
962 y -= tmprow->height();
963 SetHeightOfRow(bview, tmprow);
966 // we can set the refreshing parameters now
967 status = LyXText::NEED_MORE_REFRESH;
969 refresh_row = tmprow;
970 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
974 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
976 Row * tmprow = cur.row();
978 long y = cur.y() - tmprow->baseline();
979 SetHeightOfRow(bview, tmprow);
981 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
983 LyXParagraph * first_phys_par = tmprow->par();
985 // find the first row of the paragraph
986 if (first_phys_par != tmprow->par())
987 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
988 tmprow = tmprow->previous();
989 y -= tmprow->height();
991 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
992 tmprow = tmprow->previous();
993 y -= tmprow->height();
996 // we can set the refreshing parameters now
997 if (status == LyXText::UNCHANGED || y < refresh_y) {
999 refresh_row = tmprow;
1001 status = LyXText::NEED_MORE_REFRESH;
1002 SetCursor(bview, cur.par(), cur.pos());
1006 /* deletes and inserts again all paragaphs between the cursor
1007 * and the specified par
1008 * This function is needed after SetLayout and SetFont etc. */
1009 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
1010 LyXParagraph const * endpar) const
1013 LyXParagraph * tmppar = 0, * first_phys_par = 0;
1015 Row * tmprow = cur.row();
1017 long y = cur.y() - tmprow->baseline();
1019 if (!tmprow->previous()){
1020 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
1023 first_phys_par = tmprow->par()->FirstPhysicalPar();
1025 first_phys_par = tmprow->par();
1027 // find the first row of the paragraph
1028 if (first_phys_par != tmprow->par())
1029 while (tmprow->previous() &&
1030 (tmprow->previous()->par() != first_phys_par)) {
1031 tmprow = tmprow->previous();
1032 y -= tmprow->height();
1034 while (tmprow->previous()
1035 && tmprow->previous()->par() == first_phys_par) {
1036 tmprow = tmprow->previous();
1037 y -= tmprow->height();
1041 // we can set the refreshing parameters now
1042 status = LyXText::NEED_MORE_REFRESH;
1044 refresh_row = tmprow->previous(); /* the real refresh row will
1045 be deleted, so I store
1046 the previous here */
1049 tmppar = tmprow->next()->par();
1052 while (tmppar != endpar) {
1053 RemoveRow(tmprow->next());
1055 tmppar = tmprow->next()->par();
1060 // remove the first one
1061 tmprow2 = tmprow; /* this is because tmprow->previous()
1063 tmprow = tmprow->previous();
1066 tmppar = first_phys_par;
1070 InsertParagraph(bview, tmppar, tmprow);
1073 while (tmprow->next() && tmprow->next()->par() == tmppar)
1074 tmprow = tmprow->next();
1075 tmppar = tmppar->Next();
1077 } while (tmppar != endpar);
1079 // this is because of layout changes
1081 refresh_y -= refresh_row->height();
1082 SetHeightOfRow(bview, refresh_row);
1084 refresh_row = firstrow;
1086 SetHeightOfRow(bview, refresh_row);
1089 if (tmprow && tmprow->next())
1090 SetHeightOfRow(bview, tmprow->next());
1094 bool LyXText::FullRebreak(BufferView * bview)
1100 if (need_break_row) {
1101 BreakAgain(bview, need_break_row);
1109 /* important for the screen */
1112 /* the cursor set functions have a special mechanism. When they
1113 * realize, that you left an empty paragraph, they will delete it.
1114 * They also delete the corresponding row */
1116 // need the selection cursor:
1117 void LyXText::SetSelection()
1120 last_sel_cursor = sel_cursor;
1121 sel_start_cursor = sel_cursor;
1122 sel_end_cursor = sel_cursor;
1127 // first the toggling area
1128 if (cursor.y() < last_sel_cursor.y()
1129 || (cursor.y() == last_sel_cursor.y()
1130 && cursor.x() < last_sel_cursor.x())) {
1131 toggle_end_cursor = last_sel_cursor;
1132 toggle_cursor = cursor;
1134 toggle_end_cursor = cursor;
1135 toggle_cursor = last_sel_cursor;
1138 last_sel_cursor = cursor;
1140 // and now the whole selection
1142 if (sel_cursor.par() == cursor.par())
1143 if (sel_cursor.pos() < cursor.pos()) {
1144 sel_end_cursor = cursor;
1145 sel_start_cursor = sel_cursor;
1147 sel_end_cursor = sel_cursor;
1148 sel_start_cursor = cursor;
1150 else if (sel_cursor.y() < cursor.y() ||
1151 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1152 sel_end_cursor = cursor;
1153 sel_start_cursor = sel_cursor;
1156 sel_end_cursor = sel_cursor;
1157 sel_start_cursor = cursor;
1160 // a selection with no contents is not a selection
1161 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1162 sel_start_cursor.pos() == sel_end_cursor.pos())
1167 string const LyXText::selectionAsString(Buffer const * buffer) const
1169 if (!selection) return string();
1172 // Special handling if the whole selection is within one paragraph
1173 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1174 result += sel_start_cursor.par()->String(buffer,
1175 sel_start_cursor.pos(),
1176 sel_end_cursor.pos());
1180 // The selection spans more than one paragraph
1182 // First paragraph in selection
1183 result += sel_start_cursor.par()->String(buffer,
1184 sel_start_cursor.pos(),
1185 sel_start_cursor.par()->Last())
1188 // The paragraphs in between (if any)
1189 LyXCursor tmpcur(sel_start_cursor);
1190 tmpcur.par(tmpcur.par()->Next());
1191 while (tmpcur.par() != sel_end_cursor.par()) {
1192 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1193 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1196 // Last paragraph in selection
1197 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1203 void LyXText::ClearSelection() const
1210 void LyXText::CursorHome(BufferView * bview) const
1212 SetCursor(bview, cursor.par(), cursor.row()->pos());
1216 void LyXText::CursorEnd(BufferView * bview) const
1218 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1219 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1221 if (cursor.par()->Last() &&
1222 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1223 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1224 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1226 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1231 void LyXText::CursorTop(BufferView * bview) const
1233 while (cursor.par()->Previous())
1234 cursor.par(cursor.par()->Previous());
1235 SetCursor(bview, cursor.par(), 0);
1239 void LyXText::CursorBottom(BufferView * bview) const
1241 while (cursor.par()->Next())
1242 cursor.par(cursor.par()->Next());
1243 SetCursor(bview, cursor.par(), cursor.par()->Last());
1247 /* returns a pointer to the row near the specified y-coordinate
1248 * (relative to the whole text). y is set to the real beginning
1250 Row * LyXText::GetRowNearY(long & y) const
1252 Row * tmprow = firstrow;
1255 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1256 tmpy += tmprow->height();
1257 tmprow = tmprow->next();
1260 y = tmpy; // return the real y
1265 void LyXText::ToggleFree(BufferView * bview,
1266 LyXFont const & font, bool toggleall)
1268 // If the mask is completely neutral, tell user
1269 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1270 // Could only happen with user style
1271 bview->owner()->getMiniBuffer()
1272 ->Set(_("No font change defined. Use Character under"
1273 " the Layout menu to define font change."));
1277 // Try implicit word selection
1278 // If there is a change in the language the implicit word selection
1280 LyXCursor resetCursor = cursor;
1281 bool implicitSelection = (font.language() == ignore_language)
1282 ? SelectWordWhenUnderCursor(bview) : false;
1285 SetFont(bview, font, toggleall);
1287 /* Implicit selections are cleared afterwards and cursor is set to the
1288 original position. */
1289 if (implicitSelection) {
1291 cursor = resetCursor;
1292 SetCursor(bview, cursor.par(), cursor.pos());
1293 sel_cursor = cursor;
1298 LyXParagraph::size_type
1299 LyXText::BeginningOfMainBody(Buffer const * buf,
1300 LyXParagraph const * par) const
1302 if (textclasslist.Style(buf->params.textclass,
1303 par->GetLayout()).labeltype != LABEL_MANUAL)
1306 return par->BeginningOfMainBody();
1311 /* if there is a selection, reset every environment you can find
1312 * in the selection, otherwise just the environment you are in */
1313 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1315 LyXParagraph * tmppar, * firsttmppar;
1319 /* is is only allowed, if the cursor is IN an open footnote.
1320 * Otherwise it is too dangerous */
1321 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1324 SetUndo(bview->buffer(), Undo::FINISH,
1325 cursor.par()->PreviousBeforeFootnote()->previous,
1326 cursor.par()->NextAfterFootnote()->next);
1328 /* ok, move to the beginning of the footnote. */
1329 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1330 cursor.par(cursor.par()->Previous());
1332 SetCursor(bview, cursor.par(), cursor.par()->Last());
1333 /* this is just faster than using CursorLeft(); */
1335 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1336 tmppar = firsttmppar;
1337 /* tmppar is now the paragraph right before the footnote */
1339 bool first_footnote_par_is_not_empty = tmppar->next->size();
1342 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1343 tmppar = tmppar->next; /* I use next instead of Next(),
1344 * because there cannot be any
1345 * footnotes in a footnote
1347 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1349 /* remember the captions and empty paragraphs */
1350 if ((textclasslist.Style(bview->buffer()->params.textclass,
1351 tmppar->GetLayout())
1352 .labeltype == LABEL_SENSITIVE)
1354 tmppar->SetLayout(bview->buffer()->params, 0);
1357 // now we will paste the ex-footnote, if the layouts allow it
1358 // first restore the layout of the paragraph right behind
1361 tmppar->next->MakeSameLayout(cursor.par());
1364 if (!tmppar->GetLayout()
1366 && (!tmppar->Next()->Last()
1367 || tmppar->Next()->HasSameLayout(tmppar)))) {
1368 if (tmppar->Next()->Last()
1369 && tmppar->Next()->IsLineSeparator(0))
1370 tmppar->Next()->Erase(0);
1371 tmppar->PasteParagraph(bview->buffer()->params);
1374 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1375 * by the pasting of the beginning */
1377 /* then the beginning */
1378 /* if there is no space between the text and the footnote, so we insert
1380 * (only if the previous par and the footnotepar are not empty!) */
1381 if (!firsttmppar->next->GetLayout()
1382 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1383 if (firsttmppar->size()
1384 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1385 && first_footnote_par_is_not_empty) {
1386 firsttmppar->next->InsertChar(0, ' ');
1388 firsttmppar->PasteParagraph(bview->buffer()->params);
1391 /* now redo the paragaphs */
1392 RedoParagraphs(bview, cursor, tmppar);
1394 SetCursor(bview, cursor.par(), cursor.pos());
1396 /* sometimes it can happen, that there is a counter change */
1397 Row * row = cursor.row();
1398 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1400 UpdateCounters(bview, row);
1408 /* the DTP switches for paragraphs. LyX will store them in the
1409 * first physicla paragraph. When a paragraph is broken, the top settings
1410 * rest, the bottom settings are given to the new one. So I can make shure,
1411 * they do not duplicate themself and you cannnot make dirty things with
1414 void LyXText::SetParagraph(BufferView * bview,
1415 bool line_top, bool line_bottom,
1416 bool pagebreak_top, bool pagebreak_bottom,
1417 VSpace const & space_top,
1418 VSpace const & space_bottom,
1420 string labelwidthstring,
1423 LyXCursor tmpcursor = cursor;
1425 sel_start_cursor = cursor;
1426 sel_end_cursor = cursor;
1429 // make sure that the depth behind the selection are restored, too
1431 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1433 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1435 LyXParagraph * undoendpar = endpar;
1437 if (endpar && endpar->GetDepth()) {
1438 while (endpar && endpar->GetDepth()) {
1440 endpar = endpar->LastPhysicalPar()->Next();
1442 endpar = endpar->Next();
1444 undoendpar = endpar;
1448 endpar = endpar->Next(); // because of parindents etc.
1451 SetUndo(bview->buffer(), Undo::EDIT,
1454 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1456 sel_start_cursor.par()->previous,
1461 LyXParagraph * tmppar = sel_end_cursor.par();
1463 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1464 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1466 while (tmppar != sel_start_cursor.par()->Previous()) {
1467 SetCursor(bview, tmppar, 0);
1469 status = LyXText::NEED_MORE_REFRESH;
1470 refresh_row = cursor.row();
1471 refresh_y = cursor.y() - cursor.row()->baseline();
1473 if (cursor.par()->footnoteflag ==
1474 sel_start_cursor.par()->footnoteflag) {
1476 cursor.par()->line_top = line_top;
1477 cursor.par()->line_bottom = line_bottom;
1478 cursor.par()->pagebreak_top = pagebreak_top;
1479 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1480 cursor.par()->added_space_top = space_top;
1481 cursor.par()->added_space_bottom = space_bottom;
1482 // does the layout allow the new alignment?
1483 if (align == LYX_ALIGN_LAYOUT)
1484 align = textclasslist
1485 .Style(bview->buffer()->params.textclass,
1486 cursor.par()->GetLayout()).align;
1487 if (align & textclasslist
1488 .Style(bview->buffer()->params.textclass,
1489 cursor.par()->GetLayout()).alignpossible) {
1490 if (align == textclasslist
1491 .Style(bview->buffer()->params.textclass,
1492 cursor.par()->GetLayout()).align)
1493 cursor.par()->align = LYX_ALIGN_LAYOUT;
1495 cursor.par()->align = align;
1497 cursor.par()->SetLabelWidthString(labelwidthstring);
1498 cursor.par()->noindent = noindent;
1502 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1504 tmppar = cursor.par()->Previous();
1508 RedoParagraphs(bview, sel_start_cursor, endpar);
1511 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1512 sel_cursor = cursor;
1513 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1515 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1517 bview->updateInset(inset_owner, true);
1521 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1522 string const & width,
1523 string const & widthp,
1524 int alignment, bool hfill,
1525 bool start_minipage)
1527 LyXCursor tmpcursor = cursor;
1528 LyXParagraph * tmppar;
1530 sel_start_cursor = cursor;
1531 sel_end_cursor = cursor;
1534 // make sure that the depth behind the selection are restored, too
1536 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1538 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1540 LyXParagraph * undoendpar = endpar;
1542 if (endpar && endpar->GetDepth()) {
1543 while (endpar && endpar->GetDepth()) {
1545 endpar = endpar->LastPhysicalPar()->Next();
1547 endpar = endpar->Next();
1549 undoendpar = endpar;
1553 endpar = endpar->Next(); // because of parindents etc.
1556 SetUndo(bview->buffer(), Undo::EDIT,
1559 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1561 sel_start_cursor.par()->previous,
1565 tmppar = sel_end_cursor.par();
1567 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1568 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1570 while(tmppar != sel_start_cursor.par()->Previous()) {
1571 SetCursor(bview, tmppar, 0);
1573 status = LyXText::NEED_MORE_REFRESH;
1574 refresh_row = cursor.row();
1575 refresh_y = cursor.y() - cursor.row()->baseline();
1577 if (cursor.par()->footnoteflag ==
1578 sel_start_cursor.par()->footnoteflag) {
1580 if (type == LyXParagraph::PEXTRA_NONE) {
1581 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1582 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1583 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1586 cursor.par()->SetPExtraType(bview->buffer()->params,
1587 type, width, widthp);
1588 cursor.par()->pextra_hfill = hfill;
1589 cursor.par()->pextra_start_minipage = start_minipage;
1590 cursor.par()->pextra_alignment = alignment;
1594 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1596 tmppar = cursor.par()->Previous();
1599 RedoParagraphs(bview, sel_start_cursor, endpar);
1601 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1602 sel_cursor = cursor;
1603 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1605 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1609 char loweralphaCounter(int n)
1611 if (n < 1 || n > 26)
1619 char alphaCounter(int n)
1621 if (n < 1 || n > 26)
1629 char hebrewCounter(int n)
1631 static const char hebrew[22] = {
1632 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1633 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1634 '÷', 'ø', 'ù', 'ú'
1636 if (n < 1 || n > 22)
1644 string const romanCounter(int n)
1646 static char const * roman[20] = {
1647 "i", "ii", "iii", "iv", "v",
1648 "vi", "vii", "viii", "ix", "x",
1649 "xi", "xii", "xiii", "xiv", "xv",
1650 "xvi", "xvii", "xviii", "xix", "xx"
1652 if (n < 1 || n > 20)
1659 // set the counter of a paragraph. This includes the labels
1660 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1663 // this is only relevant for the beginning of paragraph
1664 par = par->FirstPhysicalPar();
1666 LyXLayout const & layout =
1667 textclasslist.Style(buf->params.textclass,
1670 LyXTextClass const & textclass =
1671 textclasslist.TextClass(buf->params.textclass);
1673 /* copy the prev-counters to this one, unless this is the start of a
1674 footnote or of a bibliography or the very first paragraph */
1677 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1678 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1679 && par->footnotekind == LyXParagraph::FOOTNOTE)
1681 && !(textclasslist.Style(buf->params.textclass,
1682 par->Previous()->GetLayout()
1683 ).labeltype != LABEL_BIBLIO
1684 && layout.labeltype == LABEL_BIBLIO)) {
1685 for (int i = 0; i < 10; ++i) {
1686 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1689 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1691 par->appendix = par->Previous()->appendix;
1693 if (!par->appendix && par->start_of_appendix){
1694 par->appendix = true;
1695 for (int i = 0; i < 10; ++i) {
1696 par->setCounter(i, 0);
1700 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1701 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1703 par->enumdepth = par->Previous()->enumdepth;
1704 par->itemdepth = par->Previous()->itemdepth;
1707 for (int i = 0; i < 10; ++i) {
1708 par->setCounter(i, 0);
1710 par->appendix = par->start_of_appendix;
1716 // if this is an open marginnote and this is the first
1717 // entry in the marginnote and the enclosing
1718 // environment is an enum/item then correct for the
1719 // LaTeX behaviour (ARRae)
1720 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1721 && par->footnotekind == LyXParagraph::MARGIN
1723 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1724 && (par->PreviousBeforeFootnote()
1725 && textclasslist.Style(buf->params.textclass,
1726 par->PreviousBeforeFootnote()->GetLayout()
1727 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1728 // Any itemize or enumerate environment in a marginnote
1729 // that is embedded in an itemize or enumerate
1730 // paragraph is seen by LaTeX as being at a deeper
1731 // level within that enclosing itemization/enumeration
1732 // even if there is a "standard" layout at the start of
1738 /* Maybe we have to increment the enumeration depth.
1739 * BUT, enumeration in a footnote is considered in isolation from its
1740 * surrounding paragraph so don't increment if this is the
1741 * first line of the footnote
1742 * AND, bibliographies can't have their depth changed ie. they
1743 * are always of depth 0
1746 && par->Previous()->GetDepth() < par->GetDepth()
1747 && textclasslist.Style(buf->params.textclass,
1748 par->Previous()->GetLayout()
1749 ).labeltype == LABEL_COUNTER_ENUMI
1750 && par->enumdepth < 3
1752 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1753 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1754 && par->footnotekind == LyXParagraph::FOOTNOTE)
1756 && layout.labeltype != LABEL_BIBLIO) {
1760 /* Maybe we have to decrement the enumeration depth, see note above */
1762 && par->Previous()->GetDepth() > par->GetDepth()
1764 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1765 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1766 && par->footnotekind == LyXParagraph::FOOTNOTE)
1768 && layout.labeltype != LABEL_BIBLIO) {
1769 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1770 par->setCounter(6 + par->enumdepth,
1771 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1772 /* reset the counters.
1773 * A depth change is like a breaking layout
1775 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1776 par->setCounter(i, 0);
1779 if (!par->labelstring.empty()) {
1780 par->labelstring.erase();
1783 if (layout.margintype == MARGIN_MANUAL) {
1784 if (par->labelwidthstring.empty()) {
1785 par->SetLabelWidthString(layout.labelstring());
1788 par->SetLabelWidthString(string());
1791 /* is it a layout that has an automatic label ? */
1792 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1794 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1795 if (i >= 0 && i<= buf->params.secnumdepth) {
1796 par->incCounter(i); // increment the counter
1798 // Is there a label? Useful for Chapter layout
1799 if (!par->appendix){
1800 if (!layout.labelstring().empty())
1801 par->labelstring = layout.labelstring();
1803 par->labelstring.erase();
1805 if (!layout.labelstring_appendix().empty())
1806 par->labelstring = layout.labelstring_appendix();
1808 par->labelstring.erase();
1811 std::ostringstream s;
1813 if (!par->appendix) {
1814 switch (2 * LABEL_COUNTER_CHAPTER -
1815 textclass.maxcounter() + i) {
1816 case LABEL_COUNTER_CHAPTER:
1817 s << par->getCounter(i);
1819 case LABEL_COUNTER_SECTION:
1820 s << par->getCounter(i - 1) << '.'
1821 << par->getCounter(i);
1823 case LABEL_COUNTER_SUBSECTION:
1824 s << par->getCounter(i - 2) << '.'
1825 << par->getCounter(i - 1) << '.'
1826 << par->getCounter(i);
1828 case LABEL_COUNTER_SUBSUBSECTION:
1829 s << par->getCounter(i - 3) << '.'
1830 << par->getCounter(i - 2) << '.'
1831 << par->getCounter(i - 1) << '.'
1832 << par->getCounter(i);
1835 case LABEL_COUNTER_PARAGRAPH:
1836 s << par->getCounter(i - 4) << '.'
1837 << par->getCounter(i - 3) << '.'
1838 << par->getCounter(i - 2) << '.'
1839 << par->getCounter(i - 1) << '.'
1840 << par->getCounter(i);
1842 case LABEL_COUNTER_SUBPARAGRAPH:
1843 s << par->getCounter(i - 5) << '.'
1844 << par->getCounter(i - 4) << '.'
1845 << par->getCounter(i - 3) << '.'
1846 << par->getCounter(i - 2) << '.'
1847 << par->getCounter(i - 1) << '.'
1848 << par->getCounter(i);
1852 // Can this ever be reached? And in the
1853 // case it is, how can this be correct?
1855 s << par->getCounter(i) << '.';
1858 } else { // appendix
1859 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1860 case LABEL_COUNTER_CHAPTER:
1861 if (par->isRightToLeftPar(buf->params))
1862 s << hebrewCounter(par->getCounter(i));
1864 s << alphaCounter(par->getCounter(i));
1866 case LABEL_COUNTER_SECTION:
1867 if (par->isRightToLeftPar(buf->params))
1868 s << hebrewCounter(par->getCounter(i - 1));
1870 s << alphaCounter(par->getCounter(i - 1));
1873 << par->getCounter(i);
1876 case LABEL_COUNTER_SUBSECTION:
1877 if (par->isRightToLeftPar(buf->params))
1878 s << hebrewCounter(par->getCounter(i - 2));
1880 s << alphaCounter(par->getCounter(i - 2));
1883 << par->getCounter(i-1) << '.'
1884 << par->getCounter(i);
1887 case LABEL_COUNTER_SUBSUBSECTION:
1888 if (par->isRightToLeftPar(buf->params))
1889 s << hebrewCounter(par->getCounter(i-3));
1891 s << alphaCounter(par->getCounter(i-3));
1894 << par->getCounter(i-2) << '.'
1895 << par->getCounter(i-1) << '.'
1896 << par->getCounter(i);
1899 case LABEL_COUNTER_PARAGRAPH:
1900 if (par->isRightToLeftPar(buf->params))
1901 s << hebrewCounter(par->getCounter(i-4));
1903 s << alphaCounter(par->getCounter(i-4));
1906 << par->getCounter(i-3) << '.'
1907 << par->getCounter(i-2) << '.'
1908 << par->getCounter(i-1) << '.'
1909 << par->getCounter(i);
1912 case LABEL_COUNTER_SUBPARAGRAPH:
1913 if (par->isRightToLeftPar(buf->params))
1914 s << hebrewCounter(par->getCounter(i-5));
1916 s << alphaCounter(par->getCounter(i-5));
1919 << par->getCounter(i-4) << '.'
1920 << par->getCounter(i-3) << '.'
1921 << par->getCounter(i-2) << '.'
1922 << par->getCounter(i-1) << '.'
1923 << par->getCounter(i);
1927 // Can this ever be reached? And in the
1928 // case it is, how can this be correct?
1930 s << par->getCounter(i) << '.';
1936 par->labelstring += s.str().c_str();
1937 // We really want to remove the c_str as soon as
1940 for (i++; i < 10; ++i) {
1941 // reset the following counters
1942 par->setCounter(i, 0);
1944 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1945 for (i++; i < 10; ++i) {
1946 // reset the following counters
1947 par->setCounter(i, 0);
1949 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1950 par->incCounter(i + par->enumdepth);
1951 int number = par->getCounter(i + par->enumdepth);
1953 std::ostringstream s;
1955 switch (par->enumdepth) {
1957 if (par->isRightToLeftPar(buf->params))
1959 << hebrewCounter(number)
1963 << loweralphaCounter(number)
1967 if (par->isRightToLeftPar(buf->params))
1968 s << '.' << romanCounter(number);
1970 s << romanCounter(number) << '.';
1973 if (par->isRightToLeftPar(buf->params))
1975 << alphaCounter(number);
1977 s << alphaCounter(number)
1981 if (par->isRightToLeftPar(buf->params))
1988 par->labelstring = s.str().c_str();
1989 // we really want to get rid of that c_str()
1991 for (i += par->enumdepth + 1; i < 10; ++i)
1992 par->setCounter(i, 0); /* reset the following counters */
1995 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1996 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1998 int number = par->getCounter(i);
2000 InsetCommandParams p( "bibitem" );
2001 par->bibkey = new InsetBibKey(p);
2003 par->bibkey->setCounter(number);
2004 par->labelstring = layout.labelstring();
2006 // In biblio should't be following counters but...
2008 string s = layout.labelstring();
2010 // the caption hack:
2011 if (layout.labeltype == LABEL_SENSITIVE) {
2012 bool isOK (par->InInset() && par->InInset()->owner() &&
2013 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2015 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2016 && (par->footnotekind == LyXParagraph::FIG
2017 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2018 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2019 ? ":øåéà " : "Figure:";
2020 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2021 && (par->footnotekind == LyXParagraph::TAB
2022 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2023 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2024 ? ":äìáè" : "Table:";
2025 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2026 && par->footnotekind == LyXParagraph::ALGORITHM) {
2027 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2028 ? ":Ãúéøåâìà " : "Algorithm:";
2032 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2034 = floatList.getType(tmp->type());
2035 // We should get the correct number here too.
2036 s = fl.name + " #:";
2038 /* par->SetLayout(0);
2039 s = layout->labelstring; */
2040 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2041 ? " :úåòîùî øñç" : "Senseless: ";
2044 par->labelstring = s;
2046 /* reset the enumeration counter. They are always resetted
2047 * when there is any other layout between */
2048 for (int i = 6 + par->enumdepth; i < 10; ++i)
2049 par->setCounter(i, 0);
2054 /* Updates all counters BEHIND the row. Changed paragraphs
2055 * with a dynamic left margin will be rebroken. */
2056 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2063 if (row->par()->next
2065 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2069 par = row->par()->LastPhysicalPar()->Next();
2071 par = row->par()->Next();
2074 par = row->par()->next;
2079 while (row->par() != par)
2082 SetCounter(bview->buffer(), par);
2084 /* now check for the headline layouts. remember that they
2085 * have a dynamic left margin */
2090 ( textclasslist.Style(bview->buffer()->params.textclass,
2091 par->layout).margintype == MARGIN_DYNAMIC
2092 || textclasslist.Style(bview->buffer()->params.textclass,
2093 par->layout).labeltype == LABEL_SENSITIVE)
2096 /* Rebreak the paragraph */
2097 RemoveParagraph(row);
2098 AppendParagraph(bview, row);
2101 /* think about the damned open footnotes! */
2102 while (par->Next() &&
2103 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2104 || par->Next()->IsDummy())){
2106 if (par->IsDummy()) {
2107 while (row->par() != par)
2109 RemoveParagraph(row);
2110 AppendParagraph(bview, row);
2116 par = par->LastPhysicalPar()->Next();
2125 /* insets an inset. */
2126 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2128 if (!cursor.par()->InsertInsetAllowed(inset))
2130 SetUndo(bview->buffer(), Undo::INSERT,
2132 cursor.par()->ParFromPos(cursor.pos())->previous,
2133 cursor.par()->ParFromPos(cursor.pos())->next
2135 cursor.par()->previous,
2139 cursor.par()->InsertInset(cursor.pos(), inset);
2140 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2141 * The character will not be inserted a
2146 void LyXText::copyEnvironmentType()
2148 copylayouttype = cursor.par()->GetLayout();
2152 void LyXText::pasteEnvironmentType(BufferView * bview)
2154 SetLayout(bview, copylayouttype);
2158 void LyXText::CutSelection(BufferView * bview, bool doclear)
2160 // Stuff what we got on the clipboard. Even if there is no selection.
2162 // There is a problem with having the stuffing here in that the
2163 // larger the selection the slower LyX will get. This can be
2164 // solved by running the line below only when the selection has
2165 // finished. The solution used currently just works, to make it
2166 // faster we need to be more clever and probably also have more
2167 // calls to stuffClipboard. (Lgb)
2168 bview->stuffClipboard(selectionAsString(bview->buffer()));
2170 // This doesn't make sense, if there is no selection
2174 // OK, we have a selection. This is always between sel_start_cursor
2175 // and sel_end cursor
2177 // Check whether there are half footnotes in the selection
2178 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2179 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2180 LyXParagraph * tmppar = sel_start_cursor.par();
2181 while (tmppar != sel_end_cursor.par()){
2182 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2183 WriteAlert(_("Impossible operation"),
2184 _("Don't know what to do with half floats."),
2188 tmppar = tmppar->Next();
2193 // make sure that the depth behind the selection are restored, too
2195 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2197 LyXParagraph * endpar = sel_end_cursor.par()->Next();
2199 LyXParagraph * undoendpar = endpar;
2201 if (endpar && endpar->GetDepth()) {
2202 while (endpar && endpar->GetDepth()) {
2204 endpar = endpar->LastPhysicalPar()->Next();
2206 endpar = endpar->Next();
2208 undoendpar = endpar;
2210 } else if (endpar) {
2211 endpar = endpar->Next(); // because of parindents etc.
2214 SetUndo(bview->buffer(), Undo::DELETE,
2217 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2219 sel_start_cursor.par()->previous,
2225 // there are two cases: cut only within one paragraph or
2226 // more than one paragraph
2228 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2229 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2231 if (sel_start_cursor.par() == sel_end_cursor.par())
2234 // only within one paragraph
2235 endpar = sel_start_cursor.par();
2236 int pos = sel_end_cursor.pos();
2237 cap.cutSelection(sel_start_cursor.par(), &endpar,
2238 sel_start_cursor.pos(), pos,
2239 bview->buffer()->params.textclass, doclear);
2240 sel_end_cursor.pos(pos);
2242 endpar = sel_end_cursor.par();
2244 int pos = sel_end_cursor.pos();
2245 cap.cutSelection(sel_start_cursor.par(), &endpar,
2246 sel_start_cursor.pos(), pos,
2247 bview->buffer()->params.textclass, doclear);
2249 sel_end_cursor.par(endpar);
2250 sel_end_cursor.pos(pos);
2251 cursor.pos(sel_end_cursor.pos());
2253 endpar = endpar->Next();
2255 // sometimes necessary
2257 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2259 RedoParagraphs(bview, sel_start_cursor, endpar);
2262 cursor = sel_start_cursor;
2263 SetCursor(bview, cursor.par(), cursor.pos());
2264 sel_cursor = cursor;
2265 UpdateCounters(bview, cursor.row());
2269 void LyXText::CopySelection(BufferView * bview)
2271 // Stuff what we got on the clipboard. Even if there is no selection.
2273 // There is a problem with having the stuffing here in that the
2274 // larger the selection the slower LyX will get. This can be
2275 // solved by running the line below only when the selection has
2276 // finished. The solution used currently just works, to make it
2277 // faster we need to be more clever and probably also have more
2278 // calls to stuffClipboard. (Lgb)
2279 bview->stuffClipboard(selectionAsString(bview->buffer()));
2281 // this doesnt make sense, if there is no selection
2285 // ok we have a selection. This is always between sel_start_cursor
2286 // and sel_end cursor
2289 /* check wether there are half footnotes in the selection */
2290 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2291 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2292 LyXParagraph * tmppar = sel_start_cursor.par();
2293 while (tmppar != sel_end_cursor.par()) {
2294 if (tmppar->footnoteflag !=
2295 sel_end_cursor.par()->footnoteflag) {
2296 WriteAlert(_("Impossible operation"),
2297 _("Don't know what to do"
2298 " with half floats."),
2302 tmppar = tmppar->Next();
2307 // copy behind a space if there is one
2308 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2309 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2310 && (sel_start_cursor.par() != sel_end_cursor.par()
2311 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2312 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2316 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2317 sel_start_cursor.pos(), sel_end_cursor.pos(),
2318 bview->buffer()->params.textclass);
2322 void LyXText::PasteSelection(BufferView * bview)
2326 // this does not make sense, if there is nothing to paste
2327 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2330 SetUndo(bview->buffer(), Undo::INSERT,
2332 cursor.par()->ParFromPos(cursor.pos())->previous,
2333 cursor.par()->ParFromPos(cursor.pos())->next
2335 cursor.par()->previous,
2340 LyXParagraph * endpar;
2341 LyXParagraph * actpar = cursor.par();
2343 int pos = cursor.pos();
2344 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2346 RedoParagraphs(bview, cursor, endpar);
2348 SetCursor(bview, cursor.par(), cursor.pos());
2351 sel_cursor = cursor;
2352 SetCursor(bview, actpar, pos);
2354 UpdateCounters(bview, cursor.row());
2358 // returns a pointer to the very first LyXParagraph
2359 LyXParagraph * LyXText::FirstParagraph() const
2361 return OwnerParagraph();
2365 // returns true if the specified string is at the specified position
2366 bool LyXText::IsStringInText(LyXParagraph * par,
2367 LyXParagraph::size_type pos,
2368 string const & str) const
2371 LyXParagraph::size_type i = 0;
2372 while (pos + i < par->Last()
2373 && string::size_type(i) < str.length()
2374 && str[i] == par->GetChar(pos + i)) {
2377 if (str.length() == string::size_type(i))
2384 // sets the selection over the number of characters of string, no check!!
2385 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2387 sel_cursor = cursor;
2388 for (int i = 0; str[i]; ++i)
2394 // simple replacing. The font of the first selected character is used
2395 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2398 SetCursorParUndo(bview->buffer());
2401 if (!selection) { // create a dummy selection
2402 sel_end_cursor = cursor;
2403 sel_start_cursor = cursor;
2406 // Get font setting before we cut
2407 LyXParagraph::size_type pos = sel_end_cursor.pos();
2408 LyXFont const font = sel_start_cursor.par()
2409 ->GetFontSettings(bview->buffer()->params,
2410 sel_start_cursor.pos());
2412 // Insert the new string
2413 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2414 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2418 // Cut the selection
2419 CutSelection(bview);
2425 // if the string can be found: return true and set the cursor to
2427 bool LyXText::SearchForward(BufferView * bview, string const & str) const
2429 LyXParagraph * par = cursor.par();
2430 LyXParagraph::size_type pos = cursor.pos();
2431 while (par && !IsStringInText(par, pos, str)) {
2432 if (pos < par->Last() - 1)
2440 SetCursor(bview, par, pos);
2448 bool LyXText::SearchBackward(BufferView * bview, string const & str) const
2450 LyXParagraph * par = cursor.par();
2451 int pos = cursor.pos();
2457 // We skip empty paragraphs (Asger)
2459 par = par->Previous();
2461 pos = par->Last() - 1;
2462 } while (par && pos < 0);
2464 } while (par && !IsStringInText(par, pos, str));
2467 SetCursor(bview, par, pos);
2474 // needed to insert the selection
2475 void LyXText::InsertStringA(BufferView * bview, string const & str)
2477 LyXParagraph * par = cursor.par();
2478 LyXParagraph::size_type pos = cursor.pos();
2479 LyXParagraph::size_type a = 0;
2480 LyXParagraph * endpar = cursor.par()->Next();
2482 SetCursorParUndo(bview->buffer());
2485 textclasslist.Style(bview->buffer()->params.textclass,
2486 cursor.par()->GetLayout()).isEnvironment();
2487 // only to be sure, should not be neccessary
2490 // insert the string, don't insert doublespace
2491 string::size_type i = 0;
2492 while (i < str.length()) {
2493 if (str[i] != '\n') {
2495 && i + 1 < str.length() && str[i + 1] != ' '
2496 && pos && par->GetChar(pos - 1)!= ' ') {
2497 par->InsertChar(pos, ' ', current_font);
2499 } else if (str[i] == ' ') {
2500 InsetSpecialChar * new_inset =
2501 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2502 if (par->InsertInsetAllowed(new_inset)) {
2503 par->InsertInset(pos, new_inset,
2509 } else if (str[i] == '\t') {
2510 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2511 InsetSpecialChar * new_inset =
2512 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2513 if (par->InsertInsetAllowed(new_inset)) {
2514 par->InsertInset(pos, new_inset,
2521 } else if (str[i] != 13 &&
2522 // Ignore unprintables
2523 (str[i] & 127) >= ' ') {
2524 par->InsertChar(pos, str[i], current_font);
2528 if (!par->size()) { // par is empty
2529 InsetSpecialChar * new_inset =
2530 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2531 if (par->InsertInsetAllowed(new_inset)) {
2532 par->InsertInset(pos,
2540 par->BreakParagraph(bview->buffer()->params, pos, flag);
2547 RedoParagraphs(bview, cursor, endpar);
2548 SetCursor(bview, cursor.par(), cursor.pos());
2549 sel_cursor = cursor;
2550 SetCursor(bview, par, pos);
2555 /* turns double-CR to single CR, others where converted into one blank and 13s
2556 * that are ignored .Double spaces are also converted into one. Spaces at
2557 * the beginning of a paragraph are forbidden. tabs are converted into one
2558 * space. then InsertStringA is called */
2559 void LyXText::InsertStringB(BufferView * bview, string const & s)
2562 string::size_type i = 1;
2563 while (i < str.length()) {
2566 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2568 if (str[i] == '\n' && i + 1 < str.length()) {
2569 if (str[i + 1] != '\n') {
2570 if (str[i - 1] != ' ')
2575 while (i + 1 < str.length()
2576 && (str[i + 1] == ' '
2577 || str[i + 1] == '\t'
2578 || str[i + 1] == '\n'
2579 || str[i + 1] == 13)) {
2586 InsertStringA(bview, str);
2590 bool LyXText::GotoNextError(BufferView * bview) const
2592 LyXCursor res = cursor;
2594 if (res.pos() < res.par()->Last() - 1) {
2595 res.pos(res.pos() + 1);
2597 res.par(res.par()->Next());
2601 } while (res.par() &&
2602 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2603 && res.par()->GetInset(res.pos())->AutoDelete()));
2606 SetCursor(bview, res.par(), res.pos());
2613 bool LyXText::GotoNextNote(BufferView * bview) const
2615 LyXCursor res = cursor;
2617 if (res.pos() < res.par()->Last() - 1) {
2618 res.pos(res.pos() + 1);
2620 res.par(res.par()->Next());
2624 } while (res.par() &&
2625 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2626 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2629 SetCursor(bview, res.par(), res.pos());
2636 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2637 LyXParagraph::size_type pos)
2639 LyXCursor tmpcursor;
2642 LyXParagraph::size_type z;
2643 Row * row = GetRow(par, pos, y);
2645 // is there a break one row above
2646 if (row->previous() && row->previous()->par() == row->par()) {
2647 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2648 if ( z >= row->pos()) {
2649 // set the dimensions of the row above
2650 y -= row->previous()->height();
2652 refresh_row = row->previous();
2653 status = LyXText::NEED_MORE_REFRESH;
2655 BreakAgain(bview, row->previous());
2657 // set the cursor again. Otherwise
2658 // dangling pointers are possible
2659 SetCursor(bview, cursor.par(), cursor.pos());
2660 sel_cursor = cursor;
2665 int const tmpheight = row->height();
2666 LyXParagraph::size_type const tmplast = RowLast(row);
2670 BreakAgain(bview, row);
2671 if (row->height() == tmpheight && RowLast(row) == tmplast)
2672 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2674 status = LyXText::NEED_MORE_REFRESH;
2676 // check the special right address boxes
2677 if (textclasslist.Style(bview->buffer()->params.textclass,
2678 par->GetLayout()).margintype
2679 == MARGIN_RIGHT_ADDRESS_BOX) {
2686 RedoDrawingOfParagraph(bview, tmpcursor);
2689 // set the cursor again. Otherwise dangling pointers are possible
2690 // also set the selection
2694 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2695 sel_cursor = cursor;
2696 SetCursorIntern(bview, sel_start_cursor.par(),
2697 sel_start_cursor.pos());
2698 sel_start_cursor = cursor;
2699 SetCursorIntern(bview, sel_end_cursor.par(),
2700 sel_end_cursor.pos());
2701 sel_end_cursor = cursor;
2702 SetCursorIntern(bview, last_sel_cursor.par(),
2703 last_sel_cursor.pos());
2704 last_sel_cursor = cursor;
2707 SetCursorIntern(bview, cursor.par(), cursor.pos());
2711 // returns false if inset wasn't found
2712 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2714 // first check the current paragraph
2715 int pos = cursor.par()->GetPositionOfInset(inset);
2717 CheckParagraph(bview, cursor.par(), pos);
2721 // check every paragraph
2723 LyXParagraph * par = FirstParagraph();
2726 // make sure the paragraph is open
2727 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2729 pos = par->GetPositionOfInset(inset);
2731 CheckParagraph(bview, par, pos);
2744 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2745 LyXParagraph::size_type pos,
2746 bool setfont, bool boundary) const
2748 LyXCursor old_cursor = cursor;
2749 SetCursorIntern(bview, par, pos, setfont, boundary);
2750 DeleteEmptyParagraphMechanism(bview, old_cursor);
2754 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2755 LyXParagraph::size_type pos, bool boundary) const
2758 // correct the cursor position if impossible
2759 if (pos > par->Last()){
2760 LyXParagraph * tmppar = par->ParFromPos(pos);
2761 pos = par->PositionInParFromPos(pos);
2764 if (par->IsDummy() && par->previous &&
2765 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2766 while (par->previous &&
2767 ((par->previous->IsDummy() &&
2768 (par->previous->previous->footnoteflag ==
2769 LyXParagraph::CLOSED_FOOTNOTE)) ||
2770 (par->previous->footnoteflag ==
2771 LyXParagraph::CLOSED_FOOTNOTE))) {
2772 par = par->previous ;
2773 if (par->IsDummy() &&
2774 (par->previous->footnoteflag ==
2775 LyXParagraph::CLOSED_FOOTNOTE))
2776 pos += par->size() + 1;
2778 if (par->previous) {
2779 par = par->previous;
2781 pos += par->size() + 1;
2786 cur.boundary(boundary);
2788 /* get the cursor y position in text */
2790 Row * row = GetRow(par, pos, y);
2791 /* y is now the beginning of the cursor row */
2792 y += row->baseline();
2793 /* y is now the cursor baseline */
2796 /* now get the cursors x position */
2798 float fill_separator, fill_hfill, fill_label_hfill;
2799 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2801 LyXParagraph::size_type cursor_vpos = 0;
2802 LyXParagraph::size_type last = RowLastPrintable(row);
2804 if (pos > last + 1) // This shouldn't happen.
2806 else if (pos < row->pos())
2809 if (last < row->pos())
2810 cursor_vpos = row->pos();
2811 else if (pos > last && !boundary)
2812 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2813 ? row->pos() : last + 1;
2814 else if (pos > row->pos() &&
2815 (pos > last || boundary))
2816 /// Place cursor after char at (logical) position pos - 1
2817 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2818 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2820 /// Place cursor before char at (logical) position pos
2821 cursor_vpos = (bidi_level(pos) % 2 == 0)
2822 ? log2vis(pos) : log2vis(pos) + 1;
2824 LyXParagraph::size_type main_body =
2825 BeginningOfMainBody(bview->buffer(), row->par());
2826 if ((main_body > 0) &&
2827 ((main_body-1 > last) ||
2828 !row->par()->IsLineSeparator(main_body-1)))
2831 for (LyXParagraph::size_type vpos = row->pos();
2832 vpos < cursor_vpos; ++vpos) {
2833 pos = vis2log(vpos);
2834 if (main_body > 0 && pos == main_body - 1) {
2835 x += fill_label_hfill +
2836 lyxfont::width(textclasslist.Style(
2837 bview->buffer()->params.textclass,
2838 row->par()->GetLayout())
2840 GetFont(bview->buffer(), row->par(), -2));
2841 if (row->par()->IsLineSeparator(main_body-1))
2842 x -= SingleWidth(bview, row->par(),main_body-1);
2844 if (HfillExpansion(bview->buffer(), row, pos)) {
2845 x += SingleWidth(bview, row->par(), pos);
2846 if (pos >= main_body)
2849 x += fill_label_hfill;
2850 } else if (row->par()->IsSeparator(pos)) {
2851 x += SingleWidth(bview, row->par(), pos);
2852 if (pos >= main_body)
2853 x += fill_separator;
2855 x += SingleWidth(bview, row->par(), pos);
2864 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2865 LyXParagraph::size_type pos,
2866 bool setfont, bool boundary) const
2868 SetCursor(bview, cursor, par, pos, boundary);
2870 SetCurrentFont(bview);
2874 void LyXText::SetCurrentFont(BufferView * bview) const
2876 LyXParagraph::size_type pos = cursor.pos();
2877 if (cursor.boundary() && pos > 0)
2881 if (pos == cursor.par()->Last())
2883 else if (cursor.par()->IsSeparator(pos)) {
2884 if (pos > cursor.row()->pos() &&
2885 bidi_level(pos) % 2 ==
2886 bidi_level(pos - 1) % 2)
2888 else if (pos + 1 < cursor.par()->Last())
2894 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2895 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2897 if (cursor.pos() == cursor.par()->Last() &&
2898 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2899 !cursor.boundary()) {
2900 Language const * lang =
2901 cursor.par()->getParLanguage(bview->buffer()->params);
2902 current_font.setLanguage(lang);
2903 real_current_font.setLanguage(lang);
2908 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
2910 LyXCursor old_cursor = cursor;
2912 /* get the row first */
2914 Row * row = GetRowNearY(y);
2915 cursor.par(row->par());
2918 int column = GetColumnNearX(bview, row, x, bound);
2919 cursor.pos(row->pos() + column);
2921 cursor.y(y + row->baseline());
2923 cursor.boundary(bound);
2924 SetCurrentFont(bview);
2925 DeleteEmptyParagraphMechanism(bview, old_cursor);
2929 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2930 int x, long y) const
2932 /* get the row first */
2934 Row * row = GetRowNearY(y);
2936 int column = GetColumnNearX(bview, row, x, bound);
2938 cur.par(row->par());
2939 cur.pos(row->pos() + column);
2941 cur.y(y + row->baseline());
2943 cur.boundary(bound);
2947 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2949 if (cursor.pos() > 0) {
2950 bool boundary = cursor.boundary();
2951 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2952 if (!internal && !boundary &&
2953 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2954 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2955 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2956 LyXParagraph * par = cursor.par()->Previous();
2957 SetCursor(bview, par, par->Last());
2962 void LyXText::CursorRight(BufferView * bview, bool internal) const
2964 if (!internal && cursor.boundary() &&
2965 !cursor.par()->IsNewline(cursor.pos()))
2966 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2967 else if (cursor.pos() < cursor.par()->Last()) {
2968 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2970 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2971 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2972 } else if (cursor.par()->Next())
2973 SetCursor(bview, cursor.par()->Next(), 0);
2977 void LyXText::CursorUp(BufferView * bview) const
2979 SetCursorFromCoordinates(bview, cursor.x_fix(),
2980 cursor.y() - cursor.row()->baseline() - 1);
2984 void LyXText::CursorDown(BufferView * bview) const
2986 SetCursorFromCoordinates(bview, cursor.x_fix(),
2987 cursor.y() - cursor.row()->baseline()
2988 + cursor.row()->height() + 1);
2992 void LyXText::CursorUpParagraph(BufferView * bview) const
2994 if (cursor.pos() > 0) {
2995 SetCursor(bview, cursor.par(), 0);
2997 else if (cursor.par()->Previous()) {
2998 SetCursor(bview, cursor.par()->Previous(), 0);
3003 void LyXText::CursorDownParagraph(BufferView * bview) const
3005 if (cursor.par()->Next()) {
3006 SetCursor(bview, cursor.par()->Next(), 0);
3008 SetCursor(bview, cursor.par(), cursor.par()->Last());
3013 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3014 LyXCursor const & old_cursor) const
3016 // Would be wrong to delete anything if we have a selection.
3017 if (selection) return;
3019 // We allow all kinds of "mumbo-jumbo" when freespacing.
3020 if (textclasslist.Style(bview->buffer()->params.textclass,
3021 old_cursor.par()->GetLayout()).free_spacing)
3024 bool deleted = false;
3026 /* Ok I'll put some comments here about what is missing.
3027 I have fixed BackSpace (and thus Delete) to not delete
3028 double-spaces automagically. I have also changed Cut,
3029 Copy and Paste to hopefully do some sensible things.
3030 There are still some small problems that can lead to
3031 double spaces stored in the document file or space at
3032 the beginning of paragraphs. This happens if you have
3033 the cursor betwenn to spaces and then save. Or if you
3034 cut and paste and the selection have a space at the
3035 beginning and then save right after the paste. I am
3036 sure none of these are very hard to fix, but I will
3037 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3038 that I can get some feedback. (Lgb)
3041 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3042 // delete the LineSeparator.
3045 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3046 // delete the LineSeparator.
3049 // If the pos around the old_cursor were spaces, delete one of them.
3050 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3051 // Only if the cursor has really moved
3053 if (old_cursor.pos() > 0
3054 && old_cursor.pos() < old_cursor.par()->Last()
3055 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3056 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3057 old_cursor.par()->Erase(old_cursor.pos() - 1);
3058 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3060 if (old_cursor.par() == cursor.par() &&
3061 cursor.pos() > old_cursor.pos()) {
3062 SetCursorIntern(bview, cursor.par(),
3065 SetCursorIntern(bview, cursor.par(),
3071 // Do not delete empty paragraphs with keepempty set.
3072 if ((textclasslist.Style(bview->buffer()->params.textclass,
3073 old_cursor.par()->GetLayout())).keepempty)
3076 LyXCursor tmpcursor;
3078 if (old_cursor.par() != cursor.par()) {
3079 if ( (old_cursor.par()->Last() == 0
3080 || (old_cursor.par()->Last() == 1
3081 && old_cursor.par()->IsLineSeparator(0)))
3083 && old_cursor.par()->FirstPhysicalPar()
3084 == old_cursor.par()->LastPhysicalPar()
3087 // ok, we will delete anything
3089 // make sure that you do not delete any environments
3092 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3093 !(old_cursor.row()->previous()
3094 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3095 && !(old_cursor.row()->next()
3096 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3097 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3098 && ((old_cursor.row()->previous()
3099 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3100 || (old_cursor.row()->next()
3101 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3104 status = LyXText::NEED_MORE_REFRESH;
3107 if (old_cursor.row()->previous()) {
3108 refresh_row = old_cursor.row()->previous();
3109 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3111 cursor = old_cursor; // that undo can restore the right cursor position
3112 LyXParagraph * endpar = old_cursor.par()->next;
3113 if (endpar && endpar->GetDepth()) {
3114 while (endpar && endpar->GetDepth()) {
3116 endpar = endpar->LastPhysicalPar()->Next();
3118 endpar = endpar->Next();
3122 SetUndo(bview->buffer(), Undo::DELETE,
3123 old_cursor.par()->previous,
3128 RemoveRow(old_cursor.row());
3129 if (OwnerParagraph() == old_cursor.par()) {
3130 OwnerParagraph(OwnerParagraph()->next);
3133 delete old_cursor.par();
3135 /* Breakagain the next par. Needed
3136 * because of the parindent that
3137 * can occur or dissappear. The
3138 * next row can change its height,
3139 * if there is another layout before */
3140 if (refresh_row->next()) {
3141 BreakAgain(bview, refresh_row->next());
3142 UpdateCounters(bview, refresh_row);
3144 SetHeightOfRow(bview, refresh_row);
3146 refresh_row = old_cursor.row()->next();
3147 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3150 cursor = old_cursor; // that undo can restore the right cursor position
3151 LyXParagraph * endpar = old_cursor.par()->next;
3152 if (endpar && endpar->GetDepth()) {
3153 while (endpar && endpar->GetDepth()) {
3155 endpar = endpar->LastPhysicalPar()->Next();
3157 endpar = endpar->Next();
3161 SetUndo(bview->buffer(), Undo::DELETE,
3162 old_cursor.par()->previous,
3167 RemoveRow(old_cursor.row());
3169 if (OwnerParagraph() == old_cursor.par()) {
3170 OwnerParagraph(OwnerParagraph()->next);
3172 delete old_cursor.par();
3174 /* Breakagain the next par. Needed
3175 because of the parindent that can
3176 occur or dissappear.
3177 The next row can change its height,
3178 if there is another layout before
3181 BreakAgain(bview, refresh_row);
3182 UpdateCounters(bview, refresh_row->previous());
3188 SetCursorIntern(bview, cursor.par(), cursor.pos());
3190 if (sel_cursor.par() == old_cursor.par()
3191 && sel_cursor.pos() == sel_cursor.pos()) {
3192 // correct selection
3193 sel_cursor = cursor;
3200 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3201 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3203 SetCursorIntern(bview, cursor.par(), cursor.pos());
3204 sel_cursor = cursor;
3211 LyXParagraph * LyXText::GetParFromID(int id)
3213 LyXParagraph * result = FirstParagraph();
3214 while (result && result->id() != id)
3215 result = result->next;
3221 bool LyXText::TextUndo(BufferView * bview)
3225 // returns false if no undo possible
3226 Undo * undo = bview->buffer()->undostack.pop();
3230 bview->buffer()->redostack
3231 .push(CreateUndo(bview->buffer(), undo->kind,
3232 GetParFromID(undo->number_of_before_par),
3233 GetParFromID(undo->number_of_behind_par)));
3235 return TextHandleUndo(bview, undo);
3239 bool LyXText::TextRedo(BufferView * bview)
3243 // returns false if no redo possible
3244 Undo * undo = bview->buffer()->redostack.pop();
3248 bview->buffer()->undostack
3249 .push(CreateUndo(bview->buffer(), undo->kind,
3250 GetParFromID(undo->number_of_before_par),
3251 GetParFromID(undo->number_of_behind_par)));
3253 return TextHandleUndo(bview, undo);
3257 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3261 // returns false if no undo possible
3262 bool result = false;
3264 LyXParagraph * before =
3265 GetParFromID(undo->number_of_before_par);
3266 LyXParagraph * behind =
3267 GetParFromID(undo->number_of_behind_par);
3268 LyXParagraph * tmppar;
3269 LyXParagraph * tmppar2;
3270 LyXParagraph * endpar;
3271 LyXParagraph * tmppar5;
3273 // if there's no before take the beginning
3274 // of the document for redoing
3276 SetCursorIntern(bview, FirstParagraph(), 0);
3278 // replace the paragraphs with the undo informations
3280 LyXParagraph * tmppar3 = undo->par;
3281 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3282 LyXParagraph * tmppar4 = tmppar3;
3284 while (tmppar4->next)
3285 tmppar4 = tmppar4->next;
3286 } // get last undo par
3288 // now remove the old text if there is any
3289 if (before != behind || (!behind && !before)){
3291 tmppar5 = before->next;
3293 tmppar5 = OwnerParagraph();
3295 while (tmppar5 && tmppar5 != behind){
3297 tmppar5 = tmppar5->next;
3298 // a memory optimization for edit: Only layout information
3299 // is stored in the undo. So restore the text informations.
3300 if (undo->kind == Undo::EDIT) {
3301 tmppar2->setContentsFromPar(tmppar);
3302 tmppar->clearContents();
3303 tmppar2 = tmppar2->next;
3308 // put the new stuff in the list if there is one
3311 before->next = tmppar3;
3313 OwnerParagraph(tmppar3);
3314 tmppar3->previous = before;
3317 OwnerParagraph(behind);
3320 tmppar4->next = behind;
3322 behind->previous = tmppar4;
3326 // Set the cursor for redoing
3329 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3331 SetCursorIntern(bview, before, 0);
3334 // check wether before points to a closed float and open it if necessary
3335 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3336 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3338 while (tmppar4->previous &&
3339 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3340 tmppar4 = tmppar4->previous;
3341 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3342 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3343 tmppar4 = tmppar4->next;
3350 // open a cosed footnote at the end if necessary
3351 if (behind && behind->previous &&
3352 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3353 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3354 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3355 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3356 behind = behind->next;
3361 // calculate the endpar for redoing the paragraphs.
3364 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3365 endpar = behind->LastPhysicalPar()->Next();
3367 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3369 endpar = behind->Next();
3374 tmppar = GetParFromID(undo->number_of_cursor_par);
3375 RedoParagraphs(bview, cursor, endpar);
3377 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3378 UpdateCounters(bview, cursor.row());
3388 void LyXText::FinishUndo()
3392 // makes sure the next operation will be stored
3393 undo_finished = true;
3397 void LyXText::FreezeUndo()
3401 // this is dangerous and for internal use only
3406 void LyXText::UnFreezeUndo()
3410 // this is dangerous and for internal use only
3411 undo_frozen = false;
3415 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3416 LyXParagraph const * before,
3417 LyXParagraph const * behind) const
3422 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3423 buf->redostack.clear();
3427 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3428 LyXParagraph const * before, LyXParagraph const * behind)
3432 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3436 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3437 LyXParagraph const * before,
3438 LyXParagraph const * behind) const
3443 int before_number = -1;
3444 int behind_number = -1;
3446 before_number = before->id();
3448 behind_number = behind->id();
3449 // Undo::EDIT and Undo::FINISH are
3450 // always finished. (no overlapping there)
3451 // overlapping only with insert and delete inside one paragraph:
3452 // Nobody wants all removed character
3453 // appear one by one when undoing.
3454 // EDIT is special since only layout information, not the
3455 // contents of a paragaph are stored.
3456 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3457 // check wether storing is needed
3458 if (!buf->undostack.empty() &&
3459 buf->undostack.top()->kind == kind &&
3460 buf->undostack.top()->number_of_before_par == before_number &&
3461 buf->undostack.top()->number_of_behind_par == behind_number ){
3466 // create a new Undo
3467 LyXParagraph * undopar;
3468 LyXParagraph * tmppar;
3469 LyXParagraph * tmppar2;
3471 LyXParagraph * start = 0;
3472 LyXParagraph * end = 0;
3475 start = before->next;
3477 start = FirstParagraph();
3479 end = behind->previous;
3481 end = FirstParagraph();
3487 && start != end->next
3488 && (before != behind || (!before && !behind))) {
3490 tmppar2 = tmppar->Clone();
3491 tmppar2->id(tmppar->id());
3493 // a memory optimization: Just store the layout information
3495 if (kind == Undo::EDIT){
3496 //tmppar2->text.clear();
3497 tmppar2->clearContents();
3502 while (tmppar != end && tmppar->next) {
3503 tmppar = tmppar->next;
3504 tmppar2->next = tmppar->Clone();
3505 tmppar2->next->id(tmppar->id());
3506 // a memory optimization: Just store the layout
3507 // information when only edit
3508 if (kind == Undo::EDIT){
3509 //tmppar2->next->text.clear();
3510 tmppar2->clearContents();
3512 tmppar2->next->previous = tmppar2;
3513 tmppar2 = tmppar2->next;
3517 undopar = 0; // nothing to replace (undo of delete maybe)
3520 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3521 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3523 int cursor_par = cursor.par()->id();
3524 int cursor_pos = cursor.pos();
3527 Undo * undo = new Undo(kind,
3528 before_number, behind_number,
3529 cursor_par, cursor_pos,
3532 undo_finished = false;
3537 void LyXText::SetCursorParUndo(Buffer * buf)
3541 SetUndo(buf, Undo::FINISH,
3543 cursor.par()->ParFromPos(cursor.pos())->previous,
3544 cursor.par()->ParFromPos(cursor.pos())->next
3546 cursor.par()->previous,
3553 void LyXText::toggleAppendix(BufferView * bview)
3556 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3558 LyXParagraph * par = cursor.par();
3560 bool start = !par->start_of_appendix;
3562 // ensure that we have only one start_of_appendix in this document
3563 LyXParagraph * tmp = FirstParagraph();
3564 for (; tmp; tmp = tmp->next)
3565 tmp->start_of_appendix = 0;
3566 par->start_of_appendix = start;
3568 // we can set the refreshing parameters now
3569 status = LyXText::NEED_MORE_REFRESH;
3571 refresh_row = 0; // not needed for full update
3572 UpdateCounters(bview, 0);
3573 SetCursor(bview, cursor.par(), cursor.pos());
3577 LyXParagraph * LyXText::OwnerParagraph() const
3580 return inset_owner->par;
3582 return bv_owner->buffer()->paragraph;
3586 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3589 inset_owner->par = p;
3591 bv_owner->buffer()->paragraph = p;