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)
1618 char alphaCounter(int n)
1620 if (n < 1 || n > 26)
1627 char hebrewCounter(int n)
1629 static const char hebrew[22] = {
1630 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1631 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1632 '÷', 'ø', 'ù', 'ú'
1634 if (n < 1 || n > 22)
1642 string const romanCounter(int n)
1644 static char const * roman[20] = {
1645 "i", "ii", "iii", "iv", "v",
1646 "vi", "vii", "viii", "ix", "x",
1647 "xi", "xii", "xiii", "xiv", "xv",
1648 "xvi", "xvii", "xviii", "xix", "xx"
1650 if (n < 1 || n > 20)
1657 // set the counter of a paragraph. This includes the labels
1658 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1661 // this is only relevant for the beginning of paragraph
1662 par = par->FirstPhysicalPar();
1664 LyXLayout const & layout =
1665 textclasslist.Style(buf->params.textclass,
1668 LyXTextClass const & textclass =
1669 textclasslist.TextClass(buf->params.textclass);
1671 /* copy the prev-counters to this one, unless this is the start of a
1672 footnote or of a bibliography or the very first paragraph */
1675 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1676 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1677 && par->footnotekind == LyXParagraph::FOOTNOTE)
1679 && !(textclasslist.Style(buf->params.textclass,
1680 par->Previous()->GetLayout()
1681 ).labeltype != LABEL_BIBLIO
1682 && layout.labeltype == LABEL_BIBLIO)) {
1683 for (int i = 0; i < 10; ++i) {
1684 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1687 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1689 par->appendix = par->Previous()->appendix;
1691 if (!par->appendix && par->start_of_appendix){
1692 par->appendix = true;
1693 for (int i = 0; i < 10; ++i) {
1694 par->setCounter(i, 0);
1698 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1699 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1701 par->enumdepth = par->Previous()->enumdepth;
1702 par->itemdepth = par->Previous()->itemdepth;
1705 for (int i = 0; i < 10; ++i) {
1706 par->setCounter(i, 0);
1708 par->appendix = par->start_of_appendix;
1714 // if this is an open marginnote and this is the first
1715 // entry in the marginnote and the enclosing
1716 // environment is an enum/item then correct for the
1717 // LaTeX behaviour (ARRae)
1718 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1719 && par->footnotekind == LyXParagraph::MARGIN
1721 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1722 && (par->PreviousBeforeFootnote()
1723 && textclasslist.Style(buf->params.textclass,
1724 par->PreviousBeforeFootnote()->GetLayout()
1725 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1726 // Any itemize or enumerate environment in a marginnote
1727 // that is embedded in an itemize or enumerate
1728 // paragraph is seen by LaTeX as being at a deeper
1729 // level within that enclosing itemization/enumeration
1730 // even if there is a "standard" layout at the start of
1736 /* Maybe we have to increment the enumeration depth.
1737 * BUT, enumeration in a footnote is considered in isolation from its
1738 * surrounding paragraph so don't increment if this is the
1739 * first line of the footnote
1740 * AND, bibliographies can't have their depth changed ie. they
1741 * are always of depth 0
1744 && par->Previous()->GetDepth() < par->GetDepth()
1745 && textclasslist.Style(buf->params.textclass,
1746 par->Previous()->GetLayout()
1747 ).labeltype == LABEL_COUNTER_ENUMI
1748 && par->enumdepth < 3
1750 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1751 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1752 && par->footnotekind == LyXParagraph::FOOTNOTE)
1754 && layout.labeltype != LABEL_BIBLIO) {
1758 /* Maybe we have to decrement the enumeration depth, see note above */
1760 && par->Previous()->GetDepth() > par->GetDepth()
1762 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1763 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1764 && par->footnotekind == LyXParagraph::FOOTNOTE)
1766 && layout.labeltype != LABEL_BIBLIO) {
1767 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1768 par->setCounter(6 + par->enumdepth,
1769 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1770 /* reset the counters.
1771 * A depth change is like a breaking layout
1773 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1774 par->setCounter(i, 0);
1777 if (!par->labelstring.empty()) {
1778 par->labelstring.erase();
1781 if (layout.margintype == MARGIN_MANUAL) {
1782 if (par->labelwidthstring.empty()) {
1783 par->SetLabelWidthString(layout.labelstring());
1786 par->SetLabelWidthString(string());
1789 /* is it a layout that has an automatic label ? */
1790 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1792 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1793 if (i >= 0 && i<= buf->params.secnumdepth) {
1794 par->incCounter(i); // increment the counter
1796 // Is there a label? Useful for Chapter layout
1797 if (!par->appendix){
1798 if (!layout.labelstring().empty())
1799 par->labelstring = layout.labelstring();
1801 par->labelstring.erase();
1803 if (!layout.labelstring_appendix().empty())
1804 par->labelstring = layout.labelstring_appendix();
1806 par->labelstring.erase();
1809 std::ostringstream s;
1811 if (!par->appendix) {
1812 switch (2 * LABEL_COUNTER_CHAPTER -
1813 textclass.maxcounter() + i) {
1814 case LABEL_COUNTER_CHAPTER:
1815 s << par->getCounter(i);
1817 case LABEL_COUNTER_SECTION:
1818 s << par->getCounter(i - 1) << '.'
1819 << par->getCounter(i);
1821 case LABEL_COUNTER_SUBSECTION:
1822 s << par->getCounter(i - 2) << '.'
1823 << par->getCounter(i - 1) << '.'
1824 << par->getCounter(i);
1826 case LABEL_COUNTER_SUBSUBSECTION:
1827 s << par->getCounter(i - 3) << '.'
1828 << par->getCounter(i - 2) << '.'
1829 << par->getCounter(i - 1) << '.'
1830 << par->getCounter(i);
1833 case LABEL_COUNTER_PARAGRAPH:
1834 s << par->getCounter(i - 4) << '.'
1835 << par->getCounter(i - 3) << '.'
1836 << par->getCounter(i - 2) << '.'
1837 << par->getCounter(i - 1) << '.'
1838 << par->getCounter(i);
1840 case LABEL_COUNTER_SUBPARAGRAPH:
1841 s << par->getCounter(i - 5) << '.'
1842 << par->getCounter(i - 4) << '.'
1843 << par->getCounter(i - 3) << '.'
1844 << par->getCounter(i - 2) << '.'
1845 << par->getCounter(i - 1) << '.'
1846 << par->getCounter(i);
1850 // Can this ever be reached? And in the
1851 // case it is, how can this be correct?
1853 s << par->getCounter(i) << '.';
1856 } else { // appendix
1857 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1858 case LABEL_COUNTER_CHAPTER:
1859 if (par->isRightToLeftPar(buf->params))
1860 s << hebrewCounter(par->getCounter(i));
1862 s << alphaCounter(par->getCounter(i));
1864 case LABEL_COUNTER_SECTION:
1865 if (par->isRightToLeftPar(buf->params))
1866 s << hebrewCounter(par->getCounter(i - 1));
1868 s << alphaCounter(par->getCounter(i - 1));
1871 << par->getCounter(i);
1874 case LABEL_COUNTER_SUBSECTION:
1875 if (par->isRightToLeftPar(buf->params))
1876 s << hebrewCounter(par->getCounter(i - 2));
1878 s << alphaCounter(par->getCounter(i - 2));
1881 << par->getCounter(i-1) << '.'
1882 << par->getCounter(i);
1885 case LABEL_COUNTER_SUBSUBSECTION:
1886 if (par->isRightToLeftPar(buf->params))
1887 s << hebrewCounter(par->getCounter(i-3));
1889 s << alphaCounter(par->getCounter(i-3));
1892 << par->getCounter(i-2) << '.'
1893 << par->getCounter(i-1) << '.'
1894 << par->getCounter(i);
1897 case LABEL_COUNTER_PARAGRAPH:
1898 if (par->isRightToLeftPar(buf->params))
1899 s << hebrewCounter(par->getCounter(i-4));
1901 s << alphaCounter(par->getCounter(i-4));
1904 << par->getCounter(i-3) << '.'
1905 << par->getCounter(i-2) << '.'
1906 << par->getCounter(i-1) << '.'
1907 << par->getCounter(i);
1910 case LABEL_COUNTER_SUBPARAGRAPH:
1911 if (par->isRightToLeftPar(buf->params))
1912 s << hebrewCounter(par->getCounter(i-5));
1914 s << alphaCounter(par->getCounter(i-5));
1917 << par->getCounter(i-4) << '.'
1918 << par->getCounter(i-3) << '.'
1919 << par->getCounter(i-2) << '.'
1920 << par->getCounter(i-1) << '.'
1921 << par->getCounter(i);
1925 // Can this ever be reached? And in the
1926 // case it is, how can this be correct?
1928 s << par->getCounter(i) << '.';
1934 par->labelstring += s.str().c_str();
1935 // We really want to remove the c_str as soon as
1938 for (i++; i < 10; ++i) {
1939 // reset the following counters
1940 par->setCounter(i, 0);
1942 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1943 for (i++; i < 10; ++i) {
1944 // reset the following counters
1945 par->setCounter(i, 0);
1947 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1948 par->incCounter(i + par->enumdepth);
1949 int number = par->getCounter(i + par->enumdepth);
1951 std::ostringstream s;
1953 switch (par->enumdepth) {
1955 if (par->isRightToLeftPar(buf->params))
1957 << hebrewCounter(number)
1961 << loweralphaCounter(number)
1965 if (par->isRightToLeftPar(buf->params))
1966 s << '.' << romanCounter(number);
1968 s << romanCounter(number) << '.';
1971 if (par->isRightToLeftPar(buf->params))
1973 << alphaCounter(number);
1975 s << alphaCounter(number)
1979 if (par->isRightToLeftPar(buf->params))
1986 par->labelstring = s.str().c_str();
1987 // we really want to get rid of that c_str()
1989 for (i += par->enumdepth + 1; i < 10; ++i)
1990 par->setCounter(i, 0); /* reset the following counters */
1993 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1994 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1996 int number = par->getCounter(i);
1998 InsetCommandParams p( "bibitem" );
1999 par->bibkey = new InsetBibKey(p);
2001 par->bibkey->setCounter(number);
2002 par->labelstring = layout.labelstring();
2004 // In biblio should't be following counters but...
2006 string s = layout.labelstring();
2008 // the caption hack:
2009 if (layout.labeltype == LABEL_SENSITIVE) {
2010 bool isOK (par->InInset() && par->InInset()->owner() &&
2011 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2013 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2014 && (par->footnotekind == LyXParagraph::FIG
2015 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2016 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2017 ? ":øåéà " : "Figure:";
2018 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2019 && (par->footnotekind == LyXParagraph::TAB
2020 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2021 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2022 ? ":äìáè" : "Table:";
2023 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2024 && par->footnotekind == LyXParagraph::ALGORITHM) {
2025 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2026 ? ":Ãúéøåâìà " : "Algorithm:";
2030 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2032 = floatList.getType(tmp->type());
2033 // We should get the correct number here too.
2034 s = fl.name + " #:";
2036 /* par->SetLayout(0);
2037 s = layout->labelstring; */
2038 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2039 ? " :úåòîùî øñç" : "Senseless: ";
2042 par->labelstring = s;
2044 /* reset the enumeration counter. They are always resetted
2045 * when there is any other layout between */
2046 for (int i = 6 + par->enumdepth; i < 10; ++i)
2047 par->setCounter(i, 0);
2052 /* Updates all counters BEHIND the row. Changed paragraphs
2053 * with a dynamic left margin will be rebroken. */
2054 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2061 if (row->par()->next
2063 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2067 par = row->par()->LastPhysicalPar()->Next();
2069 par = row->par()->Next();
2072 par = row->par()->next;
2077 while (row->par() != par)
2080 SetCounter(bview->buffer(), par);
2082 /* now check for the headline layouts. remember that they
2083 * have a dynamic left margin */
2088 ( textclasslist.Style(bview->buffer()->params.textclass,
2089 par->layout).margintype == MARGIN_DYNAMIC
2090 || textclasslist.Style(bview->buffer()->params.textclass,
2091 par->layout).labeltype == LABEL_SENSITIVE)
2094 /* Rebreak the paragraph */
2095 RemoveParagraph(row);
2096 AppendParagraph(bview, row);
2099 /* think about the damned open footnotes! */
2100 while (par->Next() &&
2101 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2102 || par->Next()->IsDummy())){
2104 if (par->IsDummy()) {
2105 while (row->par() != par)
2107 RemoveParagraph(row);
2108 AppendParagraph(bview, row);
2114 par = par->LastPhysicalPar()->Next();
2123 /* insets an inset. */
2124 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2126 if (!cursor.par()->InsertInsetAllowed(inset))
2128 SetUndo(bview->buffer(), Undo::INSERT,
2130 cursor.par()->ParFromPos(cursor.pos())->previous,
2131 cursor.par()->ParFromPos(cursor.pos())->next
2133 cursor.par()->previous,
2137 cursor.par()->InsertInset(cursor.pos(), inset);
2138 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2139 * The character will not be inserted a
2144 void LyXText::copyEnvironmentType()
2146 copylayouttype = cursor.par()->GetLayout();
2150 void LyXText::pasteEnvironmentType(BufferView * bview)
2152 SetLayout(bview, copylayouttype);
2156 void LyXText::CutSelection(BufferView * bview, bool doclear)
2158 // Stuff what we got on the clipboard. Even if there is no selection.
2160 // There is a problem with having the stuffing here in that the
2161 // larger the selection the slower LyX will get. This can be
2162 // solved by running the line below only when the selection has
2163 // finished. The solution used currently just works, to make it
2164 // faster we need to be more clever and probably also have more
2165 // calls to stuffClipboard. (Lgb)
2166 bview->stuffClipboard(selectionAsString(bview->buffer()));
2168 // This doesn't make sense, if there is no selection
2172 // OK, we have a selection. This is always between sel_start_cursor
2173 // and sel_end cursor
2175 // Check whether there are half footnotes in the selection
2176 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2177 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2178 LyXParagraph * tmppar = sel_start_cursor.par();
2179 while (tmppar != sel_end_cursor.par()){
2180 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2181 WriteAlert(_("Impossible operation"),
2182 _("Don't know what to do with half floats."),
2186 tmppar = tmppar->Next();
2191 // make sure that the depth behind the selection are restored, too
2193 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2195 LyXParagraph * endpar = sel_end_cursor.par()->Next();
2197 LyXParagraph * undoendpar = endpar;
2199 if (endpar && endpar->GetDepth()) {
2200 while (endpar && endpar->GetDepth()) {
2202 endpar = endpar->LastPhysicalPar()->Next();
2204 endpar = endpar->Next();
2206 undoendpar = endpar;
2208 } else if (endpar) {
2209 endpar = endpar->Next(); // because of parindents etc.
2212 SetUndo(bview->buffer(), Undo::DELETE,
2215 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2217 sel_start_cursor.par()->previous,
2223 // there are two cases: cut only within one paragraph or
2224 // more than one paragraph
2226 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2227 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2229 if (sel_start_cursor.par() == sel_end_cursor.par())
2232 // only within one paragraph
2233 endpar = sel_start_cursor.par();
2234 int pos = sel_end_cursor.pos();
2235 cap.cutSelection(sel_start_cursor.par(), &endpar,
2236 sel_start_cursor.pos(), pos,
2237 bview->buffer()->params.textclass, doclear);
2238 sel_end_cursor.pos(pos);
2240 endpar = sel_end_cursor.par();
2242 int pos = sel_end_cursor.pos();
2243 cap.cutSelection(sel_start_cursor.par(), &endpar,
2244 sel_start_cursor.pos(), pos,
2245 bview->buffer()->params.textclass, doclear);
2247 sel_end_cursor.par(endpar);
2248 sel_end_cursor.pos(pos);
2249 cursor.pos(sel_end_cursor.pos());
2251 endpar = endpar->Next();
2253 // sometimes necessary
2255 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2257 RedoParagraphs(bview, sel_start_cursor, endpar);
2260 cursor = sel_start_cursor;
2261 SetCursor(bview, cursor.par(), cursor.pos());
2262 sel_cursor = cursor;
2263 UpdateCounters(bview, cursor.row());
2267 void LyXText::CopySelection(BufferView * bview)
2269 // Stuff what we got on the clipboard. Even if there is no selection.
2271 // There is a problem with having the stuffing here in that the
2272 // larger the selection the slower LyX will get. This can be
2273 // solved by running the line below only when the selection has
2274 // finished. The solution used currently just works, to make it
2275 // faster we need to be more clever and probably also have more
2276 // calls to stuffClipboard. (Lgb)
2277 bview->stuffClipboard(selectionAsString(bview->buffer()));
2279 // this doesnt make sense, if there is no selection
2283 // ok we have a selection. This is always between sel_start_cursor
2284 // and sel_end cursor
2287 /* check wether there are half footnotes in the selection */
2288 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2289 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2290 LyXParagraph * tmppar = sel_start_cursor.par();
2291 while (tmppar != sel_end_cursor.par()) {
2292 if (tmppar->footnoteflag !=
2293 sel_end_cursor.par()->footnoteflag) {
2294 WriteAlert(_("Impossible operation"),
2295 _("Don't know what to do"
2296 " with half floats."),
2300 tmppar = tmppar->Next();
2305 // copy behind a space if there is one
2306 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2307 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2308 && (sel_start_cursor.par() != sel_end_cursor.par()
2309 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2310 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2314 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2315 sel_start_cursor.pos(), sel_end_cursor.pos(),
2316 bview->buffer()->params.textclass);
2320 void LyXText::PasteSelection(BufferView * bview)
2324 // this does not make sense, if there is nothing to paste
2325 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2328 SetUndo(bview->buffer(), Undo::INSERT,
2330 cursor.par()->ParFromPos(cursor.pos())->previous,
2331 cursor.par()->ParFromPos(cursor.pos())->next
2333 cursor.par()->previous,
2338 LyXParagraph * endpar;
2339 LyXParagraph * actpar = cursor.par();
2341 int pos = cursor.pos();
2342 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2344 RedoParagraphs(bview, cursor, endpar);
2346 SetCursor(bview, cursor.par(), cursor.pos());
2349 sel_cursor = cursor;
2350 SetCursor(bview, actpar, pos);
2352 UpdateCounters(bview, cursor.row());
2356 // returns a pointer to the very first LyXParagraph
2357 LyXParagraph * LyXText::FirstParagraph() const
2359 return OwnerParagraph();
2363 // returns true if the specified string is at the specified position
2364 bool LyXText::IsStringInText(LyXParagraph * par,
2365 LyXParagraph::size_type pos,
2366 string const & str) const
2369 LyXParagraph::size_type i = 0;
2370 while (pos + i < par->Last() && i < str.length()&&
2371 str[i] == par->GetChar(pos + i)) {
2374 if (str.length() == i)
2381 // sets the selection over the number of characters of string, no check!!
2382 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2384 sel_cursor = cursor;
2385 for (int i = 0; str[i]; ++i)
2391 // simple replacing. The font of the first selected character is used
2392 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2395 SetCursorParUndo(bview->buffer());
2398 if (!selection) { // create a dummy selection
2399 sel_end_cursor = cursor;
2400 sel_start_cursor = cursor;
2403 // Get font setting before we cut
2404 LyXParagraph::size_type pos = sel_end_cursor.pos();
2405 LyXFont const font = sel_start_cursor.par()
2406 ->GetFontSettings(bview->buffer()->params,
2407 sel_start_cursor.pos());
2409 // Insert the new string
2410 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2411 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2415 // Cut the selection
2416 CutSelection(bview);
2422 // if the string can be found: return true and set the cursor to
2424 bool LyXText::SearchForward(BufferView * bview, string const & str) const
2426 LyXParagraph * par = cursor.par();
2427 LyXParagraph::size_type pos = cursor.pos();
2428 while (par && !IsStringInText(par, pos, str)) {
2429 if (pos < par->Last() - 1)
2437 SetCursor(bview, par, pos);
2445 bool LyXText::SearchBackward(BufferView * bview, string const & str) const
2447 LyXParagraph * par = cursor.par();
2448 int pos = cursor.pos();
2454 // We skip empty paragraphs (Asger)
2456 par = par->Previous();
2458 pos = par->Last() - 1;
2459 } while (par && pos < 0);
2461 } while (par && !IsStringInText(par, pos, str));
2464 SetCursor(bview, par, pos);
2471 // needed to insert the selection
2472 void LyXText::InsertStringA(BufferView * bview, string const & str)
2474 LyXParagraph * par = cursor.par();
2475 LyXParagraph::size_type pos = cursor.pos();
2476 LyXParagraph::size_type a = 0;
2477 LyXParagraph * endpar = cursor.par()->Next();
2479 SetCursorParUndo(bview->buffer());
2482 textclasslist.Style(bview->buffer()->params.textclass,
2483 cursor.par()->GetLayout()).isEnvironment();
2484 // only to be sure, should not be neccessary
2487 // insert the string, don't insert doublespace
2488 string::size_type i = 0;
2489 while (i < str.length()) {
2490 if (str[i] != '\n') {
2492 && i + 1 < str.length() && str[i + 1] != ' '
2493 && pos && par->GetChar(pos - 1)!= ' ') {
2494 par->InsertChar(pos, ' ', current_font);
2496 } else if (str[i] == ' ') {
2497 InsetSpecialChar * new_inset =
2498 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2499 if (par->InsertInsetAllowed(new_inset)) {
2500 par->InsertInset(pos, new_inset,
2506 } else if (str[i] == '\t') {
2507 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2508 InsetSpecialChar * new_inset =
2509 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2510 if (par->InsertInsetAllowed(new_inset)) {
2511 par->InsertInset(pos, new_inset,
2518 } else if (str[i] != 13 &&
2519 // Ignore unprintables
2520 (str[i] & 127) >= ' ') {
2521 par->InsertChar(pos, str[i], current_font);
2525 if (!par->size()) { // par is empty
2526 InsetSpecialChar * new_inset =
2527 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2528 if (par->InsertInsetAllowed(new_inset)) {
2529 par->InsertInset(pos,
2537 par->BreakParagraph(bview->buffer()->params, pos, flag);
2544 RedoParagraphs(bview, cursor, endpar);
2545 SetCursor(bview, cursor.par(), cursor.pos());
2546 sel_cursor = cursor;
2547 SetCursor(bview, par, pos);
2552 /* turns double-CR to single CR, others where converted into one blank and 13s
2553 * that are ignored .Double spaces are also converted into one. Spaces at
2554 * the beginning of a paragraph are forbidden. tabs are converted into one
2555 * space. then InsertStringA is called */
2556 void LyXText::InsertStringB(BufferView * bview, string const & s)
2559 string::size_type i = 1;
2560 while (i < str.length()) {
2563 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2565 if (str[i] == '\n' && i + 1 < str.length()) {
2566 if (str[i + 1] != '\n') {
2567 if (str[i - 1] != ' ')
2572 while (i + 1 < str.length()
2573 && (str[i + 1] == ' '
2574 || str[i + 1] == '\t'
2575 || str[i + 1] == '\n'
2576 || str[i + 1] == 13)) {
2583 InsertStringA(bview, str);
2587 bool LyXText::GotoNextError(BufferView * bview) const
2589 LyXCursor res = cursor;
2591 if (res.pos() < res.par()->Last() - 1) {
2592 res.pos(res.pos() + 1);
2594 res.par(res.par()->Next());
2598 } while (res.par() &&
2599 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2600 && res.par()->GetInset(res.pos())->AutoDelete()));
2603 SetCursor(bview, res.par(), res.pos());
2610 bool LyXText::GotoNextNote(BufferView * bview) const
2612 LyXCursor res = cursor;
2614 if (res.pos() < res.par()->Last() - 1) {
2615 res.pos(res.pos() + 1);
2617 res.par(res.par()->Next());
2621 } while (res.par() &&
2622 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2623 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2626 SetCursor(bview, res.par(), res.pos());
2633 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2634 LyXParagraph::size_type pos)
2636 LyXCursor tmpcursor;
2639 LyXParagraph::size_type z;
2640 Row * row = GetRow(par, pos, y);
2642 // is there a break one row above
2643 if (row->previous() && row->previous()->par() == row->par()) {
2644 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2645 if ( z >= row->pos()) {
2646 // set the dimensions of the row above
2647 y -= row->previous()->height();
2649 refresh_row = row->previous();
2650 status = LyXText::NEED_MORE_REFRESH;
2652 BreakAgain(bview, row->previous());
2654 // set the cursor again. Otherwise
2655 // dangling pointers are possible
2656 SetCursor(bview, cursor.par(), cursor.pos());
2657 sel_cursor = cursor;
2662 int const tmpheight = row->height();
2663 LyXParagraph::size_type const tmplast = RowLast(row);
2667 BreakAgain(bview, row);
2668 if (row->height() == tmpheight && RowLast(row) == tmplast)
2669 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2671 status = LyXText::NEED_MORE_REFRESH;
2673 // check the special right address boxes
2674 if (textclasslist.Style(bview->buffer()->params.textclass,
2675 par->GetLayout()).margintype
2676 == MARGIN_RIGHT_ADDRESS_BOX) {
2683 RedoDrawingOfParagraph(bview, tmpcursor);
2686 // set the cursor again. Otherwise dangling pointers are possible
2687 // also set the selection
2691 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2692 sel_cursor = cursor;
2693 SetCursorIntern(bview, sel_start_cursor.par(),
2694 sel_start_cursor.pos());
2695 sel_start_cursor = cursor;
2696 SetCursorIntern(bview, sel_end_cursor.par(),
2697 sel_end_cursor.pos());
2698 sel_end_cursor = cursor;
2699 SetCursorIntern(bview, last_sel_cursor.par(),
2700 last_sel_cursor.pos());
2701 last_sel_cursor = cursor;
2704 SetCursorIntern(bview, cursor.par(), cursor.pos());
2708 // returns false if inset wasn't found
2709 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2711 // first check the current paragraph
2712 int pos = cursor.par()->GetPositionOfInset(inset);
2714 CheckParagraph(bview, cursor.par(), pos);
2718 // check every paragraph
2720 LyXParagraph * par = FirstParagraph();
2723 // make sure the paragraph is open
2724 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2726 pos = par->GetPositionOfInset(inset);
2728 CheckParagraph(bview, par, pos);
2741 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2742 LyXParagraph::size_type pos,
2743 bool setfont, bool boundary) const
2745 LyXCursor old_cursor = cursor;
2746 SetCursorIntern(bview, par, pos, setfont, boundary);
2747 DeleteEmptyParagraphMechanism(bview, old_cursor);
2751 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2752 LyXParagraph::size_type pos, bool boundary) const
2755 // correct the cursor position if impossible
2756 if (pos > par->Last()){
2757 LyXParagraph * tmppar = par->ParFromPos(pos);
2758 pos = par->PositionInParFromPos(pos);
2761 if (par->IsDummy() && par->previous &&
2762 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2763 while (par->previous &&
2764 ((par->previous->IsDummy() &&
2765 (par->previous->previous->footnoteflag ==
2766 LyXParagraph::CLOSED_FOOTNOTE)) ||
2767 (par->previous->footnoteflag ==
2768 LyXParagraph::CLOSED_FOOTNOTE))) {
2769 par = par->previous ;
2770 if (par->IsDummy() &&
2771 (par->previous->footnoteflag ==
2772 LyXParagraph::CLOSED_FOOTNOTE))
2773 pos += par->size() + 1;
2775 if (par->previous) {
2776 par = par->previous;
2778 pos += par->size() + 1;
2783 cur.boundary(boundary);
2785 /* get the cursor y position in text */
2787 Row * row = GetRow(par, pos, y);
2788 /* y is now the beginning of the cursor row */
2789 y += row->baseline();
2790 /* y is now the cursor baseline */
2793 /* now get the cursors x position */
2795 float fill_separator, fill_hfill, fill_label_hfill;
2796 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2798 LyXParagraph::size_type cursor_vpos = 0;
2799 LyXParagraph::size_type last = RowLastPrintable(row);
2801 if (pos > last + 1) // This shouldn't happen.
2803 else if (pos < row->pos())
2806 if (last < row->pos())
2807 cursor_vpos = row->pos();
2808 else if (pos > last && !boundary)
2809 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2810 ? row->pos() : last + 1;
2811 else if (pos > row->pos() &&
2812 (pos > last || boundary))
2813 /// Place cursor after char at (logical) position pos - 1
2814 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2815 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2817 /// Place cursor before char at (logical) position pos
2818 cursor_vpos = (bidi_level(pos) % 2 == 0)
2819 ? log2vis(pos) : log2vis(pos) + 1;
2821 LyXParagraph::size_type main_body =
2822 BeginningOfMainBody(bview->buffer(), row->par());
2823 if ((main_body > 0) &&
2824 ((main_body-1 > last) ||
2825 !row->par()->IsLineSeparator(main_body-1)))
2828 for (LyXParagraph::size_type vpos = row->pos();
2829 vpos < cursor_vpos; ++vpos) {
2830 pos = vis2log(vpos);
2831 if (main_body > 0 && pos == main_body - 1) {
2832 x += fill_label_hfill +
2833 lyxfont::width(textclasslist.Style(
2834 bview->buffer()->params.textclass,
2835 row->par()->GetLayout())
2837 GetFont(bview->buffer(), row->par(), -2));
2838 if (row->par()->IsLineSeparator(main_body-1))
2839 x -= SingleWidth(bview, row->par(),main_body-1);
2841 if (HfillExpansion(bview->buffer(), row, pos)) {
2842 x += SingleWidth(bview, row->par(), pos);
2843 if (pos >= main_body)
2846 x += fill_label_hfill;
2847 } else if (row->par()->IsSeparator(pos)) {
2848 x += SingleWidth(bview, row->par(), pos);
2849 if (pos >= main_body)
2850 x += fill_separator;
2852 x += SingleWidth(bview, row->par(), pos);
2861 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2862 LyXParagraph::size_type pos,
2863 bool setfont, bool boundary) const
2865 SetCursor(bview, cursor, par, pos, boundary);
2867 SetCurrentFont(bview);
2871 void LyXText::SetCurrentFont(BufferView * bview) const
2873 LyXParagraph::size_type pos = cursor.pos();
2874 if (cursor.boundary() && pos > 0)
2878 if (pos == cursor.par()->Last())
2880 else if (cursor.par()->IsSeparator(pos)) {
2881 if (pos > cursor.row()->pos() &&
2882 bidi_level(pos) % 2 ==
2883 bidi_level(pos - 1) % 2)
2885 else if (pos + 1 < cursor.par()->Last())
2891 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2892 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2894 if (cursor.pos() == cursor.par()->Last() &&
2895 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2896 !cursor.boundary()) {
2897 Language const * lang =
2898 cursor.par()->getParLanguage(bview->buffer()->params);
2899 current_font.setLanguage(lang);
2900 real_current_font.setLanguage(lang);
2905 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
2907 LyXCursor old_cursor = cursor;
2909 /* get the row first */
2911 Row * row = GetRowNearY(y);
2912 cursor.par(row->par());
2915 int column = GetColumnNearX(bview, row, x, bound);
2916 cursor.pos(row->pos() + column);
2918 cursor.y(y + row->baseline());
2920 cursor.boundary(bound);
2921 SetCurrentFont(bview);
2922 DeleteEmptyParagraphMechanism(bview, old_cursor);
2926 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2927 int x, long y) const
2929 /* get the row first */
2931 Row * row = GetRowNearY(y);
2933 int column = GetColumnNearX(bview, row, x, bound);
2935 cur.par(row->par());
2936 cur.pos(row->pos() + column);
2938 cur.y(y + row->baseline());
2940 cur.boundary(bound);
2944 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2946 CursorLeftIntern(bview, internal);
2950 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
2952 if (cursor.pos() > 0) {
2953 bool boundary = cursor.boundary();
2954 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2955 if (!internal && !boundary &&
2956 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2957 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2958 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2959 LyXParagraph * par = cursor.par()->Previous();
2960 SetCursor(bview, par, par->Last());
2965 void LyXText::CursorRight(BufferView * bview, bool internal) const
2967 CursorRightIntern(bview, internal);
2971 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
2973 if (!internal && cursor.boundary() &&
2974 !cursor.par()->IsNewline(cursor.pos()))
2975 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2976 else if (cursor.pos() < cursor.par()->Last()) {
2977 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2979 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2980 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2981 } else if (cursor.par()->Next())
2982 SetCursor(bview, cursor.par()->Next(), 0);
2986 void LyXText::CursorUp(BufferView * bview) const
2988 SetCursorFromCoordinates(bview, cursor.x_fix(),
2989 cursor.y() - cursor.row()->baseline() - 1);
2993 void LyXText::CursorDown(BufferView * bview) const
2995 SetCursorFromCoordinates(bview, cursor.x_fix(),
2996 cursor.y() - cursor.row()->baseline()
2997 + cursor.row()->height() + 1);
3001 void LyXText::CursorUpParagraph(BufferView * bview) const
3003 if (cursor.pos() > 0) {
3004 SetCursor(bview, cursor.par(), 0);
3006 else if (cursor.par()->Previous()) {
3007 SetCursor(bview, cursor.par()->Previous(), 0);
3012 void LyXText::CursorDownParagraph(BufferView * bview) const
3014 if (cursor.par()->Next()) {
3015 SetCursor(bview, cursor.par()->Next(), 0);
3017 SetCursor(bview, cursor.par(), cursor.par()->Last());
3022 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3023 LyXCursor const & old_cursor) const
3025 // Would be wrong to delete anything if we have a selection.
3026 if (selection) return;
3028 // We allow all kinds of "mumbo-jumbo" when freespacing.
3029 if (textclasslist.Style(bview->buffer()->params.textclass,
3030 old_cursor.par()->GetLayout()).free_spacing)
3033 bool deleted = false;
3035 /* Ok I'll put some comments here about what is missing.
3036 I have fixed BackSpace (and thus Delete) to not delete
3037 double-spaces automagically. I have also changed Cut,
3038 Copy and Paste to hopefully do some sensible things.
3039 There are still some small problems that can lead to
3040 double spaces stored in the document file or space at
3041 the beginning of paragraphs. This happens if you have
3042 the cursor betwenn to spaces and then save. Or if you
3043 cut and paste and the selection have a space at the
3044 beginning and then save right after the paste. I am
3045 sure none of these are very hard to fix, but I will
3046 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3047 that I can get some feedback. (Lgb)
3050 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3051 // delete the LineSeparator.
3054 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3055 // delete the LineSeparator.
3058 // If the pos around the old_cursor were spaces, delete one of them.
3059 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3060 // Only if the cursor has really moved
3062 if (old_cursor.pos() > 0
3063 && old_cursor.pos() < old_cursor.par()->Last()
3064 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3065 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3066 old_cursor.par()->Erase(old_cursor.pos() - 1);
3067 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3069 if (old_cursor.par() == cursor.par() &&
3070 cursor.pos() > old_cursor.pos()) {
3071 SetCursorIntern(bview, cursor.par(),
3074 SetCursorIntern(bview, cursor.par(),
3080 // Do not delete empty paragraphs with keepempty set.
3081 if ((textclasslist.Style(bview->buffer()->params.textclass,
3082 old_cursor.par()->GetLayout())).keepempty)
3085 LyXCursor tmpcursor;
3087 if (old_cursor.par() != cursor.par()) {
3088 if ( (old_cursor.par()->Last() == 0
3089 || (old_cursor.par()->Last() == 1
3090 && old_cursor.par()->IsLineSeparator(0)))
3092 && old_cursor.par()->FirstPhysicalPar()
3093 == old_cursor.par()->LastPhysicalPar()
3096 // ok, we will delete anything
3098 // make sure that you do not delete any environments
3101 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3102 !(old_cursor.row()->previous()
3103 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3104 && !(old_cursor.row()->next()
3105 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3106 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3107 && ((old_cursor.row()->previous()
3108 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3109 || (old_cursor.row()->next()
3110 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3113 status = LyXText::NEED_MORE_REFRESH;
3116 if (old_cursor.row()->previous()) {
3117 refresh_row = old_cursor.row()->previous();
3118 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3120 cursor = old_cursor; // that undo can restore the right cursor position
3121 LyXParagraph * endpar = old_cursor.par()->next;
3122 if (endpar && endpar->GetDepth()) {
3123 while (endpar && endpar->GetDepth()) {
3125 endpar = endpar->LastPhysicalPar()->Next();
3127 endpar = endpar->Next();
3131 SetUndo(bview->buffer(), Undo::DELETE,
3132 old_cursor.par()->previous,
3137 RemoveRow(old_cursor.row());
3138 if (OwnerParagraph() == old_cursor.par()) {
3139 OwnerParagraph(OwnerParagraph()->next);
3142 delete old_cursor.par();
3144 /* Breakagain the next par. Needed
3145 * because of the parindent that
3146 * can occur or dissappear. The
3147 * next row can change its height,
3148 * if there is another layout before */
3149 if (refresh_row->next()) {
3150 BreakAgain(bview, refresh_row->next());
3151 UpdateCounters(bview, refresh_row);
3153 SetHeightOfRow(bview, refresh_row);
3155 refresh_row = old_cursor.row()->next();
3156 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3159 cursor = old_cursor; // that undo can restore the right cursor position
3160 LyXParagraph * endpar = old_cursor.par()->next;
3161 if (endpar && endpar->GetDepth()) {
3162 while (endpar && endpar->GetDepth()) {
3164 endpar = endpar->LastPhysicalPar()->Next();
3166 endpar = endpar->Next();
3170 SetUndo(bview->buffer(), Undo::DELETE,
3171 old_cursor.par()->previous,
3176 RemoveRow(old_cursor.row());
3178 if (OwnerParagraph() == old_cursor.par()) {
3179 OwnerParagraph(OwnerParagraph()->next);
3181 delete old_cursor.par();
3183 /* Breakagain the next par. Needed
3184 because of the parindent that can
3185 occur or dissappear.
3186 The next row can change its height,
3187 if there is another layout before
3190 BreakAgain(bview, refresh_row);
3191 UpdateCounters(bview, refresh_row->previous());
3197 SetCursorIntern(bview, cursor.par(), cursor.pos());
3199 if (sel_cursor.par() == old_cursor.par()
3200 && sel_cursor.pos() == sel_cursor.pos()) {
3201 // correct selection
3202 sel_cursor = cursor;
3209 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3210 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3212 SetCursorIntern(bview, cursor.par(), cursor.pos());
3213 sel_cursor = cursor;
3220 LyXParagraph * LyXText::GetParFromID(int id)
3222 LyXParagraph * result = FirstParagraph();
3223 while (result && result->id() != id)
3224 result = result->next;
3230 bool LyXText::TextUndo(BufferView * bview)
3234 // returns false if no undo possible
3235 Undo * undo = bview->buffer()->undostack.pop();
3239 bview->buffer()->redostack
3240 .push(CreateUndo(bview->buffer(), undo->kind,
3241 GetParFromID(undo->number_of_before_par),
3242 GetParFromID(undo->number_of_behind_par)));
3244 return TextHandleUndo(bview, undo);
3248 bool LyXText::TextRedo(BufferView * bview)
3252 // returns false if no redo possible
3253 Undo * undo = bview->buffer()->redostack.pop();
3257 bview->buffer()->undostack
3258 .push(CreateUndo(bview->buffer(), undo->kind,
3259 GetParFromID(undo->number_of_before_par),
3260 GetParFromID(undo->number_of_behind_par)));
3262 return TextHandleUndo(bview, undo);
3266 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3270 // returns false if no undo possible
3271 bool result = false;
3273 LyXParagraph * before =
3274 GetParFromID(undo->number_of_before_par);
3275 LyXParagraph * behind =
3276 GetParFromID(undo->number_of_behind_par);
3277 LyXParagraph * tmppar;
3278 LyXParagraph * tmppar2;
3279 LyXParagraph * endpar;
3280 LyXParagraph * tmppar5;
3282 // if there's no before take the beginning
3283 // of the document for redoing
3285 SetCursorIntern(bview, FirstParagraph(), 0);
3287 // replace the paragraphs with the undo informations
3289 LyXParagraph * tmppar3 = undo->par;
3290 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3291 LyXParagraph * tmppar4 = tmppar3;
3293 while (tmppar4->next)
3294 tmppar4 = tmppar4->next;
3295 } // get last undo par
3297 // now remove the old text if there is any
3298 if (before != behind || (!behind && !before)){
3300 tmppar5 = before->next;
3302 tmppar5 = OwnerParagraph();
3304 while (tmppar5 && tmppar5 != behind){
3306 tmppar5 = tmppar5->next;
3307 // a memory optimization for edit: Only layout information
3308 // is stored in the undo. So restore the text informations.
3309 if (undo->kind == Undo::EDIT) {
3310 tmppar2->setContentsFromPar(tmppar);
3311 tmppar->clearContents();
3312 tmppar2 = tmppar2->next;
3317 // put the new stuff in the list if there is one
3320 before->next = tmppar3;
3322 OwnerParagraph(tmppar3);
3323 tmppar3->previous = before;
3326 OwnerParagraph(behind);
3329 tmppar4->next = behind;
3331 behind->previous = tmppar4;
3335 // Set the cursor for redoing
3338 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3340 SetCursorIntern(bview, before, 0);
3343 // check wether before points to a closed float and open it if necessary
3344 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3345 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3347 while (tmppar4->previous &&
3348 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3349 tmppar4 = tmppar4->previous;
3350 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3351 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3352 tmppar4 = tmppar4->next;
3359 // open a cosed footnote at the end if necessary
3360 if (behind && behind->previous &&
3361 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3362 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3363 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3364 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3365 behind = behind->next;
3370 // calculate the endpar for redoing the paragraphs.
3373 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3374 endpar = behind->LastPhysicalPar()->Next();
3376 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3378 endpar = behind->Next();
3383 tmppar = GetParFromID(undo->number_of_cursor_par);
3384 RedoParagraphs(bview, cursor, endpar);
3386 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3387 UpdateCounters(bview, cursor.row());
3397 void LyXText::FinishUndo()
3401 // makes sure the next operation will be stored
3402 undo_finished = true;
3406 void LyXText::FreezeUndo()
3410 // this is dangerous and for internal use only
3415 void LyXText::UnFreezeUndo()
3419 // this is dangerous and for internal use only
3420 undo_frozen = false;
3424 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3425 LyXParagraph const * before,
3426 LyXParagraph const * behind) const
3431 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3432 buf->redostack.clear();
3436 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3437 LyXParagraph const * before, LyXParagraph const * behind)
3441 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3445 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3446 LyXParagraph const * before,
3447 LyXParagraph const * behind) const
3452 int before_number = -1;
3453 int behind_number = -1;
3455 before_number = before->id();
3457 behind_number = behind->id();
3458 // Undo::EDIT and Undo::FINISH are
3459 // always finished. (no overlapping there)
3460 // overlapping only with insert and delete inside one paragraph:
3461 // Nobody wants all removed character
3462 // appear one by one when undoing.
3463 // EDIT is special since only layout information, not the
3464 // contents of a paragaph are stored.
3465 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3466 // check wether storing is needed
3467 if (!buf->undostack.empty() &&
3468 buf->undostack.top()->kind == kind &&
3469 buf->undostack.top()->number_of_before_par == before_number &&
3470 buf->undostack.top()->number_of_behind_par == behind_number ){
3475 // create a new Undo
3476 LyXParagraph * undopar;
3477 LyXParagraph * tmppar;
3478 LyXParagraph * tmppar2;
3480 LyXParagraph * start = 0;
3481 LyXParagraph * end = 0;
3484 start = before->next;
3486 start = FirstParagraph();
3488 end = behind->previous;
3490 end = FirstParagraph();
3496 && start != end->next
3497 && (before != behind || (!before && !behind))) {
3499 tmppar2 = tmppar->Clone();
3500 tmppar2->id(tmppar->id());
3502 // a memory optimization: Just store the layout information
3504 if (kind == Undo::EDIT){
3505 //tmppar2->text.clear();
3506 tmppar2->clearContents();
3511 while (tmppar != end && tmppar->next) {
3512 tmppar = tmppar->next;
3513 tmppar2->next = tmppar->Clone();
3514 tmppar2->next->id(tmppar->id());
3515 // a memory optimization: Just store the layout
3516 // information when only edit
3517 if (kind == Undo::EDIT){
3518 //tmppar2->next->text.clear();
3519 tmppar2->clearContents();
3521 tmppar2->next->previous = tmppar2;
3522 tmppar2 = tmppar2->next;
3526 undopar = 0; // nothing to replace (undo of delete maybe)
3529 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3530 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3532 int cursor_par = cursor.par()->id();
3533 int cursor_pos = cursor.pos();
3536 Undo * undo = new Undo(kind,
3537 before_number, behind_number,
3538 cursor_par, cursor_pos,
3541 undo_finished = false;
3546 void LyXText::SetCursorParUndo(Buffer * buf)
3550 SetUndo(buf, Undo::FINISH,
3552 cursor.par()->ParFromPos(cursor.pos())->previous,
3553 cursor.par()->ParFromPos(cursor.pos())->next
3555 cursor.par()->previous,
3562 void LyXText::toggleAppendix(BufferView * bview)
3565 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3567 LyXParagraph * par = cursor.par();
3569 bool start = !par->start_of_appendix;
3571 // ensure that we have only one start_of_appendix in this document
3572 LyXParagraph * tmp = FirstParagraph();
3573 for (; tmp; tmp = tmp->next)
3574 tmp->start_of_appendix = 0;
3575 par->start_of_appendix = start;
3577 // we can set the refreshing parameters now
3578 status = LyXText::NEED_MORE_REFRESH;
3580 refresh_row = 0; // not needed for full update
3581 UpdateCounters(bview, 0);
3582 SetCursor(bview, cursor.par(), cursor.pos());
3586 LyXParagraph * LyXText::OwnerParagraph() const
3589 return inset_owner->par;
3591 return bv_owner->buffer()->paragraph;
3595 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3598 inset_owner->par = p;
3600 bv_owner->buffer()->paragraph = p;