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"
54 LyXText::LyXText(BufferView * bv)
62 LyXText::LyXText(InsetText * inset)
72 the_locking_inset = 0;
80 status = LyXText::UNCHANGED;
81 // set cursor at the very top position
82 selection = true; /* these setting is necessary
83 because of the delete-empty-
84 paragraph mechanism in
87 LyXParagraph * par = OwnerParagraph();
88 current_font = GetFont(bv_owner->buffer(), par, 0);
90 InsertParagraph(bv_owner, par, lastrow);
93 SetCursor(bv_owner, firstrow->par(), 0);
95 current_font = LyXFont(LyXFont::ALL_SANE);
101 // no rebreak necessary
104 undo_finished = true;
107 // Default layouttype for copy environment type
111 // Dump all rowinformation:
112 Row * tmprow = firstrow;
113 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
115 lyxerr << tmprow->baseline() << '\t'
116 << tmprow->par << '\t'
117 << tmprow->pos() << '\t'
118 << tmprow->height << '\t'
119 << tmprow->ascent_of_text << '\t'
120 << tmprow->fill << '\n';
121 tmprow = tmprow->next();
128 void LyXText::init(BufferView * bview)
133 LyXParagraph * par = OwnerParagraph();
134 current_font = GetFont(bview->buffer(), par, 0);
136 InsertParagraph(bview, par, lastrow);
139 SetCursorIntern(bview, firstrow->par(), 0);
142 // Dump all rowinformation:
143 Row * tmprow = firstrow;
144 lyxerr << "Width = " << width << endl;
145 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
147 lyxerr << tmprow->baseline() << '\t'
148 << tmprow->par() << '\t'
149 << tmprow->pos() << '\t'
150 << tmprow->height() << '\t'
151 << tmprow->ascent_of_text() << '\t'
152 << tmprow->fill() << '\n';
153 tmprow = tmprow->next();
161 // Delete all rows, this does not touch the paragraphs!
162 Row * tmprow = firstrow;
164 tmprow = firstrow->next();
171 // Gets the fully instantiated font at a given position in a paragraph
172 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
173 // The difference is that this one is used for displaying, and thus we
174 // are allowed to make cosmetic improvements. For instance make footnotes
176 // If position is -1, we get the layout font of the paragraph.
177 // If position is -2, we get the font of the manual label of the paragraph.
178 LyXFont const LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
179 LyXParagraph::size_type pos) const
181 LyXLayout const & layout =
182 textclasslist.Style(buf->params.textclass, par->GetLayout());
184 char par_depth = par->GetDepth();
185 // We specialize the 95% common case:
188 par->footnoteflag == LyXParagraph::NO_FOOTNOTE &&
193 if (layout.labeltype == LABEL_MANUAL
194 && pos < BeginningOfMainBody(buf, par)) {
196 LyXFont f = par->GetFontSettings(buf->params,
198 return f.realize(layout.reslabelfont);
200 LyXFont f = par->GetFontSettings(buf->params, pos);
201 return f.realize(layout.resfont);
206 // process layoutfont for pos == -1 and labelfont for pos < -1
208 return layout.resfont;
210 return layout.reslabelfont;
214 // The uncommon case need not be optimized as much
216 LyXFont layoutfont, tmpfont;
220 if (pos < BeginningOfMainBody(buf, par)) {
222 layoutfont = layout.labelfont;
225 layoutfont = layout.font;
227 tmpfont = par->GetFontSettings(buf->params, pos);
228 tmpfont.realize(layoutfont);
231 // process layoutfont for pos == -1 and labelfont for pos < -1
233 tmpfont = layout.font;
235 tmpfont = layout.labelfont;
238 // Resolve against environment font information
239 while (par && par_depth && !tmpfont.resolved()) {
240 par = par->DepthHook(par_depth - 1);
242 tmpfont.realize(textclasslist.
243 Style(buf->params.textclass,
244 par->GetLayout()).font);
245 par_depth = par->GetDepth();
249 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
252 // Cosmetic improvement: If this is an open footnote, make the font
254 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
255 && par->footnotekind == LyXParagraph::FOOTNOTE) {
263 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
264 LyXParagraph::size_type pos,
268 // Let the insets convert their font
269 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
270 if (par->GetInset(pos))
271 font = par->GetInset(pos)->ConvertFont(font);
274 LyXLayout const & layout =
275 textclasslist.Style(buf->params.textclass,
278 // Get concrete layout font to reduce against
281 if (pos < BeginningOfMainBody(buf, par))
282 layoutfont = layout.labelfont;
284 layoutfont = layout.font;
286 // Realize against environment font information
287 if (par->GetDepth()){
288 LyXParagraph * tp = par;
289 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
290 tp = tp->DepthHook(tp->GetDepth()-1);
292 layoutfont.realize(textclasslist.
293 Style(buf->params.textclass,
294 tp->GetLayout()).font);
298 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
301 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
302 && par->footnotekind == LyXParagraph::FOOTNOTE) {
303 layoutfont.decSize();
306 // Now, reduce font against full layout font
307 font.reduce(layoutfont);
309 par->SetFont(pos, font);
313 /* inserts a new row behind the specified row, increments
314 * the touched counters */
315 void LyXText::InsertRow(Row * row, LyXParagraph * par,
316 LyXParagraph::size_type pos) const
318 Row * tmprow = new Row;
321 tmprow->next(firstrow);
324 tmprow->previous(row);
325 tmprow->next(row->next());
330 tmprow->next()->previous(tmprow);
332 if (tmprow->previous())
333 tmprow->previous()->next(tmprow);
341 ++number_of_rows; // one more row
345 // removes the row and reset the touched counters
346 void LyXText::RemoveRow(Row * row) const
348 /* this must not happen before the currentrow for clear reasons.
349 so the trick is just to set the current row onto the previous
352 GetRow(row->par(), row->pos(), unused_y);
355 row->next()->previous(row->previous());
356 if (!row->previous()) {
357 firstrow = row->next();
359 row->previous()->next(row->next());
362 lastrow = row->previous();
364 height -= row->height(); // the text becomes smaller
367 --number_of_rows; // one row less
371 // remove all following rows of the paragraph of the specified row.
372 void LyXText::RemoveParagraph(Row * row) const
374 LyXParagraph * tmppar = row->par();
378 while (row && row->par() == tmppar) {
379 tmprow = row->next();
386 // insert the specified paragraph behind the specified row
387 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
390 InsertRow(row, par, 0); /* insert a new row, starting
393 SetCounter(bview->buffer(), par); // set the counters
395 // and now append the whole paragraph behind the new row
398 AppendParagraph(bview, firstrow);
400 row->next()->height(0);
401 AppendParagraph(bview, row->next());
407 void LyXText::ToggleFootnote(BufferView * bview)
409 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
411 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
413 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
415 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
416 CloseFootnote(bview);
423 void LyXText::OpenStuff(BufferView * bview)
425 if (cursor.pos() == 0 && cursor.par()->bibkey){
426 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
427 } else if (cursor.pos() < cursor.par()->Last()
428 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
429 && cursor.par()->GetInset(cursor.pos())->Editable()) {
430 bview->owner()->getMiniBuffer()
431 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
432 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
433 SetCursorParUndo(bview->buffer());
434 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
438 ToggleFootnote(bview);
446 void LyXText::CloseFootnote(BufferView * bview)
448 LyXParagraph * tmppar;
449 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
451 // if the cursor is not in an open footnote, or
452 // there is no open footnote in this paragraph, just return.
453 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
456 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
457 bview->owner()->getMiniBuffer()
458 ->Set(_("Nothing to do"));
462 // ok, move the cursor right before the footnote
463 // just a little faster than using CursorRight()
465 cursor.par()->ParFromPos(cursor.pos()) != par;) {
466 cursor.pos(cursor.pos() + 1);
469 // now the cursor is at the beginning of the physical par
470 SetCursor(bview, cursor.par(),
472 cursor.par()->ParFromPos(cursor.pos())->size());
474 /* we are in a footnote, so let us move at the beginning */
475 /* this is just faster than using just CursorLeft() */
477 tmppar = cursor.par();
478 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
479 // just a little bit faster than movin the cursor
480 tmppar = tmppar->Previous();
482 SetCursor(bview, tmppar, tmppar->Last());
485 // the cursor must be exactly before the footnote
486 par = cursor.par()->ParFromPos(cursor.pos());
488 status = LyXText::NEED_MORE_REFRESH;
489 refresh_row = cursor.row();
490 refresh_y = cursor.y() - cursor.row()->baseline();
492 tmppar = cursor.par();
493 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
494 Row * row = cursor.row();
496 tmppar->CloseFootnote(cursor.pos());
498 while (tmppar != endpar) {
499 RemoveRow(row->next());
501 tmppar = row->next()->par();
506 AppendParagraph(bview, cursor.row());
508 SetCursor(bview, cursor.par(), cursor.pos());
512 if (cursor.row()->next())
513 SetHeightOfRow(bview, cursor.row()->next());
518 /* used in setlayout */
519 // Asger is not sure we want to do this...
520 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
524 LyXLayout const & layout =
525 textclasslist.Style(buf->params.textclass, par->GetLayout());
527 LyXFont layoutfont, tmpfont;
528 for (LyXParagraph::size_type pos = 0;
529 pos < par->Last(); ++pos) {
530 if (pos < BeginningOfMainBody(buf, par))
531 layoutfont = layout.labelfont;
533 layoutfont = layout.font;
535 tmpfont = par->GetFontSettings(buf->params, pos);
536 tmpfont.reduce(layoutfont);
537 par->SetFont(pos, tmpfont);
542 LyXParagraph * LyXText::SetLayout(BufferView * bview,
543 LyXCursor & cur, LyXCursor & sstart_cur,
544 LyXCursor & send_cur,
545 LyXTextClass::size_type layout)
548 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
550 LyXParagraph * endpar = send_cur.par()->Next();
552 LyXParagraph * undoendpar = endpar;
554 if (endpar && endpar->GetDepth()) {
555 while (endpar && endpar->GetDepth()) {
557 endpar = endpar->LastPhysicalPar()->Next();
559 endpar = endpar->Next();
564 endpar = endpar->Next(); // because of parindents etc.
567 SetUndo(bview->buffer(), Undo::EDIT,
569 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
571 sstart_cur.par()->previous,
575 /* ok we have a selection. This is always between sstart_cur
576 * and sel_end cursor */
579 LyXLayout const & lyxlayout =
580 textclasslist.Style(bview->buffer()->params.textclass, layout);
582 while (cur.par() != send_cur.par()) {
584 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
586 cur.par()->SetLayout(bview->buffer()->params, layout);
587 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
589 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
591 LyXParagraph * fppar = cur.par();
593 fppar->added_space_top = lyxlayout.fill_top ?
594 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
595 fppar->added_space_bottom = lyxlayout.fill_bottom ?
596 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
597 if (lyxlayout.margintype == MARGIN_MANUAL)
598 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
599 if (lyxlayout.labeltype != LABEL_BIBLIO
601 delete fppar->bibkey;
607 cur.par(cur.par()->Next());
610 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
612 cur.par()->SetLayout(bview->buffer()->params, layout);
613 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
615 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
617 LyXParagraph * fppar = cur.par();
619 fppar->added_space_top = lyxlayout.fill_top ?
620 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
621 fppar->added_space_bottom = lyxlayout.fill_bottom ?
622 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
623 if (lyxlayout.margintype == MARGIN_MANUAL)
624 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
625 if (lyxlayout.labeltype != LABEL_BIBLIO
627 delete fppar->bibkey;
636 // set layout over selection and make a total rebreak of those paragraphs
637 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
639 LyXCursor tmpcursor = cursor; /* store the current cursor */
641 // if there is no selection just set the layout
642 // of the current paragraph */
644 sel_start_cursor = cursor; // dummy selection
645 sel_end_cursor = cursor;
648 endpar = SetLayout(bview, cursor, sel_start_cursor,
649 sel_end_cursor, layout);
650 RedoParagraphs(bview, sel_start_cursor, endpar);
652 // we have to reset the selection, because the
653 // geometry could have changed
654 SetCursor(bview, sel_start_cursor.par(),
655 sel_start_cursor.pos(), false);
657 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
659 UpdateCounters(bview, cursor.row());
662 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
666 // increment depth over selection and
667 // make a total rebreak of those paragraphs
668 void LyXText::IncDepth(BufferView * bview)
670 // If there is no selection, just use the current paragraph
672 sel_start_cursor = cursor; // dummy selection
673 sel_end_cursor = cursor;
676 // We end at the next paragraph with depth 0
677 LyXParagraph * endpar =
679 sel_end_cursor.par()->LastPhysicalPar()->Next();
681 sel_end_cursor.par()->Next();
683 LyXParagraph * undoendpar = endpar;
685 if (endpar && endpar->GetDepth()) {
686 while (endpar && endpar->GetDepth()) {
688 endpar = endpar->LastPhysicalPar()->Next();
690 endpar = endpar->Next();
696 endpar = endpar->Next(); // because of parindents etc.
699 SetUndo(bview->buffer(), Undo::EDIT,
702 .par()->ParFromPos(sel_start_cursor.pos())->previous,
704 sel_start_cursor.par()->previous,
708 LyXCursor tmpcursor = cursor; // store the current cursor
710 // ok we have a selection. This is always between sel_start_cursor
711 // and sel_end cursor
712 cursor = sel_start_cursor;
714 bool anything_changed = false;
717 // NOTE: you can't change the depth of a bibliography entry
720 cursor.par()->footnoteflag ==
721 sel_start_cursor.par()->footnoteflag &&
723 textclasslist.Style(bview->buffer()->params.textclass,
724 cursor.par()->GetLayout()
725 ).labeltype != LABEL_BIBLIO) {
726 LyXParagraph * prev =
728 cursor.par()->FirstPhysicalPar()->Previous();
730 cursor.par()->Previous();
733 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
734 || (prev->GetDepth() == cursor.par()->GetDepth()
735 && textclasslist.Style(bview->buffer()->params.textclass,
736 prev->GetLayout()).isEnvironment()))) {
738 cursor.par()->FirstPhysicalPar()->depth++;
740 cursor.par()->depth++;
742 anything_changed = true;
745 if (cursor.par() == sel_end_cursor.par())
747 cursor.par(cursor.par()->Next());
750 // if nothing changed set all depth to 0
751 if (!anything_changed) {
752 cursor = sel_start_cursor;
753 while (cursor.par() != sel_end_cursor.par()) {
755 cursor.par()->FirstPhysicalPar()->depth = 0;
757 cursor.par()->depth = 0;
759 cursor.par(cursor.par()->Next());
762 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
763 cursor.par()->FirstPhysicalPar()->depth = 0;
765 cursor.par()->depth = 0;
769 RedoParagraphs(bview, sel_start_cursor, endpar);
771 // we have to reset the selection, because the
772 // geometry could have changed
773 SetCursor(bview, sel_start_cursor.par(),
774 sel_start_cursor.pos());
776 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
777 UpdateCounters(bview, cursor.row());
780 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
784 // decrement depth over selection and
785 // make a total rebreak of those paragraphs
786 void LyXText::DecDepth(BufferView * bview)
788 // if there is no selection just set the layout
789 // of the current paragraph
791 sel_start_cursor = cursor; // dummy selection
792 sel_end_cursor = cursor;
795 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
797 LyXParagraph * endpar = sel_end_cursor.par()->Next();
799 LyXParagraph * undoendpar = endpar;
801 if (endpar && endpar->GetDepth()) {
802 while (endpar && endpar->GetDepth()) {
804 endpar = endpar->LastPhysicalPar()->Next();
806 endpar = endpar->Next();
812 endpar = endpar->Next(); // because of parindents etc.
815 SetUndo(bview->buffer(), Undo::EDIT,
818 .par()->ParFromPos(sel_start_cursor.pos())->previous,
820 sel_start_cursor.par()->previous,
824 LyXCursor tmpcursor = cursor; // store the current cursor
826 // ok we have a selection. This is always between sel_start_cursor
827 // and sel_end cursor
828 cursor = sel_start_cursor;
832 if (cursor.par()->footnoteflag ==
833 sel_start_cursor.par()->footnoteflag) {
834 if (cursor.par()->FirstPhysicalPar()->depth)
835 cursor.par()->FirstPhysicalPar()->depth--;
838 if (cursor.par()->depth)
839 cursor.par()->depth--;
841 if (cursor.par() == sel_end_cursor.par())
843 cursor.par(cursor.par()->Next());
846 RedoParagraphs(bview, sel_start_cursor, endpar);
848 // we have to reset the selection, because the
849 // geometry could have changed
850 SetCursor(bview, sel_start_cursor.par(),
851 sel_start_cursor.pos());
853 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
854 UpdateCounters(bview, cursor.row());
857 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
861 // set font over selection and make a total rebreak of those paragraphs
862 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
864 // if there is no selection just set the current_font
866 // Determine basis font
868 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
870 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
872 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
873 // Update current font
874 real_current_font.update(font,
875 bview->buffer()->params.language,
878 // Reduce to implicit settings
879 current_font = real_current_font;
880 current_font.reduce(layoutfont);
881 // And resolve it completely
882 real_current_font.realize(layoutfont);
886 LyXCursor tmpcursor = cursor; // store the current cursor
888 // ok we have a selection. This is always between sel_start_cursor
889 // and sel_end cursor
891 SetUndo(bview->buffer(), Undo::EDIT,
893 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
894 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next
896 sel_start_cursor.par()->previous,
897 sel_end_cursor.par()->next
900 cursor = sel_start_cursor;
901 while (cursor.par() != sel_end_cursor.par() ||
904 cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag &&
906 cursor.pos() < sel_end_cursor.pos()))
908 if (cursor.pos() < cursor.par()->Last()
910 && cursor.par()->footnoteflag
911 == sel_start_cursor.par()->footnoteflag
914 // an open footnote should behave
916 LyXFont newfont = GetFont(bview->buffer(),
917 cursor.par(), cursor.pos());
919 bview->buffer()->params.language,
921 SetCharFont(bview->buffer(),
922 cursor.par(), cursor.pos(), newfont);
923 cursor.pos(cursor.pos() + 1);
926 cursor.par(cursor.par()->Next());
930 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
932 // we have to reset the selection, because the
933 // geometry could have changed
934 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
936 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
939 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
940 tmpcursor.boundary());
944 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
946 Row * tmprow = cur.row();
947 int y = cur.y() - tmprow->baseline();
949 SetHeightOfRow(bview, tmprow);
951 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
953 LyXParagraph * first_phys_par = tmprow->par();
955 // find the first row of the paragraph
956 if (first_phys_par != tmprow->par())
957 while (tmprow->previous()
958 && tmprow->previous()->par() != first_phys_par) {
959 tmprow = tmprow->previous();
960 y -= tmprow->height();
961 SetHeightOfRow(bview, tmprow);
963 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
964 tmprow = tmprow->previous();
965 y -= tmprow->height();
966 SetHeightOfRow(bview, tmprow);
969 // we can set the refreshing parameters now
970 status = LyXText::NEED_MORE_REFRESH;
972 refresh_row = tmprow;
973 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
977 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
979 Row * tmprow = cur.row();
981 int y = cur.y() - tmprow->baseline();
982 SetHeightOfRow(bview, tmprow);
984 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
986 LyXParagraph * first_phys_par = tmprow->par();
988 // find the first row of the paragraph
989 if (first_phys_par != tmprow->par())
990 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
991 tmprow = tmprow->previous();
992 y -= tmprow->height();
994 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
995 tmprow = tmprow->previous();
996 y -= tmprow->height();
999 // we can set the refreshing parameters now
1000 if (status == LyXText::UNCHANGED || y < refresh_y) {
1002 refresh_row = tmprow;
1004 status = LyXText::NEED_MORE_REFRESH;
1005 SetCursor(bview, cur.par(), cur.pos());
1009 /* deletes and inserts again all paragaphs between the cursor
1010 * and the specified par
1011 * This function is needed after SetLayout and SetFont etc. */
1012 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
1013 LyXParagraph const * endpar) const
1016 LyXParagraph * tmppar = 0, * first_phys_par = 0;
1018 Row * tmprow = cur.row();
1020 int y = cur.y() - tmprow->baseline();
1022 if (!tmprow->previous()){
1023 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
1026 first_phys_par = tmprow->par()->FirstPhysicalPar();
1028 first_phys_par = tmprow->par();
1030 // find the first row of the paragraph
1031 if (first_phys_par != tmprow->par())
1032 while (tmprow->previous() &&
1033 (tmprow->previous()->par() != first_phys_par)) {
1034 tmprow = tmprow->previous();
1035 y -= tmprow->height();
1037 while (tmprow->previous()
1038 && tmprow->previous()->par() == first_phys_par) {
1039 tmprow = tmprow->previous();
1040 y -= tmprow->height();
1044 // we can set the refreshing parameters now
1045 status = LyXText::NEED_MORE_REFRESH;
1047 refresh_row = tmprow->previous(); /* the real refresh row will
1048 be deleted, so I store
1049 the previous here */
1052 tmppar = tmprow->next()->par();
1055 while (tmppar != endpar) {
1056 RemoveRow(tmprow->next());
1058 tmppar = tmprow->next()->par();
1063 // remove the first one
1064 tmprow2 = tmprow; /* this is because tmprow->previous()
1066 tmprow = tmprow->previous();
1069 tmppar = first_phys_par;
1073 InsertParagraph(bview, tmppar, tmprow);
1076 while (tmprow->next() && tmprow->next()->par() == tmppar)
1077 tmprow = tmprow->next();
1078 tmppar = tmppar->Next();
1080 } while (tmppar != endpar);
1082 // this is because of layout changes
1084 refresh_y -= refresh_row->height();
1085 SetHeightOfRow(bview, refresh_row);
1087 refresh_row = firstrow;
1089 SetHeightOfRow(bview, refresh_row);
1092 if (tmprow && tmprow->next())
1093 SetHeightOfRow(bview, tmprow->next());
1097 bool LyXText::FullRebreak(BufferView * bview)
1103 if (need_break_row) {
1104 BreakAgain(bview, need_break_row);
1112 /* important for the screen */
1115 /* the cursor set functions have a special mechanism. When they
1116 * realize, that you left an empty paragraph, they will delete it.
1117 * They also delete the corresponding row */
1119 // need the selection cursor:
1120 void LyXText::SetSelection(BufferView * bview)
1122 const bool lsel = selection;
1125 last_sel_cursor = sel_cursor;
1126 sel_start_cursor = sel_cursor;
1127 sel_end_cursor = sel_cursor;
1132 // first the toggling area
1133 if (cursor.y() < last_sel_cursor.y()
1134 || (cursor.y() == last_sel_cursor.y()
1135 && cursor.x() < last_sel_cursor.x())) {
1136 toggle_end_cursor = last_sel_cursor;
1137 toggle_cursor = cursor;
1139 toggle_end_cursor = cursor;
1140 toggle_cursor = last_sel_cursor;
1143 last_sel_cursor = cursor;
1145 // and now the whole selection
1147 if (sel_cursor.par() == cursor.par())
1148 if (sel_cursor.pos() < cursor.pos()) {
1149 sel_end_cursor = cursor;
1150 sel_start_cursor = sel_cursor;
1152 sel_end_cursor = sel_cursor;
1153 sel_start_cursor = cursor;
1155 else if (sel_cursor.y() < cursor.y() ||
1156 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1157 sel_end_cursor = cursor;
1158 sel_start_cursor = sel_cursor;
1161 sel_end_cursor = sel_cursor;
1162 sel_start_cursor = cursor;
1165 // a selection with no contents is not a selection
1166 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1167 sel_start_cursor.pos() == sel_end_cursor.pos())
1170 if (inset_owner && (selection || lsel))
1171 inset_owner->SetUpdateStatus(bview, InsetText::SELECTION);
1175 string const LyXText::selectionAsString(Buffer const * buffer) const
1177 if (!selection) return string();
1180 // Special handling if the whole selection is within one paragraph
1181 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1182 result += sel_start_cursor.par()->String(buffer,
1183 sel_start_cursor.pos(),
1184 sel_end_cursor.pos());
1188 // The selection spans more than one paragraph
1190 // First paragraph in selection
1191 result += sel_start_cursor.par()->String(buffer,
1192 sel_start_cursor.pos(),
1193 sel_start_cursor.par()->Last())
1196 // The paragraphs in between (if any)
1197 LyXCursor tmpcur(sel_start_cursor);
1198 tmpcur.par(tmpcur.par()->Next());
1199 while (tmpcur.par() != sel_end_cursor.par()) {
1200 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1201 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1204 // Last paragraph in selection
1205 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1211 void LyXText::ClearSelection() const
1214 status = LyXText::NEED_MORE_REFRESH;
1220 void LyXText::CursorHome(BufferView * bview) const
1222 SetCursor(bview, cursor.par(), cursor.row()->pos());
1226 void LyXText::CursorEnd(BufferView * bview) const
1228 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1229 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1231 if (cursor.par()->Last() &&
1232 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1233 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1234 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1236 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1241 void LyXText::CursorTop(BufferView * bview) const
1243 while (cursor.par()->Previous())
1244 cursor.par(cursor.par()->Previous());
1245 SetCursor(bview, cursor.par(), 0);
1249 void LyXText::CursorBottom(BufferView * bview) const
1251 while (cursor.par()->Next())
1252 cursor.par(cursor.par()->Next());
1253 SetCursor(bview, cursor.par(), cursor.par()->Last());
1257 /* returns a pointer to the row near the specified y-coordinate
1258 * (relative to the whole text). y is set to the real beginning
1260 Row * LyXText::GetRowNearY(int & y) const
1262 Row * tmprow = firstrow;
1265 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1266 tmpy += tmprow->height();
1267 tmprow = tmprow->next();
1270 y = tmpy; // return the real y
1275 void LyXText::ToggleFree(BufferView * bview,
1276 LyXFont const & font, bool toggleall)
1278 // If the mask is completely neutral, tell user
1279 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1280 // Could only happen with user style
1281 bview->owner()->getMiniBuffer()
1282 ->Set(_("No font change defined. Use Character under"
1283 " the Layout menu to define font change."));
1287 // Try implicit word selection
1288 // If there is a change in the language the implicit word selection
1290 LyXCursor resetCursor = cursor;
1291 bool implicitSelection = (font.language() == ignore_language
1292 && font.number() == LyXFont::IGNORE)
1293 ? SelectWordWhenUnderCursor(bview) : false;
1296 SetFont(bview, font, toggleall);
1298 /* Implicit selections are cleared afterwards and cursor is set to the
1299 original position. */
1300 if (implicitSelection) {
1302 cursor = resetCursor;
1303 SetCursor(bview, cursor.par(), cursor.pos());
1304 sel_cursor = cursor;
1307 inset_owner->SetUpdateStatus(bview, InsetText::CURSOR_PAR);
1311 LyXParagraph::size_type
1312 LyXText::BeginningOfMainBody(Buffer const * buf,
1313 LyXParagraph const * par) const
1315 if (textclasslist.Style(buf->params.textclass,
1316 par->GetLayout()).labeltype != LABEL_MANUAL)
1319 return par->BeginningOfMainBody();
1324 /* if there is a selection, reset every environment you can find
1325 * in the selection, otherwise just the environment you are in */
1326 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1328 LyXParagraph * tmppar, * firsttmppar;
1332 /* is is only allowed, if the cursor is IN an open footnote.
1333 * Otherwise it is too dangerous */
1334 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1337 SetUndo(bview->buffer(), Undo::FINISH,
1338 cursor.par()->PreviousBeforeFootnote()->previous,
1339 cursor.par()->NextAfterFootnote()->next);
1341 /* ok, move to the beginning of the footnote. */
1342 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1343 cursor.par(cursor.par()->Previous());
1345 SetCursor(bview, cursor.par(), cursor.par()->Last());
1346 /* this is just faster than using CursorLeft(); */
1348 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1349 tmppar = firsttmppar;
1350 /* tmppar is now the paragraph right before the footnote */
1352 bool first_footnote_par_is_not_empty = tmppar->next->size();
1355 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1356 tmppar = tmppar->next; /* I use next instead of Next(),
1357 * because there cannot be any
1358 * footnotes in a footnote
1360 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1362 /* remember the captions and empty paragraphs */
1363 if ((textclasslist.Style(bview->buffer()->params.textclass,
1364 tmppar->GetLayout())
1365 .labeltype == LABEL_SENSITIVE)
1367 tmppar->SetLayout(bview->buffer()->params, 0);
1370 // now we will paste the ex-footnote, if the layouts allow it
1371 // first restore the layout of the paragraph right behind
1374 tmppar->next->MakeSameLayout(cursor.par());
1377 if (!tmppar->GetLayout()
1379 && (!tmppar->Next()->Last()
1380 || tmppar->Next()->HasSameLayout(tmppar)))) {
1381 if (tmppar->Next()->Last()
1382 && tmppar->Next()->IsLineSeparator(0))
1383 tmppar->Next()->Erase(0);
1384 tmppar->PasteParagraph(bview->buffer()->params);
1387 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1388 * by the pasting of the beginning */
1390 /* then the beginning */
1391 /* if there is no space between the text and the footnote, so we insert
1393 * (only if the previous par and the footnotepar are not empty!) */
1394 if (!firsttmppar->next->GetLayout()
1395 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1396 if (firsttmppar->size()
1397 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1398 && first_footnote_par_is_not_empty) {
1399 firsttmppar->next->InsertChar(0, ' ');
1401 firsttmppar->PasteParagraph(bview->buffer()->params);
1404 /* now redo the paragaphs */
1405 RedoParagraphs(bview, cursor, tmppar);
1407 SetCursor(bview, cursor.par(), cursor.pos());
1409 /* sometimes it can happen, that there is a counter change */
1410 Row * row = cursor.row();
1411 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1413 UpdateCounters(bview, row);
1421 /* the DTP switches for paragraphs. LyX will store them in the
1422 * first physicla paragraph. When a paragraph is broken, the top settings
1423 * rest, the bottom settings are given to the new one. So I can make shure,
1424 * they do not duplicate themself and you cannnot make dirty things with
1427 void LyXText::SetParagraph(BufferView * bview,
1428 bool line_top, bool line_bottom,
1429 bool pagebreak_top, bool pagebreak_bottom,
1430 VSpace const & space_top,
1431 VSpace const & space_bottom,
1433 string labelwidthstring,
1436 LyXCursor tmpcursor = cursor;
1438 sel_start_cursor = cursor;
1439 sel_end_cursor = cursor;
1442 // make sure that the depth behind the selection are restored, too
1444 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1446 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1448 LyXParagraph * undoendpar = endpar;
1450 if (endpar && endpar->GetDepth()) {
1451 while (endpar && endpar->GetDepth()) {
1453 endpar = endpar->LastPhysicalPar()->Next();
1455 endpar = endpar->Next();
1457 undoendpar = endpar;
1461 endpar = endpar->Next(); // because of parindents etc.
1464 SetUndo(bview->buffer(), Undo::EDIT,
1467 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1469 sel_start_cursor.par()->previous,
1474 LyXParagraph * tmppar = sel_end_cursor.par();
1476 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1477 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1479 while (tmppar != sel_start_cursor.par()->Previous()) {
1480 SetCursor(bview, tmppar, 0);
1482 status = LyXText::NEED_MORE_REFRESH;
1483 refresh_row = cursor.row();
1484 refresh_y = cursor.y() - cursor.row()->baseline();
1486 if (cursor.par()->footnoteflag ==
1487 sel_start_cursor.par()->footnoteflag) {
1489 cursor.par()->line_top = line_top;
1490 cursor.par()->line_bottom = line_bottom;
1491 cursor.par()->pagebreak_top = pagebreak_top;
1492 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1493 cursor.par()->added_space_top = space_top;
1494 cursor.par()->added_space_bottom = space_bottom;
1495 // does the layout allow the new alignment?
1496 if (align == LYX_ALIGN_LAYOUT)
1497 align = textclasslist
1498 .Style(bview->buffer()->params.textclass,
1499 cursor.par()->GetLayout()).align;
1500 if (align & textclasslist
1501 .Style(bview->buffer()->params.textclass,
1502 cursor.par()->GetLayout()).alignpossible) {
1503 if (align == textclasslist
1504 .Style(bview->buffer()->params.textclass,
1505 cursor.par()->GetLayout()).align)
1506 cursor.par()->align = LYX_ALIGN_LAYOUT;
1508 cursor.par()->align = align;
1510 cursor.par()->SetLabelWidthString(labelwidthstring);
1511 cursor.par()->noindent = noindent;
1515 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1517 tmppar = cursor.par()->Previous();
1521 RedoParagraphs(bview, sel_start_cursor, endpar);
1524 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1525 sel_cursor = cursor;
1526 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1527 SetSelection(bview);
1528 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1530 bview->updateInset(inset_owner, true);
1534 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1535 string const & width,
1536 string const & widthp,
1537 int alignment, bool hfill,
1538 bool start_minipage)
1540 LyXCursor tmpcursor = cursor;
1541 LyXParagraph * tmppar;
1543 sel_start_cursor = cursor;
1544 sel_end_cursor = cursor;
1547 // make sure that the depth behind the selection are restored, too
1549 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1551 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1553 LyXParagraph * undoendpar = endpar;
1555 if (endpar && endpar->GetDepth()) {
1556 while (endpar && endpar->GetDepth()) {
1558 endpar = endpar->LastPhysicalPar()->Next();
1560 endpar = endpar->Next();
1562 undoendpar = endpar;
1566 endpar = endpar->Next(); // because of parindents etc.
1569 SetUndo(bview->buffer(), Undo::EDIT,
1572 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1574 sel_start_cursor.par()->previous,
1578 tmppar = sel_end_cursor.par();
1580 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1581 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1583 while(tmppar != sel_start_cursor.par()->Previous()) {
1584 SetCursor(bview, tmppar, 0);
1586 status = LyXText::NEED_MORE_REFRESH;
1587 refresh_row = cursor.row();
1588 refresh_y = cursor.y() - cursor.row()->baseline();
1590 if (cursor.par()->footnoteflag ==
1591 sel_start_cursor.par()->footnoteflag) {
1593 if (type == LyXParagraph::PEXTRA_NONE) {
1594 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1595 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1596 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1599 cursor.par()->SetPExtraType(bview->buffer()->params,
1600 type, width, widthp);
1601 cursor.par()->pextra_hfill = hfill;
1602 cursor.par()->pextra_start_minipage = start_minipage;
1603 cursor.par()->pextra_alignment = alignment;
1607 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1609 tmppar = cursor.par()->Previous();
1612 RedoParagraphs(bview, sel_start_cursor, endpar);
1614 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1615 sel_cursor = cursor;
1616 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1617 SetSelection(bview);
1618 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1622 char loweralphaCounter(int n)
1624 if (n < 1 || n > 26)
1632 char alphaCounter(int n)
1634 if (n < 1 || n > 26)
1642 char hebrewCounter(int n)
1644 static const char hebrew[22] = {
1645 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1646 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1647 '÷', 'ø', 'ù', 'ú'
1649 if (n < 1 || n > 22)
1657 string const romanCounter(int n)
1659 static char const * roman[20] = {
1660 "i", "ii", "iii", "iv", "v",
1661 "vi", "vii", "viii", "ix", "x",
1662 "xi", "xii", "xiii", "xiv", "xv",
1663 "xvi", "xvii", "xviii", "xix", "xx"
1665 if (n < 1 || n > 20)
1672 // set the counter of a paragraph. This includes the labels
1673 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1676 // this is only relevant for the beginning of paragraph
1677 par = par->FirstPhysicalPar();
1679 LyXLayout const & layout =
1680 textclasslist.Style(buf->params.textclass,
1683 LyXTextClass const & textclass =
1684 textclasslist.TextClass(buf->params.textclass);
1686 /* copy the prev-counters to this one, unless this is the start of a
1687 footnote or of a bibliography or the very first paragraph */
1690 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1691 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1692 && par->footnotekind == LyXParagraph::FOOTNOTE)
1694 && !(textclasslist.Style(buf->params.textclass,
1695 par->Previous()->GetLayout()
1696 ).labeltype != LABEL_BIBLIO
1697 && layout.labeltype == LABEL_BIBLIO)) {
1698 for (int i = 0; i < 10; ++i) {
1699 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1702 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1704 par->appendix = par->Previous()->appendix;
1706 if (!par->appendix && par->start_of_appendix){
1707 par->appendix = true;
1708 for (int i = 0; i < 10; ++i) {
1709 par->setCounter(i, 0);
1713 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1714 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1716 par->enumdepth = par->Previous()->enumdepth;
1717 par->itemdepth = par->Previous()->itemdepth;
1720 for (int i = 0; i < 10; ++i) {
1721 par->setCounter(i, 0);
1723 par->appendix = par->start_of_appendix;
1729 // if this is an open marginnote and this is the first
1730 // entry in the marginnote and the enclosing
1731 // environment is an enum/item then correct for the
1732 // LaTeX behaviour (ARRae)
1733 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1734 && par->footnotekind == LyXParagraph::MARGIN
1736 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1737 && (par->PreviousBeforeFootnote()
1738 && textclasslist.Style(buf->params.textclass,
1739 par->PreviousBeforeFootnote()->GetLayout()
1740 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1741 // Any itemize or enumerate environment in a marginnote
1742 // that is embedded in an itemize or enumerate
1743 // paragraph is seen by LaTeX as being at a deeper
1744 // level within that enclosing itemization/enumeration
1745 // even if there is a "standard" layout at the start of
1751 /* Maybe we have to increment the enumeration depth.
1752 * BUT, enumeration in a footnote is considered in isolation from its
1753 * surrounding paragraph so don't increment if this is the
1754 * first line of the footnote
1755 * AND, bibliographies can't have their depth changed ie. they
1756 * are always of depth 0
1759 && par->Previous()->GetDepth() < par->GetDepth()
1760 && textclasslist.Style(buf->params.textclass,
1761 par->Previous()->GetLayout()
1762 ).labeltype == LABEL_COUNTER_ENUMI
1763 && par->enumdepth < 3
1765 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1766 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1767 && par->footnotekind == LyXParagraph::FOOTNOTE)
1769 && layout.labeltype != LABEL_BIBLIO) {
1773 /* Maybe we have to decrement the enumeration depth, see note above */
1775 && par->Previous()->GetDepth() > par->GetDepth()
1777 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1778 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1779 && par->footnotekind == LyXParagraph::FOOTNOTE)
1781 && layout.labeltype != LABEL_BIBLIO) {
1782 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1783 par->setCounter(6 + par->enumdepth,
1784 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1785 /* reset the counters.
1786 * A depth change is like a breaking layout
1788 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1789 par->setCounter(i, 0);
1792 if (!par->labelstring.empty()) {
1793 par->labelstring.erase();
1796 if (layout.margintype == MARGIN_MANUAL) {
1797 if (par->labelwidthstring.empty()) {
1798 par->SetLabelWidthString(layout.labelstring());
1801 par->SetLabelWidthString(string());
1804 /* is it a layout that has an automatic label ? */
1805 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1807 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1808 if (i >= 0 && i<= buf->params.secnumdepth) {
1809 par->incCounter(i); // increment the counter
1811 // Is there a label? Useful for Chapter layout
1812 if (!par->appendix){
1813 if (!layout.labelstring().empty())
1814 par->labelstring = layout.labelstring();
1816 par->labelstring.erase();
1818 if (!layout.labelstring_appendix().empty())
1819 par->labelstring = layout.labelstring_appendix();
1821 par->labelstring.erase();
1824 std::ostringstream s;
1826 if (!par->appendix) {
1827 switch (2 * LABEL_COUNTER_CHAPTER -
1828 textclass.maxcounter() + i) {
1829 case LABEL_COUNTER_CHAPTER:
1830 s << par->getCounter(i);
1832 case LABEL_COUNTER_SECTION:
1833 s << par->getCounter(i - 1) << '.'
1834 << par->getCounter(i);
1836 case LABEL_COUNTER_SUBSECTION:
1837 s << par->getCounter(i - 2) << '.'
1838 << par->getCounter(i - 1) << '.'
1839 << par->getCounter(i);
1841 case LABEL_COUNTER_SUBSUBSECTION:
1842 s << par->getCounter(i - 3) << '.'
1843 << par->getCounter(i - 2) << '.'
1844 << par->getCounter(i - 1) << '.'
1845 << par->getCounter(i);
1848 case LABEL_COUNTER_PARAGRAPH:
1849 s << par->getCounter(i - 4) << '.'
1850 << par->getCounter(i - 3) << '.'
1851 << par->getCounter(i - 2) << '.'
1852 << par->getCounter(i - 1) << '.'
1853 << par->getCounter(i);
1855 case LABEL_COUNTER_SUBPARAGRAPH:
1856 s << par->getCounter(i - 5) << '.'
1857 << par->getCounter(i - 4) << '.'
1858 << par->getCounter(i - 3) << '.'
1859 << par->getCounter(i - 2) << '.'
1860 << par->getCounter(i - 1) << '.'
1861 << par->getCounter(i);
1865 // Can this ever be reached? And in the
1866 // case it is, how can this be correct?
1868 s << par->getCounter(i) << '.';
1871 } else { // appendix
1872 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1873 case LABEL_COUNTER_CHAPTER:
1874 if (par->isRightToLeftPar(buf->params))
1875 s << hebrewCounter(par->getCounter(i));
1877 s << alphaCounter(par->getCounter(i));
1879 case LABEL_COUNTER_SECTION:
1880 if (par->isRightToLeftPar(buf->params))
1881 s << hebrewCounter(par->getCounter(i - 1));
1883 s << alphaCounter(par->getCounter(i - 1));
1886 << par->getCounter(i);
1889 case LABEL_COUNTER_SUBSECTION:
1890 if (par->isRightToLeftPar(buf->params))
1891 s << hebrewCounter(par->getCounter(i - 2));
1893 s << alphaCounter(par->getCounter(i - 2));
1896 << par->getCounter(i-1) << '.'
1897 << par->getCounter(i);
1900 case LABEL_COUNTER_SUBSUBSECTION:
1901 if (par->isRightToLeftPar(buf->params))
1902 s << hebrewCounter(par->getCounter(i-3));
1904 s << alphaCounter(par->getCounter(i-3));
1907 << par->getCounter(i-2) << '.'
1908 << par->getCounter(i-1) << '.'
1909 << par->getCounter(i);
1912 case LABEL_COUNTER_PARAGRAPH:
1913 if (par->isRightToLeftPar(buf->params))
1914 s << hebrewCounter(par->getCounter(i-4));
1916 s << alphaCounter(par->getCounter(i-4));
1919 << par->getCounter(i-3) << '.'
1920 << par->getCounter(i-2) << '.'
1921 << par->getCounter(i-1) << '.'
1922 << par->getCounter(i);
1925 case LABEL_COUNTER_SUBPARAGRAPH:
1926 if (par->isRightToLeftPar(buf->params))
1927 s << hebrewCounter(par->getCounter(i-5));
1929 s << alphaCounter(par->getCounter(i-5));
1932 << par->getCounter(i-4) << '.'
1933 << par->getCounter(i-3) << '.'
1934 << par->getCounter(i-2) << '.'
1935 << par->getCounter(i-1) << '.'
1936 << par->getCounter(i);
1940 // Can this ever be reached? And in the
1941 // case it is, how can this be correct?
1943 s << par->getCounter(i) << '.';
1949 par->labelstring += s.str().c_str();
1950 // We really want to remove the c_str as soon as
1953 for (i++; i < 10; ++i) {
1954 // reset the following counters
1955 par->setCounter(i, 0);
1957 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1958 for (i++; i < 10; ++i) {
1959 // reset the following counters
1960 par->setCounter(i, 0);
1962 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1963 par->incCounter(i + par->enumdepth);
1964 int number = par->getCounter(i + par->enumdepth);
1966 std::ostringstream s;
1968 switch (par->enumdepth) {
1970 if (par->isRightToLeftPar(buf->params))
1972 << hebrewCounter(number)
1976 << loweralphaCounter(number)
1980 if (par->isRightToLeftPar(buf->params))
1981 s << '.' << romanCounter(number);
1983 s << romanCounter(number) << '.';
1986 if (par->isRightToLeftPar(buf->params))
1988 << alphaCounter(number);
1990 s << alphaCounter(number)
1994 if (par->isRightToLeftPar(buf->params))
2001 par->labelstring = s.str().c_str();
2002 // we really want to get rid of that c_str()
2004 for (i += par->enumdepth + 1; i < 10; ++i)
2005 par->setCounter(i, 0); /* reset the following counters */
2008 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2009 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2011 int number = par->getCounter(i);
2013 InsetCommandParams p( "bibitem" );
2014 par->bibkey = new InsetBibKey(p);
2016 par->bibkey->setCounter(number);
2017 par->labelstring = layout.labelstring();
2019 // In biblio should't be following counters but...
2021 string s = layout.labelstring();
2023 // the caption hack:
2024 if (layout.labeltype == LABEL_SENSITIVE) {
2025 bool isOK (par->InInset() && par->InInset()->owner() &&
2026 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2028 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2029 && (par->footnotekind == LyXParagraph::FIG
2030 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2031 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2032 ? ":øåéà " : "Figure:";
2033 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2034 && (par->footnotekind == LyXParagraph::TAB
2035 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2036 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2037 ? ":äìáè" : "Table:";
2038 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2039 && par->footnotekind == LyXParagraph::ALGORITHM) {
2040 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2041 ? ":Ãúéøåâìà " : "Algorithm:";
2045 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2047 = floatList.getType(tmp->type());
2048 // We should get the correct number here too.
2049 s = fl.name() + " #:";
2051 /* par->SetLayout(0);
2052 s = layout->labelstring; */
2053 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2054 ? " :úåòîùî øñç" : "Senseless: ";
2057 par->labelstring = s;
2059 /* reset the enumeration counter. They are always resetted
2060 * when there is any other layout between */
2061 for (int i = 6 + par->enumdepth; i < 10; ++i)
2062 par->setCounter(i, 0);
2067 /* Updates all counters BEHIND the row. Changed paragraphs
2068 * with a dynamic left margin will be rebroken. */
2069 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2076 if (row->par()->next
2078 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2082 par = row->par()->LastPhysicalPar()->Next();
2084 par = row->par()->Next();
2087 par = row->par()->next;
2092 while (row->par() != par)
2095 SetCounter(bview->buffer(), par);
2097 /* now check for the headline layouts. remember that they
2098 * have a dynamic left margin */
2103 ( textclasslist.Style(bview->buffer()->params.textclass,
2104 par->layout).margintype == MARGIN_DYNAMIC
2105 || textclasslist.Style(bview->buffer()->params.textclass,
2106 par->layout).labeltype == LABEL_SENSITIVE)
2109 /* Rebreak the paragraph */
2110 RemoveParagraph(row);
2111 AppendParagraph(bview, row);
2114 /* think about the damned open footnotes! */
2115 while (par->Next() &&
2116 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2117 || par->Next()->IsDummy())){
2119 if (par->IsDummy()) {
2120 while (row->par() != par)
2122 RemoveParagraph(row);
2123 AppendParagraph(bview, row);
2129 par = par->LastPhysicalPar()->Next();
2138 /* insets an inset. */
2139 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2141 if (!cursor.par()->InsertInsetAllowed(inset))
2143 SetUndo(bview->buffer(), Undo::INSERT,
2145 cursor.par()->ParFromPos(cursor.pos())->previous,
2146 cursor.par()->ParFromPos(cursor.pos())->next
2148 cursor.par()->previous,
2152 cursor.par()->InsertInset(cursor.pos(), inset);
2153 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2154 * The character will not be inserted a
2157 // If we enter a highly editable inset the cursor should be to before
2158 // the inset. This couldn't happen before as Undo was not handled inside
2159 // inset now after the Undo LyX tries to call inset->Edit(...) again
2160 // and cannot do this as the cursor is behind the inset and GetInset
2161 // does not return the inset!
2162 if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
2163 CursorLeft(bview, true);
2169 void LyXText::copyEnvironmentType()
2171 copylayouttype = cursor.par()->GetLayout();
2175 void LyXText::pasteEnvironmentType(BufferView * bview)
2177 SetLayout(bview, copylayouttype);
2181 void LyXText::CutSelection(BufferView * bview, bool doclear)
2183 // Stuff what we got on the clipboard. Even if there is no selection.
2185 // There is a problem with having the stuffing here in that the
2186 // larger the selection the slower LyX will get. This can be
2187 // solved by running the line below only when the selection has
2188 // finished. The solution used currently just works, to make it
2189 // faster we need to be more clever and probably also have more
2190 // calls to stuffClipboard. (Lgb)
2191 bview->stuffClipboard(selectionAsString(bview->buffer()));
2193 // This doesn't make sense, if there is no selection
2197 // OK, we have a selection. This is always between sel_start_cursor
2198 // and sel_end_cursor
2200 // Check whether there are half footnotes in the selection
2201 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2202 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2203 LyXParagraph * tmppar = sel_start_cursor.par();
2204 while (tmppar != sel_end_cursor.par()){
2205 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2206 WriteAlert(_("Impossible operation"),
2207 _("Don't know what to do with half floats."),
2211 tmppar = tmppar->Next();
2216 // make sure that the depth behind the selection are restored, too
2218 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2220 LyXParagraph * endpar = sel_end_cursor.par()->Next();
2222 LyXParagraph * undoendpar = endpar;
2224 if (endpar && endpar->GetDepth()) {
2225 while (endpar && endpar->GetDepth()) {
2227 endpar = endpar->LastPhysicalPar()->Next();
2229 endpar = endpar->Next();
2231 undoendpar = endpar;
2233 } else if (endpar) {
2234 endpar = endpar->Next(); // because of parindents etc.
2237 SetUndo(bview->buffer(), Undo::DELETE,
2240 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2242 sel_start_cursor.par()->previous,
2248 // there are two cases: cut only within one paragraph or
2249 // more than one paragraph
2251 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2252 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2254 if (sel_start_cursor.par() == sel_end_cursor.par())
2257 // only within one paragraph
2258 endpar = sel_start_cursor.par();
2259 int pos = sel_end_cursor.pos();
2260 cap.cutSelection(sel_start_cursor.par(), &endpar,
2261 sel_start_cursor.pos(), pos,
2262 bview->buffer()->params.textclass, doclear);
2263 sel_end_cursor.pos(pos);
2265 endpar = sel_end_cursor.par();
2267 int pos = sel_end_cursor.pos();
2268 cap.cutSelection(sel_start_cursor.par(), &endpar,
2269 sel_start_cursor.pos(), pos,
2270 bview->buffer()->params.textclass, doclear);
2272 sel_end_cursor.par(endpar);
2273 sel_end_cursor.pos(pos);
2274 cursor.pos(sel_end_cursor.pos());
2276 endpar = endpar->Next();
2278 // sometimes necessary
2280 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2282 RedoParagraphs(bview, sel_start_cursor, endpar);
2285 cursor = sel_start_cursor;
2286 SetCursor(bview, cursor.par(), cursor.pos());
2287 sel_cursor = cursor;
2288 UpdateCounters(bview, cursor.row());
2292 void LyXText::CopySelection(BufferView * bview)
2294 // Stuff what we got on the clipboard. Even if there is no selection.
2296 // There is a problem with having the stuffing here in that the
2297 // larger the selection the slower LyX will get. This can be
2298 // solved by running the line below only when the selection has
2299 // finished. The solution used currently just works, to make it
2300 // faster we need to be more clever and probably also have more
2301 // calls to stuffClipboard. (Lgb)
2302 bview->stuffClipboard(selectionAsString(bview->buffer()));
2304 // this doesnt make sense, if there is no selection
2308 // ok we have a selection. This is always between sel_start_cursor
2309 // and sel_end cursor
2312 /* check wether there are half footnotes in the selection */
2313 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2314 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2315 LyXParagraph * tmppar = sel_start_cursor.par();
2316 while (tmppar != sel_end_cursor.par()) {
2317 if (tmppar->footnoteflag !=
2318 sel_end_cursor.par()->footnoteflag) {
2319 WriteAlert(_("Impossible operation"),
2320 _("Don't know what to do"
2321 " with half floats."),
2325 tmppar = tmppar->Next();
2330 // copy behind a space if there is one
2331 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2332 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2333 && (sel_start_cursor.par() != sel_end_cursor.par()
2334 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2335 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2339 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2340 sel_start_cursor.pos(), sel_end_cursor.pos(),
2341 bview->buffer()->params.textclass);
2345 void LyXText::PasteSelection(BufferView * bview)
2349 // this does not make sense, if there is nothing to paste
2350 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2353 SetUndo(bview->buffer(), Undo::INSERT,
2355 cursor.par()->ParFromPos(cursor.pos())->previous,
2356 cursor.par()->ParFromPos(cursor.pos())->next
2358 cursor.par()->previous,
2363 LyXParagraph * endpar;
2364 LyXParagraph * actpar = cursor.par();
2366 int pos = cursor.pos();
2367 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2369 RedoParagraphs(bview, cursor, endpar);
2371 SetCursor(bview, cursor.par(), cursor.pos());
2374 sel_cursor = cursor;
2375 SetCursor(bview, actpar, pos);
2376 SetSelection(bview);
2377 UpdateCounters(bview, cursor.row());
2381 // returns a pointer to the very first LyXParagraph
2382 LyXParagraph * LyXText::FirstParagraph() const
2384 return OwnerParagraph();
2388 // returns true if the specified string is at the specified position
2389 bool LyXText::IsStringInText(LyXParagraph * par,
2390 LyXParagraph::size_type pos,
2391 string const & str) const
2396 LyXParagraph::size_type i = 0;
2397 while (pos + i < par->Last()
2398 && string::size_type(i) < str.length()
2399 && str[i] == par->GetChar(pos + i)) {
2402 if (str.length() == string::size_type(i))
2408 // sets the selection over the number of characters of string, no check!!
2409 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2411 sel_cursor = cursor;
2412 for (int i = 0; str[i]; ++i)
2414 SetSelection(bview);
2418 // simple replacing. The font of the first selected character is used
2419 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2422 SetCursorParUndo(bview->buffer());
2425 if (!selection) { // create a dummy selection
2426 sel_end_cursor = cursor;
2427 sel_start_cursor = cursor;
2430 // Get font setting before we cut
2431 LyXParagraph::size_type pos = sel_end_cursor.pos();
2432 LyXFont const font = sel_start_cursor.par()
2433 ->GetFontSettings(bview->buffer()->params,
2434 sel_start_cursor.pos());
2436 // Insert the new string
2437 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2438 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2442 // Cut the selection
2443 CutSelection(bview);
2449 // if the string can be found: return true and set the cursor to
2451 bool LyXText::SearchForward(BufferView * bview, string const & str) const
2453 LyXParagraph * par = cursor.par();
2454 LyXParagraph::size_type pos = cursor.pos();
2455 while (par && !IsStringInText(par, pos, str)) {
2456 if (pos < par->Last() - 1)
2464 SetCursor(bview, par, pos);
2472 bool LyXText::SearchBackward(BufferView * bview, string const & str) const
2474 LyXParagraph * par = cursor.par();
2475 int pos = cursor.pos();
2481 // We skip empty paragraphs (Asger)
2483 par = par->Previous();
2485 pos = par->Last() - 1;
2486 } while (par && pos < 0);
2488 } while (par && !IsStringInText(par, pos, str));
2491 SetCursor(bview, par, pos);
2498 // needed to insert the selection
2499 void LyXText::InsertStringA(BufferView * bview, string const & str)
2501 LyXParagraph * par = cursor.par();
2502 LyXParagraph::size_type pos = cursor.pos();
2503 LyXParagraph::size_type a = 0;
2504 LyXParagraph * endpar = cursor.par()->Next();
2506 SetCursorParUndo(bview->buffer());
2509 textclasslist.Style(bview->buffer()->params.textclass,
2510 cursor.par()->GetLayout()).isEnvironment();
2511 // only to be sure, should not be neccessary
2514 // insert the string, don't insert doublespace
2515 string::size_type i = 0;
2516 while (i < str.length()) {
2517 if (str[i] != '\n') {
2519 && i + 1 < str.length() && str[i + 1] != ' '
2520 && pos && par->GetChar(pos - 1)!= ' ') {
2521 par->InsertChar(pos, ' ', current_font);
2523 } else if (str[i] == ' ') {
2524 InsetSpecialChar * new_inset =
2525 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2526 if (par->InsertInsetAllowed(new_inset)) {
2527 par->InsertInset(pos, new_inset,
2533 } else if (str[i] == '\t') {
2534 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2535 InsetSpecialChar * new_inset =
2536 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2537 if (par->InsertInsetAllowed(new_inset)) {
2538 par->InsertInset(pos, new_inset,
2545 } else if (str[i] != 13 &&
2546 // Ignore unprintables
2547 (str[i] & 127) >= ' ') {
2548 par->InsertChar(pos, str[i], current_font);
2552 if (!par->size()) { // par is empty
2553 InsetSpecialChar * new_inset =
2554 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2555 if (par->InsertInsetAllowed(new_inset)) {
2556 par->InsertInset(pos,
2564 par->BreakParagraph(bview->buffer()->params, pos, flag);
2571 RedoParagraphs(bview, cursor, endpar);
2572 SetCursor(bview, cursor.par(), cursor.pos());
2573 sel_cursor = cursor;
2574 SetCursor(bview, par, pos);
2575 SetSelection(bview);
2579 /* turns double-CR to single CR, others where converted into one blank and 13s
2580 * that are ignored .Double spaces are also converted into one. Spaces at
2581 * the beginning of a paragraph are forbidden. tabs are converted into one
2582 * space. then InsertStringA is called */
2583 void LyXText::InsertStringB(BufferView * bview, string const & s)
2586 string::size_type i = 1;
2587 while (i < str.length()) {
2590 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2592 if (str[i] == '\n' && i + 1 < str.length()) {
2593 if (str[i + 1] != '\n') {
2594 if (str[i - 1] != ' ')
2599 while (i + 1 < str.length()
2600 && (str[i + 1] == ' '
2601 || str[i + 1] == '\t'
2602 || str[i + 1] == '\n'
2603 || str[i + 1] == 13)) {
2610 InsertStringA(bview, str);
2614 bool LyXText::GotoNextInset(BufferView * bview,
2615 std::vector<Inset::Code> const & codes,
2616 string const & contents) const
2618 LyXCursor res = cursor;
2621 if (res.pos() < res.par()->Last() - 1) {
2622 res.pos(res.pos() + 1);
2624 res.par(res.par()->Next());
2628 } while (res.par() &&
2629 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2630 && (inset = res.par()->GetInset(res.pos())) != 0
2631 && find(codes.begin(), codes.end(), inset->LyxCode())
2633 && (contents.empty() ||
2634 static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
2638 SetCursor(bview, res.par(), res.pos());
2645 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2646 LyXParagraph::size_type pos)
2648 LyXCursor tmpcursor;
2651 LyXParagraph::size_type z;
2652 Row * row = GetRow(par, pos, y);
2654 // is there a break one row above
2655 if (row->previous() && row->previous()->par() == row->par()) {
2656 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2657 if (z >= row->pos()) {
2658 // set the dimensions of the row above
2659 y -= row->previous()->height();
2661 refresh_row = row->previous();
2662 status = LyXText::NEED_MORE_REFRESH;
2664 BreakAgain(bview, row->previous());
2666 // set the cursor again. Otherwise
2667 // dangling pointers are possible
2668 SetCursor(bview, cursor.par(), cursor.pos(),
2669 false, cursor.boundary());
2670 sel_cursor = cursor;
2675 int const tmpheight = row->height();
2676 LyXParagraph::size_type const tmplast = RowLast(row);
2680 BreakAgain(bview, row);
2681 if (row->height() == tmpheight && RowLast(row) == tmplast)
2682 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2684 status = LyXText::NEED_MORE_REFRESH;
2686 // check the special right address boxes
2687 if (textclasslist.Style(bview->buffer()->params.textclass,
2688 par->GetLayout()).margintype
2689 == MARGIN_RIGHT_ADDRESS_BOX) {
2696 RedoDrawingOfParagraph(bview, tmpcursor);
2699 // set the cursor again. Otherwise dangling pointers are possible
2700 // also set the selection
2704 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2705 false, sel_cursor.boundary());
2706 sel_cursor = cursor;
2707 SetCursorIntern(bview, sel_start_cursor.par(),
2708 sel_start_cursor.pos(),
2709 false, sel_start_cursor.boundary());
2710 sel_start_cursor = cursor;
2711 SetCursorIntern(bview, sel_end_cursor.par(),
2712 sel_end_cursor.pos(),
2713 false, sel_end_cursor.boundary());
2714 sel_end_cursor = cursor;
2715 SetCursorIntern(bview, last_sel_cursor.par(),
2716 last_sel_cursor.pos(),
2717 false, last_sel_cursor.boundary());
2718 last_sel_cursor = cursor;
2721 SetCursorIntern(bview, cursor.par(), cursor.pos(),
2722 false, cursor.boundary());
2726 // returns false if inset wasn't found
2727 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2729 // first check the current paragraph
2730 int pos = cursor.par()->GetPositionOfInset(inset);
2732 CheckParagraph(bview, cursor.par(), pos);
2736 // check every paragraph
2738 LyXParagraph * par = FirstParagraph();
2741 // make sure the paragraph is open
2742 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2744 pos = par->GetPositionOfInset(inset);
2746 CheckParagraph(bview, par, pos);
2759 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2760 LyXParagraph::size_type pos,
2761 bool setfont, bool boundary) const
2763 LyXCursor old_cursor = cursor;
2764 SetCursorIntern(bview, par, pos, setfont, boundary);
2765 DeleteEmptyParagraphMechanism(bview, old_cursor);
2769 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2770 LyXParagraph::size_type pos, bool boundary) const
2773 // correct the cursor position if impossible
2774 if (pos > par->Last()){
2775 LyXParagraph * tmppar = par->ParFromPos(pos);
2776 pos = par->PositionInParFromPos(pos);
2779 if (par->IsDummy() && par->previous &&
2780 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2781 while (par->previous &&
2782 ((par->previous->IsDummy() &&
2783 (par->previous->previous->footnoteflag ==
2784 LyXParagraph::CLOSED_FOOTNOTE)) ||
2785 (par->previous->footnoteflag ==
2786 LyXParagraph::CLOSED_FOOTNOTE))) {
2787 par = par->previous ;
2788 if (par->IsDummy() &&
2789 (par->previous->footnoteflag ==
2790 LyXParagraph::CLOSED_FOOTNOTE))
2791 pos += par->size() + 1;
2793 if (par->previous) {
2794 par = par->previous;
2796 pos += par->size() + 1;
2801 cur.boundary(boundary);
2803 /* get the cursor y position in text */
2805 Row * row = GetRow(par, pos, y);
2806 /* y is now the beginning of the cursor row */
2807 y += row->baseline();
2808 /* y is now the cursor baseline */
2811 /* now get the cursors x position */
2813 float fill_separator, fill_hfill, fill_label_hfill;
2814 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2816 LyXParagraph::size_type cursor_vpos = 0;
2817 LyXParagraph::size_type last = RowLastPrintable(row);
2819 if (pos > last + 1) // This shouldn't happen.
2821 else if (pos < row->pos())
2824 if (last < row->pos())
2825 cursor_vpos = row->pos();
2826 else if (pos > last && !boundary)
2827 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2828 ? row->pos() : last + 1;
2829 else if (pos > row->pos() &&
2830 (pos > last || boundary))
2831 /// Place cursor after char at (logical) position pos - 1
2832 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2833 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2835 /// Place cursor before char at (logical) position pos
2836 cursor_vpos = (bidi_level(pos) % 2 == 0)
2837 ? log2vis(pos) : log2vis(pos) + 1;
2839 LyXParagraph::size_type main_body =
2840 BeginningOfMainBody(bview->buffer(), row->par());
2841 if ((main_body > 0) &&
2842 ((main_body-1 > last) ||
2843 !row->par()->IsLineSeparator(main_body-1)))
2846 for (LyXParagraph::size_type vpos = row->pos();
2847 vpos < cursor_vpos; ++vpos) {
2848 pos = vis2log(vpos);
2849 if (main_body > 0 && pos == main_body - 1) {
2850 x += fill_label_hfill +
2851 lyxfont::width(textclasslist.Style(
2852 bview->buffer()->params.textclass,
2853 row->par()->GetLayout())
2855 GetFont(bview->buffer(), row->par(), -2));
2856 if (row->par()->IsLineSeparator(main_body-1))
2857 x -= SingleWidth(bview, row->par(),main_body-1);
2859 if (HfillExpansion(bview->buffer(), row, pos)) {
2860 x += SingleWidth(bview, row->par(), pos);
2861 if (pos >= main_body)
2864 x += fill_label_hfill;
2865 } else if (row->par()->IsSeparator(pos)) {
2866 x += SingleWidth(bview, row->par(), pos);
2867 if (pos >= main_body)
2868 x += fill_separator;
2870 x += SingleWidth(bview, row->par(), pos);
2879 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2880 LyXParagraph::size_type pos,
2881 bool setfont, bool boundary) const
2883 SetCursor(bview, cursor, par, pos, boundary);
2885 SetCurrentFont(bview);
2889 void LyXText::SetCurrentFont(BufferView * bview) const
2891 LyXParagraph::size_type pos = cursor.pos();
2892 if (cursor.boundary() && pos > 0)
2896 if (pos == cursor.par()->Last())
2898 else if (cursor.par()->IsSeparator(pos)) {
2899 if (pos > cursor.row()->pos() &&
2900 bidi_level(pos) % 2 ==
2901 bidi_level(pos - 1) % 2)
2903 else if (pos + 1 < cursor.par()->Last())
2909 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2910 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2912 if (cursor.pos() == cursor.par()->Last() &&
2913 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2914 !cursor.boundary()) {
2915 Language const * lang =
2916 cursor.par()->getParLanguage(bview->buffer()->params);
2917 current_font.setLanguage(lang);
2918 real_current_font.setLanguage(lang);
2923 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2925 LyXCursor old_cursor = cursor;
2927 /* get the row first */
2929 Row * row = GetRowNearY(y);
2930 cursor.par(row->par());
2933 int column = GetColumnNearX(bview, row, x, bound);
2934 cursor.pos(row->pos() + column);
2936 cursor.y(y + row->baseline());
2938 cursor.boundary(bound);
2939 SetCurrentFont(bview);
2940 DeleteEmptyParagraphMechanism(bview, old_cursor);
2944 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2947 /* get the row first */
2949 Row * row = GetRowNearY(y);
2951 int column = GetColumnNearX(bview, row, x, bound);
2953 cur.par(row->par());
2954 cur.pos(row->pos() + column);
2956 cur.y(y + row->baseline());
2958 cur.boundary(bound);
2962 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2964 if (cursor.pos() > 0) {
2965 bool boundary = cursor.boundary();
2966 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2967 if (!internal && !boundary &&
2968 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2969 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2970 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2971 LyXParagraph * par = cursor.par()->Previous();
2972 SetCursor(bview, par, par->Last());
2977 void LyXText::CursorRight(BufferView * bview, bool internal) const
2979 if (!internal && cursor.boundary() &&
2980 !cursor.par()->IsNewline(cursor.pos()))
2981 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2982 else if (cursor.pos() < cursor.par()->Last()) {
2983 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2985 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2986 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2987 } else if (cursor.par()->Next())
2988 SetCursor(bview, cursor.par()->Next(), 0);
2992 void LyXText::CursorUp(BufferView * bview) const
2994 SetCursorFromCoordinates(bview, cursor.x_fix(),
2995 cursor.y() - cursor.row()->baseline() - 1);
2999 void LyXText::CursorDown(BufferView * bview) const
3001 SetCursorFromCoordinates(bview, cursor.x_fix(),
3002 cursor.y() - cursor.row()->baseline()
3003 + cursor.row()->height() + 1);
3007 void LyXText::CursorUpParagraph(BufferView * bview) const
3009 if (cursor.pos() > 0) {
3010 SetCursor(bview, cursor.par(), 0);
3012 else if (cursor.par()->Previous()) {
3013 SetCursor(bview, cursor.par()->Previous(), 0);
3018 void LyXText::CursorDownParagraph(BufferView * bview) const
3020 if (cursor.par()->Next()) {
3021 SetCursor(bview, cursor.par()->Next(), 0);
3023 SetCursor(bview, cursor.par(), cursor.par()->Last());
3028 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3029 LyXCursor const & old_cursor) const
3031 // Would be wrong to delete anything if we have a selection.
3032 if (selection) return;
3034 // We allow all kinds of "mumbo-jumbo" when freespacing.
3035 if (textclasslist.Style(bview->buffer()->params.textclass,
3036 old_cursor.par()->GetLayout()).free_spacing)
3039 bool deleted = false;
3041 /* Ok I'll put some comments here about what is missing.
3042 I have fixed BackSpace (and thus Delete) to not delete
3043 double-spaces automagically. I have also changed Cut,
3044 Copy and Paste to hopefully do some sensible things.
3045 There are still some small problems that can lead to
3046 double spaces stored in the document file or space at
3047 the beginning of paragraphs. This happens if you have
3048 the cursor betwenn to spaces and then save. Or if you
3049 cut and paste and the selection have a space at the
3050 beginning and then save right after the paste. I am
3051 sure none of these are very hard to fix, but I will
3052 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3053 that I can get some feedback. (Lgb)
3056 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3057 // delete the LineSeparator.
3060 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3061 // delete the LineSeparator.
3064 // If the pos around the old_cursor were spaces, delete one of them.
3065 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3066 // Only if the cursor has really moved
3068 if (old_cursor.pos() > 0
3069 && old_cursor.pos() < old_cursor.par()->Last()
3070 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3071 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3072 old_cursor.par()->Erase(old_cursor.pos() - 1);
3073 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3075 if (old_cursor.par() == cursor.par() &&
3076 cursor.pos() > old_cursor.pos()) {
3077 SetCursorIntern(bview, cursor.par(),
3080 SetCursorIntern(bview, cursor.par(),
3086 // Do not delete empty paragraphs with keepempty set.
3087 if ((textclasslist.Style(bview->buffer()->params.textclass,
3088 old_cursor.par()->GetLayout())).keepempty)
3091 LyXCursor tmpcursor;
3093 if (old_cursor.par() != cursor.par()) {
3094 if ((old_cursor.par()->Last() == 0
3095 || (old_cursor.par()->Last() == 1
3096 && old_cursor.par()->IsLineSeparator(0)))
3098 && old_cursor.par()->FirstPhysicalPar()
3099 == old_cursor.par()->LastPhysicalPar()
3102 // ok, we will delete anything
3104 // make sure that you do not delete any environments
3107 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3108 !(old_cursor.row()->previous()
3109 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3110 && !(old_cursor.row()->next()
3111 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3112 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3113 && ((old_cursor.row()->previous()
3114 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3115 || (old_cursor.row()->next()
3116 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3119 status = LyXText::NEED_MORE_REFRESH;
3122 if (old_cursor.row()->previous()) {
3123 refresh_row = old_cursor.row()->previous();
3124 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3126 cursor = old_cursor; // that undo can restore the right cursor position
3127 LyXParagraph * endpar = old_cursor.par()->next;
3128 if (endpar && endpar->GetDepth()) {
3129 while (endpar && endpar->GetDepth()) {
3131 endpar = endpar->LastPhysicalPar()->Next();
3133 endpar = endpar->Next();
3137 SetUndo(bview->buffer(), Undo::DELETE,
3138 old_cursor.par()->previous,
3143 RemoveRow(old_cursor.row());
3144 if (OwnerParagraph() == old_cursor.par()) {
3145 OwnerParagraph(OwnerParagraph()->next);
3148 delete old_cursor.par();
3150 /* Breakagain the next par. Needed
3151 * because of the parindent that
3152 * can occur or dissappear. The
3153 * next row can change its height,
3154 * if there is another layout before */
3155 if (refresh_row->next()) {
3156 BreakAgain(bview, refresh_row->next());
3157 UpdateCounters(bview, refresh_row);
3159 SetHeightOfRow(bview, refresh_row);
3161 refresh_row = old_cursor.row()->next();
3162 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3165 cursor = old_cursor; // that undo can restore the right cursor position
3166 LyXParagraph * endpar = old_cursor.par()->next;
3167 if (endpar && endpar->GetDepth()) {
3168 while (endpar && endpar->GetDepth()) {
3170 endpar = endpar->LastPhysicalPar()->Next();
3172 endpar = endpar->Next();
3176 SetUndo(bview->buffer(), Undo::DELETE,
3177 old_cursor.par()->previous,
3182 RemoveRow(old_cursor.row());
3184 if (OwnerParagraph() == old_cursor.par()) {
3185 OwnerParagraph(OwnerParagraph()->next);
3187 delete old_cursor.par();
3189 /* Breakagain the next par. Needed
3190 because of the parindent that can
3191 occur or dissappear.
3192 The next row can change its height,
3193 if there is another layout before
3196 BreakAgain(bview, refresh_row);
3197 UpdateCounters(bview, refresh_row->previous());
3203 SetCursorIntern(bview, cursor.par(), cursor.pos());
3205 if (sel_cursor.par() == old_cursor.par()
3206 && sel_cursor.pos() == sel_cursor.pos()) {
3207 // correct selection
3208 sel_cursor = cursor;
3215 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3216 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3218 SetCursorIntern(bview, cursor.par(), cursor.pos());
3219 sel_cursor = cursor;
3226 LyXParagraph * LyXText::GetParFromID(int id)
3228 LyXParagraph * result = FirstParagraph();
3229 while (result && result->id() != id)
3230 result = result->next;
3236 bool LyXText::TextUndo(BufferView * bview)
3240 // returns false if no undo possible
3241 Undo * undo = bview->buffer()->undostack.pop();
3245 bview->buffer()->redostack
3246 .push(CreateUndo(bview->buffer(), undo->kind,
3247 GetParFromID(undo->number_of_before_par),
3248 GetParFromID(undo->number_of_behind_par)));
3250 return TextHandleUndo(bview, undo);
3254 bool LyXText::TextRedo(BufferView * bview)
3258 // returns false if no redo possible
3259 Undo * undo = bview->buffer()->redostack.pop();
3263 bview->buffer()->undostack
3264 .push(CreateUndo(bview->buffer(), undo->kind,
3265 GetParFromID(undo->number_of_before_par),
3266 GetParFromID(undo->number_of_behind_par)));
3268 return TextHandleUndo(bview, undo);
3272 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3276 // returns false if no undo possible
3277 bool result = false;
3279 LyXParagraph * before =
3280 GetParFromID(undo->number_of_before_par);
3281 LyXParagraph * behind =
3282 GetParFromID(undo->number_of_behind_par);
3283 LyXParagraph * tmppar;
3284 LyXParagraph * tmppar2;
3285 LyXParagraph * endpar;
3286 LyXParagraph * tmppar5;
3288 // if there's no before take the beginning
3289 // of the document for redoing
3291 SetCursorIntern(bview, FirstParagraph(), 0);
3293 // replace the paragraphs with the undo informations
3295 LyXParagraph * tmppar3 = undo->par;
3296 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3297 LyXParagraph * tmppar4 = tmppar3;
3299 while (tmppar4->next)
3300 tmppar4 = tmppar4->next;
3301 } // get last undo par
3303 // now remove the old text if there is any
3304 if (before != behind || (!behind && !before)){
3306 tmppar5 = before->next;
3308 tmppar5 = OwnerParagraph();
3310 while (tmppar5 && tmppar5 != behind){
3312 tmppar5 = tmppar5->next;
3313 // a memory optimization for edit: Only layout information
3314 // is stored in the undo. So restore the text informations.
3315 if (undo->kind == Undo::EDIT) {
3316 tmppar2->setContentsFromPar(tmppar);
3317 tmppar->clearContents();
3318 tmppar2 = tmppar2->next;
3323 // put the new stuff in the list if there is one
3326 before->next = tmppar3;
3328 OwnerParagraph(tmppar3);
3329 tmppar3->previous = before;
3332 OwnerParagraph(behind);
3335 tmppar4->next = behind;
3337 behind->previous = tmppar4;
3341 // Set the cursor for redoing
3344 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3346 SetCursorIntern(bview, before, 0);
3349 // check wether before points to a closed float and open it if necessary
3350 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3351 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3353 while (tmppar4->previous &&
3354 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3355 tmppar4 = tmppar4->previous;
3356 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3357 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3358 tmppar4 = tmppar4->next;
3365 // open a cosed footnote at the end if necessary
3366 if (behind && behind->previous &&
3367 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3368 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3369 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3370 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3371 behind = behind->next;
3376 // calculate the endpar for redoing the paragraphs.
3379 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3380 endpar = behind->LastPhysicalPar()->Next();
3382 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3384 endpar = behind->Next();
3389 tmppar = GetParFromID(undo->number_of_cursor_par);
3390 RedoParagraphs(bview, cursor, endpar);
3392 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3393 UpdateCounters(bview, cursor.row());
3403 void LyXText::FinishUndo()
3407 // makes sure the next operation will be stored
3408 undo_finished = true;
3412 void LyXText::FreezeUndo()
3416 // this is dangerous and for internal use only
3421 void LyXText::UnFreezeUndo()
3425 // this is dangerous and for internal use only
3426 undo_frozen = false;
3430 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3431 LyXParagraph const * before,
3432 LyXParagraph const * behind) const
3437 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3438 buf->redostack.clear();
3442 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3443 LyXParagraph const * before, LyXParagraph const * behind)
3447 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3451 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3452 LyXParagraph const * before,
3453 LyXParagraph const * behind) const
3458 int before_number = -1;
3459 int behind_number = -1;
3461 before_number = before->id();
3463 behind_number = behind->id();
3464 // Undo::EDIT and Undo::FINISH are
3465 // always finished. (no overlapping there)
3466 // overlapping only with insert and delete inside one paragraph:
3467 // Nobody wants all removed character
3468 // appear one by one when undoing.
3469 // EDIT is special since only layout information, not the
3470 // contents of a paragaph are stored.
3471 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3472 // check wether storing is needed
3473 if (!buf->undostack.empty() &&
3474 buf->undostack.top()->kind == kind &&
3475 buf->undostack.top()->number_of_before_par == before_number &&
3476 buf->undostack.top()->number_of_behind_par == behind_number ){
3481 // create a new Undo
3482 LyXParagraph * undopar;
3483 LyXParagraph * tmppar;
3484 LyXParagraph * tmppar2;
3486 LyXParagraph * start = 0;
3487 LyXParagraph * end = 0;
3490 start = before->next;
3492 start = FirstParagraph();
3494 end = behind->previous;
3496 end = FirstParagraph();
3501 if (start && end && (start != end->next) &&
3502 ((before != behind) || (!before && !behind)))
3505 tmppar2 = tmppar->Clone();
3506 tmppar2->id(tmppar->id());
3508 // a memory optimization: Just store the layout information
3510 if (kind == Undo::EDIT){
3511 //tmppar2->text.clear();
3512 tmppar2->clearContents();
3517 while (tmppar != end && tmppar->next) {
3518 tmppar = tmppar->next;
3519 tmppar2->next = tmppar->Clone();
3520 tmppar2->next->id(tmppar->id());
3521 // a memory optimization: Just store the layout
3522 // information when only edit
3523 if (kind == Undo::EDIT){
3524 //tmppar2->next->text.clear();
3525 tmppar2->clearContents();
3527 tmppar2->next->previous = tmppar2;
3528 tmppar2 = tmppar2->next;
3532 undopar = 0; // nothing to replace (undo of delete maybe)
3535 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3536 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3538 int cursor_par = cursor.par()->id();
3539 int cursor_pos = cursor.pos();
3542 Undo * undo = new Undo(kind,
3543 before_number, behind_number,
3544 cursor_par, cursor_pos,
3547 undo_finished = false;
3552 void LyXText::SetCursorParUndo(Buffer * buf)
3556 SetUndo(buf, Undo::FINISH,
3558 cursor.par()->ParFromPos(cursor.pos())->previous,
3559 cursor.par()->ParFromPos(cursor.pos())->next
3561 cursor.par()->previous,
3568 void LyXText::toggleAppendix(BufferView * bview)
3571 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3573 LyXParagraph * par = cursor.par();
3575 bool start = !par->start_of_appendix;
3577 // ensure that we have only one start_of_appendix in this document
3578 LyXParagraph * tmp = FirstParagraph();
3579 for (; tmp; tmp = tmp->next)
3580 tmp->start_of_appendix = 0;
3581 par->start_of_appendix = start;
3583 // we can set the refreshing parameters now
3584 status = LyXText::NEED_MORE_REFRESH;
3586 refresh_row = 0; // not needed for full update
3587 UpdateCounters(bview, 0);
3588 SetCursor(bview, cursor.par(), cursor.pos());
3592 LyXParagraph * LyXText::OwnerParagraph() const
3595 return inset_owner->par;
3597 return bv_owner->buffer()->paragraph;
3601 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3604 inset_owner->par = p;
3606 bv_owner->buffer()->paragraph = p;