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;
530 pos < par->Last(); ++pos) {
532 pos < par->size(); ++pos) {
534 if (pos < BeginningOfMainBody(buf, par))
535 layoutfont = layout.labelfont;
537 layoutfont = layout.font;
539 tmpfont = par->GetFontSettings(buf->params, pos);
540 tmpfont.reduce(layoutfont);
541 par->SetFont(pos, tmpfont);
546 LyXParagraph * LyXText::SetLayout(BufferView * bview,
547 LyXCursor & cur, LyXCursor & sstart_cur,
548 LyXCursor & send_cur,
549 LyXTextClass::size_type layout)
552 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->next();
554 LyXParagraph * endpar = send_cur.par()->next();
556 LyXParagraph * undoendpar = endpar;
558 if (endpar && endpar->GetDepth()) {
559 while (endpar && endpar->GetDepth()) {
561 endpar = endpar->LastPhysicalPar()->next();
563 endpar = endpar->next();
568 endpar = endpar->next(); // because of parindents etc.
571 SetUndo(bview->buffer(), Undo::EDIT,
573 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous_,
575 sstart_cur.par()->previous(),
579 /* ok we have a selection. This is always between sstart_cur
580 * and sel_end cursor */
583 LyXLayout const & lyxlayout =
584 textclasslist.Style(bview->buffer()->params.textclass, layout);
586 while (cur.par() != send_cur.par()) {
588 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
590 cur.par()->SetLayout(bview->buffer()->params, layout);
591 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
593 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
595 LyXParagraph * fppar = cur.par();
597 fppar->params.spaceTop(lyxlayout.fill_top ?
598 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
599 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
600 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
601 if (lyxlayout.margintype == MARGIN_MANUAL)
602 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
603 if (lyxlayout.labeltype != LABEL_BIBLIO
605 delete fppar->bibkey;
611 cur.par(cur.par()->next());
614 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
616 cur.par()->SetLayout(bview->buffer()->params, layout);
617 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
619 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
621 LyXParagraph * fppar = cur.par();
623 fppar->params.spaceTop(lyxlayout.fill_top ?
624 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
625 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
626 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
627 if (lyxlayout.margintype == MARGIN_MANUAL)
628 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
629 if (lyxlayout.labeltype != LABEL_BIBLIO
631 delete fppar->bibkey;
640 // set layout over selection and make a total rebreak of those paragraphs
641 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
643 LyXCursor tmpcursor = cursor; /* store the current cursor */
645 // if there is no selection just set the layout
646 // of the current paragraph */
648 sel_start_cursor = cursor; // dummy selection
649 sel_end_cursor = cursor;
652 endpar = SetLayout(bview, cursor, sel_start_cursor,
653 sel_end_cursor, layout);
654 RedoParagraphs(bview, sel_start_cursor, endpar);
656 // we have to reset the selection, because the
657 // geometry could have changed
658 SetCursor(bview, sel_start_cursor.par(),
659 sel_start_cursor.pos(), false);
661 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
663 UpdateCounters(bview, cursor.row());
664 ClearSelection(bview);
666 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
670 // increment depth over selection and
671 // make a total rebreak of those paragraphs
672 void LyXText::IncDepth(BufferView * bview)
674 // If there is no selection, just use the current paragraph
676 sel_start_cursor = cursor; // dummy selection
677 sel_end_cursor = cursor;
680 // We end at the next paragraph with depth 0
681 LyXParagraph * endpar =
683 sel_end_cursor.par()->LastPhysicalPar()->next();
685 sel_end_cursor.par()->next();
687 LyXParagraph * undoendpar = endpar;
689 if (endpar && endpar->GetDepth()) {
690 while (endpar && endpar->GetDepth()) {
692 endpar = endpar->LastPhysicalPar()->next();
694 endpar = endpar->next();
700 endpar = endpar->next(); // because of parindents etc.
703 SetUndo(bview->buffer(), Undo::EDIT,
706 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
708 sel_start_cursor.par()->previous(),
712 LyXCursor tmpcursor = cursor; // store the current cursor
714 // ok we have a selection. This is always between sel_start_cursor
715 // and sel_end cursor
716 cursor = sel_start_cursor;
718 bool anything_changed = false;
721 // NOTE: you can't change the depth of a bibliography entry
724 cursor.par()->footnoteflag ==
725 sel_start_cursor.par()->footnoteflag &&
727 textclasslist.Style(bview->buffer()->params.textclass,
728 cursor.par()->GetLayout()
729 ).labeltype != LABEL_BIBLIO) {
730 LyXParagraph * prev =
732 cursor.par()->FirstPhysicalPar()->previous();
734 cursor.par()->previous();
737 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
738 || (prev->GetDepth() == cursor.par()->GetDepth()
739 && textclasslist.Style(bview->buffer()->params.textclass,
740 prev->GetLayout()).isEnvironment()))) {
742 cursor.par()->FirstPhysicalPar()->params.depth(cursor.par()->FirstPhysicalPar()->params.depth() + 1);
744 cursor.par()->params.depth(cursor.par()->params.depth() + 1);
746 anything_changed = true;
749 if (cursor.par() == sel_end_cursor.par())
751 cursor.par(cursor.par()->next());
754 // if nothing changed set all depth to 0
755 if (!anything_changed) {
756 cursor = sel_start_cursor;
757 while (cursor.par() != sel_end_cursor.par()) {
759 cursor.par()->FirstPhysicalPar()->params.depth(0);
761 cursor.par()->params.depth(0);
763 cursor.par(cursor.par()->next());
766 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
767 cursor.par()->FirstPhysicalPar()->params.depth(0);
769 cursor.par()->params.depth(0);
773 RedoParagraphs(bview, sel_start_cursor, endpar);
775 // we have to reset the selection, because the
776 // geometry could have changed
777 SetCursor(bview, sel_start_cursor.par(),
778 sel_start_cursor.pos());
780 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
781 UpdateCounters(bview, cursor.row());
782 ClearSelection(bview);
784 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
788 // decrement depth over selection and
789 // make a total rebreak of those paragraphs
790 void LyXText::DecDepth(BufferView * bview)
792 // if there is no selection just set the layout
793 // of the current paragraph
795 sel_start_cursor = cursor; // dummy selection
796 sel_end_cursor = cursor;
799 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
801 LyXParagraph * endpar = sel_end_cursor.par()->next();
803 LyXParagraph * undoendpar = endpar;
805 if (endpar && endpar->GetDepth()) {
806 while (endpar && endpar->GetDepth()) {
808 endpar = endpar->LastPhysicalPar()->next();
810 endpar = endpar->next();
816 endpar = endpar->next(); // because of parindents etc.
819 SetUndo(bview->buffer(), Undo::EDIT,
822 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
824 sel_start_cursor.par()->previous(),
828 LyXCursor tmpcursor = cursor; // store the current cursor
830 // ok we have a selection. This is always between sel_start_cursor
831 // and sel_end cursor
832 cursor = sel_start_cursor;
836 if (cursor.par()->footnoteflag ==
837 sel_start_cursor.par()->footnoteflag) {
838 if (cursor.par()->FirstPhysicalPar()->params.depth())
839 cursor.par()->FirstPhysicalPar()->params.depth(cursor.par()->FirstPhysicalPar()->params.depth() - 1);
842 if (cursor.par()->params.depth())
843 cursor.par()->params.depth(cursor.par()->params.depth() - 1);
845 if (cursor.par() == sel_end_cursor.par())
847 cursor.par(cursor.par()->next());
850 RedoParagraphs(bview, sel_start_cursor, endpar);
852 // we have to reset the selection, because the
853 // geometry could have changed
854 SetCursor(bview, sel_start_cursor.par(),
855 sel_start_cursor.pos());
857 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
858 UpdateCounters(bview, cursor.row());
859 ClearSelection(bview);
861 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
865 // set font over selection and make a total rebreak of those paragraphs
866 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
868 // if there is no selection just set the current_font
870 // Determine basis font
872 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
874 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
876 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
877 // Update current font
878 real_current_font.update(font,
879 bview->buffer()->params.language,
882 // Reduce to implicit settings
883 current_font = real_current_font;
884 current_font.reduce(layoutfont);
885 // And resolve it completely
886 real_current_font.realize(layoutfont);
890 LyXCursor tmpcursor = cursor; // store the current cursor
892 // ok we have a selection. This is always between sel_start_cursor
893 // and sel_end cursor
895 SetUndo(bview->buffer(), Undo::EDIT,
897 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous_,
898 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next_
900 sel_start_cursor.par()->previous(),
901 sel_end_cursor.par()->next()
904 cursor = sel_start_cursor;
905 while (cursor.par() != sel_end_cursor.par() ||
908 cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag &&
910 cursor.pos() < sel_end_cursor.pos()))
913 if (cursor.pos() < cursor.par()->Last()
914 && cursor.par()->footnoteflag
915 == sel_start_cursor.par()->footnoteflag
917 if (cursor.pos() < cursor.par()->size()
920 // an open footnote should behave
922 LyXFont newfont = GetFont(bview->buffer(),
923 cursor.par(), cursor.pos());
925 bview->buffer()->params.language,
927 SetCharFont(bview->buffer(),
928 cursor.par(), cursor.pos(), newfont);
929 cursor.pos(cursor.pos() + 1);
932 cursor.par(cursor.par()->next());
936 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->next());
938 // we have to reset the selection, because the
939 // geometry could have changed
940 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
942 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
943 ClearSelection(bview);
945 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
946 tmpcursor.boundary());
950 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
952 Row * tmprow = cur.row();
953 int y = cur.y() - tmprow->baseline();
955 SetHeightOfRow(bview, tmprow);
957 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
959 LyXParagraph * first_phys_par = tmprow->par();
961 // find the first row of the paragraph
962 if (first_phys_par != tmprow->par())
963 while (tmprow->previous()
964 && tmprow->previous()->par() != first_phys_par) {
965 tmprow = tmprow->previous();
966 y -= tmprow->height();
967 SetHeightOfRow(bview, tmprow);
969 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
970 tmprow = tmprow->previous();
971 y -= tmprow->height();
972 SetHeightOfRow(bview, tmprow);
975 // we can set the refreshing parameters now
976 status = LyXText::NEED_MORE_REFRESH;
978 refresh_row = tmprow;
979 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
983 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
985 Row * tmprow = cur.row();
987 int y = cur.y() - tmprow->baseline();
988 SetHeightOfRow(bview, tmprow);
990 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
992 LyXParagraph * first_phys_par = tmprow->par();
994 // find the first row of the paragraph
995 if (first_phys_par != tmprow->par())
996 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
997 tmprow = tmprow->previous();
998 y -= tmprow->height();
1000 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
1001 tmprow = tmprow->previous();
1002 y -= tmprow->height();
1005 // we can set the refreshing parameters now
1006 if (status == LyXText::UNCHANGED || y < refresh_y) {
1008 refresh_row = tmprow;
1010 status = LyXText::NEED_MORE_REFRESH;
1011 SetCursor(bview, cur.par(), cur.pos());
1015 /* deletes and inserts again all paragaphs between the cursor
1016 * and the specified par
1017 * This function is needed after SetLayout and SetFont etc. */
1018 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
1019 LyXParagraph const * endpar) const
1022 LyXParagraph * tmppar = 0, * first_phys_par = 0;
1024 Row * tmprow = cur.row();
1026 int y = cur.y() - tmprow->baseline();
1028 if (!tmprow->previous()){
1029 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
1032 first_phys_par = tmprow->par()->FirstPhysicalPar();
1034 first_phys_par = tmprow->par();
1036 // find the first row of the paragraph
1037 if (first_phys_par != tmprow->par())
1038 while (tmprow->previous() &&
1039 (tmprow->previous()->par() != first_phys_par)) {
1040 tmprow = tmprow->previous();
1041 y -= tmprow->height();
1043 while (tmprow->previous()
1044 && tmprow->previous()->par() == first_phys_par) {
1045 tmprow = tmprow->previous();
1046 y -= tmprow->height();
1050 // we can set the refreshing parameters now
1051 status = LyXText::NEED_MORE_REFRESH;
1053 refresh_row = tmprow->previous(); /* the real refresh row will
1054 be deleted, so I store
1055 the previous here */
1058 tmppar = tmprow->next()->par();
1061 while (tmppar != endpar) {
1062 RemoveRow(tmprow->next());
1064 tmppar = tmprow->next()->par();
1069 // remove the first one
1070 tmprow2 = tmprow; /* this is because tmprow->previous()
1072 tmprow = tmprow->previous();
1075 tmppar = first_phys_par;
1079 InsertParagraph(bview, tmppar, tmprow);
1082 while (tmprow->next() && tmprow->next()->par() == tmppar)
1083 tmprow = tmprow->next();
1084 tmppar = tmppar->next();
1086 } while (tmppar != endpar);
1088 // this is because of layout changes
1090 refresh_y -= refresh_row->height();
1091 SetHeightOfRow(bview, refresh_row);
1093 refresh_row = firstrow;
1095 SetHeightOfRow(bview, refresh_row);
1098 if (tmprow && tmprow->next())
1099 SetHeightOfRow(bview, tmprow->next());
1103 bool LyXText::FullRebreak(BufferView * bview)
1109 if (need_break_row) {
1110 BreakAgain(bview, need_break_row);
1118 /* important for the screen */
1121 /* the cursor set functions have a special mechanism. When they
1122 * realize, that you left an empty paragraph, they will delete it.
1123 * They also delete the corresponding row */
1125 // need the selection cursor:
1126 void LyXText::SetSelection(BufferView * bview)
1128 const bool lsel = selection;
1131 last_sel_cursor = sel_cursor;
1132 sel_start_cursor = sel_cursor;
1133 sel_end_cursor = sel_cursor;
1138 // first the toggling area
1139 if (cursor.y() < last_sel_cursor.y()
1140 || (cursor.y() == last_sel_cursor.y()
1141 && cursor.x() < last_sel_cursor.x())) {
1142 toggle_end_cursor = last_sel_cursor;
1143 toggle_cursor = cursor;
1145 toggle_end_cursor = cursor;
1146 toggle_cursor = last_sel_cursor;
1149 last_sel_cursor = cursor;
1151 // and now the whole selection
1153 if (sel_cursor.par() == cursor.par())
1154 if (sel_cursor.pos() < cursor.pos()) {
1155 sel_end_cursor = cursor;
1156 sel_start_cursor = sel_cursor;
1158 sel_end_cursor = sel_cursor;
1159 sel_start_cursor = cursor;
1161 else if (sel_cursor.y() < cursor.y() ||
1162 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1163 sel_end_cursor = cursor;
1164 sel_start_cursor = sel_cursor;
1167 sel_end_cursor = sel_cursor;
1168 sel_start_cursor = cursor;
1171 // a selection with no contents is not a selection
1172 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1173 sel_start_cursor.pos() == sel_end_cursor.pos())
1176 if (inset_owner && (selection || lsel))
1177 inset_owner->SetUpdateStatus(bview, InsetText::SELECTION);
1181 string const LyXText::selectionAsString(Buffer const * buffer) const
1183 if (!selection) return string();
1186 // Special handling if the whole selection is within one paragraph
1187 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1188 result += sel_start_cursor.par()->String(buffer,
1189 sel_start_cursor.pos(),
1190 sel_end_cursor.pos());
1194 // The selection spans more than one paragraph
1196 // First paragraph in selection
1198 result += sel_start_cursor.par()->String(buffer,
1199 sel_start_cursor.pos(),
1200 sel_start_cursor.par()->Last())
1203 result += sel_start_cursor.par()->String(buffer,
1204 sel_start_cursor.pos(),
1205 sel_start_cursor.par()->size())
1209 // The paragraphs in between (if any)
1210 LyXCursor tmpcur(sel_start_cursor);
1211 tmpcur.par(tmpcur.par()->next());
1212 while (tmpcur.par() != sel_end_cursor.par()) {
1214 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1216 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->size()) + "\n\n";
1218 tmpcur.par(tmpcur.par()->next()); // Or NextAfterFootnote??
1221 // Last paragraph in selection
1222 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1228 void LyXText::ClearSelection(BufferView * /*bview*/) const
1235 void LyXText::CursorHome(BufferView * bview) const
1237 SetCursor(bview, cursor.par(), cursor.row()->pos());
1241 void LyXText::CursorEnd(BufferView * bview) const
1243 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1244 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1247 if (cursor.par()->Last() &&
1249 if (cursor.par()->size() &&
1251 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1252 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1253 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1255 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1260 void LyXText::CursorTop(BufferView * bview) const
1262 while (cursor.par()->previous())
1263 cursor.par(cursor.par()->previous());
1264 SetCursor(bview, cursor.par(), 0);
1268 void LyXText::CursorBottom(BufferView * bview) const
1270 while (cursor.par()->next())
1271 cursor.par(cursor.par()->next());
1273 SetCursor(bview, cursor.par(), cursor.par()->Last());
1275 SetCursor(bview, cursor.par(), cursor.par()->size());
1280 /* returns a pointer to the row near the specified y-coordinate
1281 * (relative to the whole text). y is set to the real beginning
1283 Row * LyXText::GetRowNearY(int & y) const
1285 Row * tmprow = firstrow;
1288 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1289 tmpy += tmprow->height();
1290 tmprow = tmprow->next();
1293 y = tmpy; // return the real y
1298 void LyXText::ToggleFree(BufferView * bview,
1299 LyXFont const & font, bool toggleall)
1301 // If the mask is completely neutral, tell user
1302 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1303 // Could only happen with user style
1304 bview->owner()->getMiniBuffer()
1305 ->Set(_("No font change defined. Use Character under"
1306 " the Layout menu to define font change."));
1310 // Try implicit word selection
1311 // If there is a change in the language the implicit word selection
1313 LyXCursor resetCursor = cursor;
1314 bool implicitSelection = (font.language() == ignore_language
1315 && font.number() == LyXFont::IGNORE)
1316 ? SelectWordWhenUnderCursor(bview) : false;
1319 SetFont(bview, font, toggleall);
1321 /* Implicit selections are cleared afterwards and cursor is set to the
1322 original position. */
1323 if (implicitSelection) {
1324 ClearSelection(bview);
1325 cursor = resetCursor;
1326 SetCursor(bview, cursor.par(), cursor.pos());
1327 sel_cursor = cursor;
1330 inset_owner->SetUpdateStatus(bview, InsetText::CURSOR_PAR);
1334 LyXParagraph::size_type
1335 LyXText::BeginningOfMainBody(Buffer const * buf,
1336 LyXParagraph const * par) const
1338 if (textclasslist.Style(buf->params.textclass,
1339 par->GetLayout()).labeltype != LABEL_MANUAL)
1342 return par->BeginningOfMainBody();
1347 /* if there is a selection, reset every environment you can find
1348 * in the selection, otherwise just the environment you are in */
1349 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1351 LyXParagraph * tmppar, * firsttmppar;
1353 ClearSelection(bview);
1355 /* is is only allowed, if the cursor is IN an open footnote.
1356 * Otherwise it is too dangerous */
1357 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1360 SetUndo(bview->buffer(), Undo::FINISH,
1361 cursor.par()->PreviousBeforeFootnote()->previous_,
1362 cursor.par()->NextAfterFootnote()->next_);
1364 /* ok, move to the beginning of the footnote. */
1365 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1366 cursor.par(cursor.par()->previous());
1368 SetCursor(bview, cursor.par(), cursor.par()->Last());
1369 /* this is just faster than using CursorLeft(); */
1371 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1372 tmppar = firsttmppar;
1373 /* tmppar is now the paragraph right before the footnote */
1375 bool first_footnote_par_is_not_empty = tmppar->next_->size();
1377 while (tmppar->next_
1378 && tmppar->next_->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1379 tmppar = tmppar->next_; /* I use next instead of Next(),
1380 * because there cannot be any
1381 * footnotes in a footnote
1383 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1385 /* remember the captions and empty paragraphs */
1386 if ((textclasslist.Style(bview->buffer()->params.textclass,
1387 tmppar->GetLayout())
1388 .labeltype == LABEL_SENSITIVE)
1390 tmppar->SetLayout(bview->buffer()->params, 0);
1393 // now we will paste the ex-footnote, if the layouts allow it
1394 // first restore the layout of the paragraph right behind
1397 tmppar->next_->MakeSameLayout(cursor.par());
1400 if (!tmppar->GetLayout()
1402 && (!tmppar->next()->Last()
1403 || tmppar->next()->HasSameLayout(tmppar)))) {
1404 if (tmppar->next()->Last()
1405 && tmppar->next()->IsLineSeparator(0))
1406 tmppar->next()->Erase(0);
1407 tmppar->PasteParagraph(bview->buffer()->params);
1410 tmppar = tmppar->next(); /* make sure tmppar cannot be touched
1411 * by the pasting of the beginning */
1413 /* then the beginning */
1414 /* if there is no space between the text and the footnote, so we insert
1416 * (only if the previous par and the footnotepar are not empty!) */
1417 if (!firsttmppar->next_->GetLayout()
1418 || firsttmppar->HasSameLayout(firsttmppar->next_)) {
1419 if (firsttmppar->size()
1420 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1421 && first_footnote_par_is_not_empty) {
1422 firsttmppar->next_->InsertChar(0, ' ');
1424 firsttmppar->PasteParagraph(bview->buffer()->params);
1427 /* now redo the paragaphs */
1428 RedoParagraphs(bview, cursor, tmppar);
1430 SetCursor(bview, cursor.par(), cursor.pos());
1432 /* sometimes it can happen, that there is a counter change */
1433 Row * row = cursor.row();
1434 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1436 UpdateCounters(bview, row);
1439 ClearSelection(bview);
1444 /* the DTP switches for paragraphs. LyX will store them in the
1445 * first physicla paragraph. When a paragraph is broken, the top settings
1446 * rest, the bottom settings are given to the new one. So I can make shure,
1447 * they do not duplicate themself and you cannnot make dirty things with
1450 void LyXText::SetParagraph(BufferView * bview,
1451 bool line_top, bool line_bottom,
1452 bool pagebreak_top, bool pagebreak_bottom,
1453 VSpace const & space_top,
1454 VSpace const & space_bottom,
1456 string labelwidthstring,
1459 LyXCursor tmpcursor = cursor;
1461 sel_start_cursor = cursor;
1462 sel_end_cursor = cursor;
1465 // make sure that the depth behind the selection are restored, too
1467 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
1469 LyXParagraph * endpar = sel_end_cursor.par()->next();
1471 LyXParagraph * undoendpar = endpar;
1473 if (endpar && endpar->GetDepth()) {
1474 while (endpar && endpar->GetDepth()) {
1476 endpar = endpar->LastPhysicalPar()->next();
1478 endpar = endpar->next();
1480 undoendpar = endpar;
1484 endpar = endpar->next(); // because of parindents etc.
1487 SetUndo(bview->buffer(), Undo::EDIT,
1490 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
1492 sel_start_cursor.par()->previous(),
1497 LyXParagraph * tmppar = sel_end_cursor.par();
1499 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->previous()) {
1500 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1502 while (tmppar != sel_start_cursor.par()->previous()) {
1503 SetCursor(bview, tmppar, 0);
1505 status = LyXText::NEED_MORE_REFRESH;
1506 refresh_row = cursor.row();
1507 refresh_y = cursor.y() - cursor.row()->baseline();
1509 if (cursor.par()->footnoteflag ==
1510 sel_start_cursor.par()->footnoteflag) {
1512 cursor.par()->params.lineTop(line_top);
1513 cursor.par()->params.lineBottom(line_bottom);
1514 cursor.par()->params.pagebreakTop(pagebreak_top);
1515 cursor.par()->params.pagebreakBottom(pagebreak_bottom);
1516 cursor.par()->params.spaceTop(space_top);
1517 cursor.par()->params.spaceBottom(space_bottom);
1518 // does the layout allow the new alignment?
1519 if (align == LYX_ALIGN_LAYOUT)
1520 align = textclasslist
1521 .Style(bview->buffer()->params.textclass,
1522 cursor.par()->GetLayout()).align;
1523 if (align & textclasslist
1524 .Style(bview->buffer()->params.textclass,
1525 cursor.par()->GetLayout()).alignpossible) {
1526 if (align == textclasslist
1527 .Style(bview->buffer()->params.textclass,
1528 cursor.par()->GetLayout()).align)
1529 cursor.par()->params.align(LYX_ALIGN_LAYOUT);
1531 cursor.par()->params.align(align);
1533 cursor.par()->SetLabelWidthString(labelwidthstring);
1534 cursor.par()->params.noindent(noindent);
1538 tmppar = cursor.par()->FirstPhysicalPar()->previous();
1540 tmppar = cursor.par()->previous();
1544 RedoParagraphs(bview, sel_start_cursor, endpar);
1546 ClearSelection(bview);
1547 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1548 sel_cursor = cursor;
1549 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1550 SetSelection(bview);
1551 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1553 bview->updateInset(inset_owner, true);
1557 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1558 string const & width,
1559 string const & widthp,
1560 int alignment, bool hfill,
1561 bool start_minipage)
1563 LyXCursor tmpcursor = cursor;
1564 LyXParagraph * tmppar;
1566 sel_start_cursor = cursor;
1567 sel_end_cursor = cursor;
1570 // make sure that the depth behind the selection are restored, too
1572 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
1574 LyXParagraph * endpar = sel_end_cursor.par()->next();
1576 LyXParagraph * undoendpar = endpar;
1578 if (endpar && endpar->GetDepth()) {
1579 while (endpar && endpar->GetDepth()) {
1581 endpar = endpar->LastPhysicalPar()->next();
1583 endpar = endpar->next();
1585 undoendpar = endpar;
1589 endpar = endpar->next(); // because of parindents etc.
1592 SetUndo(bview->buffer(), Undo::EDIT,
1595 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
1597 sel_start_cursor.par()->previous(),
1601 tmppar = sel_end_cursor.par();
1603 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->previous()) {
1604 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1606 while(tmppar != sel_start_cursor.par()->previous()) {
1607 SetCursor(bview, tmppar, 0);
1609 status = LyXText::NEED_MORE_REFRESH;
1610 refresh_row = cursor.row();
1611 refresh_y = cursor.y() - cursor.row()->baseline();
1613 if (cursor.par()->footnoteflag ==
1614 sel_start_cursor.par()->footnoteflag) {
1616 if (type == LyXParagraph::PEXTRA_NONE) {
1617 if (cursor.par()->params.pextraType() != LyXParagraph::PEXTRA_NONE) {
1618 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1619 cursor.par()->params.pextraType(LyXParagraph::PEXTRA_NONE);
1622 cursor.par()->SetPExtraType(bview->buffer()->params,
1623 type, width, widthp);
1624 cursor.par()->params.pextraHfill(hfill);
1625 cursor.par()->params.pextraStartMinipage(start_minipage);
1626 cursor.par()->params.pextraAlignment(alignment);
1630 tmppar = cursor.par()->FirstPhysicalPar()->previous();
1632 tmppar = cursor.par()->previous();
1635 RedoParagraphs(bview, sel_start_cursor, endpar);
1636 ClearSelection(bview);
1637 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1638 sel_cursor = cursor;
1639 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1640 SetSelection(bview);
1641 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1645 char loweralphaCounter(int n)
1647 if (n < 1 || n > 26)
1655 char alphaCounter(int n)
1657 if (n < 1 || n > 26)
1665 char hebrewCounter(int n)
1667 static const char hebrew[22] = {
1668 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1669 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1670 '÷', 'ø', 'ù', 'ú'
1672 if (n < 1 || n > 22)
1680 string const romanCounter(int n)
1682 static char const * roman[20] = {
1683 "i", "ii", "iii", "iv", "v",
1684 "vi", "vii", "viii", "ix", "x",
1685 "xi", "xii", "xiii", "xiv", "xv",
1686 "xvi", "xvii", "xviii", "xix", "xx"
1688 if (n < 1 || n > 20)
1695 // set the counter of a paragraph. This includes the labels
1696 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1699 // this is only relevant for the beginning of paragraph
1700 par = par->FirstPhysicalPar();
1702 LyXLayout const & layout =
1703 textclasslist.Style(buf->params.textclass,
1706 LyXTextClass const & textclass =
1707 textclasslist.TextClass(buf->params.textclass);
1709 /* copy the prev-counters to this one, unless this is the start of a
1710 footnote or of a bibliography or the very first paragraph */
1713 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1714 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1715 && par->footnotekind == LyXParagraph::FOOTNOTE)
1717 && !(textclasslist.Style(buf->params.textclass,
1718 par->previous()->GetLayout()
1719 ).labeltype != LABEL_BIBLIO
1720 && layout.labeltype == LABEL_BIBLIO)) {
1721 for (int i = 0; i < 10; ++i) {
1722 par->setCounter(i, par->previous()->GetFirstCounter(i));
1725 par->params.appendix(par->previous()->FirstPhysicalPar()->params.appendix());
1727 par->params.appendix(par->previous()->params.appendix());
1729 if (!par->params.appendix() && par->params.startOfAppendix()) {
1730 par->params.appendix(true);
1731 for (int i = 0; i < 10; ++i) {
1732 par->setCounter(i, 0);
1736 par->enumdepth = par->previous()->FirstPhysicalPar()->enumdepth;
1737 par->itemdepth = par->previous()->FirstPhysicalPar()->itemdepth;
1739 par->enumdepth = par->previous()->enumdepth;
1740 par->itemdepth = par->previous()->itemdepth;
1743 for (int i = 0; i < 10; ++i) {
1744 par->setCounter(i, 0);
1746 par->params.appendix(par->params.startOfAppendix());
1752 // if this is an open marginnote and this is the first
1753 // entry in the marginnote and the enclosing
1754 // environment is an enum/item then correct for the
1755 // LaTeX behaviour (ARRae)
1756 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1757 && par->footnotekind == LyXParagraph::MARGIN
1759 && par->previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1760 && (par->PreviousBeforeFootnote()
1761 && textclasslist.Style(buf->params.textclass,
1762 par->PreviousBeforeFootnote()->GetLayout()
1763 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1764 // Any itemize or enumerate environment in a marginnote
1765 // that is embedded in an itemize or enumerate
1766 // paragraph is seen by LaTeX as being at a deeper
1767 // level within that enclosing itemization/enumeration
1768 // even if there is a "standard" layout at the start of
1774 /* Maybe we have to increment the enumeration depth.
1775 * BUT, enumeration in a footnote is considered in isolation from its
1776 * surrounding paragraph so don't increment if this is the
1777 * first line of the footnote
1778 * AND, bibliographies can't have their depth changed ie. they
1779 * are always of depth 0
1782 && par->previous()->GetDepth() < par->GetDepth()
1783 && textclasslist.Style(buf->params.textclass,
1784 par->previous()->GetLayout()
1785 ).labeltype == LABEL_COUNTER_ENUMI
1786 && par->enumdepth < 3
1788 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1789 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1790 && par->footnotekind == LyXParagraph::FOOTNOTE)
1792 && layout.labeltype != LABEL_BIBLIO) {
1796 /* Maybe we have to decrement the enumeration depth, see note above */
1798 && par->previous()->GetDepth() > par->GetDepth()
1800 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1801 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1802 && par->footnotekind == LyXParagraph::FOOTNOTE)
1804 && layout.labeltype != LABEL_BIBLIO) {
1805 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1806 par->setCounter(6 + par->enumdepth,
1807 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1808 /* reset the counters.
1809 * A depth change is like a breaking layout
1811 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1812 par->setCounter(i, 0);
1815 if (!par->params.labelString().empty()) {
1816 par->params.labelString(string());
1819 if (layout.margintype == MARGIN_MANUAL) {
1820 if (par->params.labelWidthString().empty()) {
1821 par->SetLabelWidthString(layout.labelstring());
1824 par->SetLabelWidthString(string());
1827 /* is it a layout that has an automatic label ? */
1828 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1830 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1831 if (i >= 0 && i<= buf->params.secnumdepth) {
1832 par->incCounter(i); // increment the counter
1834 // Is there a label? Useful for Chapter layout
1835 if (!par->params.appendix()) {
1836 if (!layout.labelstring().empty())
1837 par->params.labelString(layout.labelstring());
1839 par->params.labelString(string());
1841 if (!layout.labelstring_appendix().empty())
1842 par->params.labelString(layout.labelstring_appendix());
1844 par->params.labelString(string());
1847 std::ostringstream s;
1849 if (!par->params.appendix()) {
1850 switch (2 * LABEL_COUNTER_CHAPTER -
1851 textclass.maxcounter() + i) {
1852 case LABEL_COUNTER_CHAPTER:
1853 s << par->getCounter(i);
1855 case LABEL_COUNTER_SECTION:
1856 s << par->getCounter(i - 1) << '.'
1857 << par->getCounter(i);
1859 case LABEL_COUNTER_SUBSECTION:
1860 s << par->getCounter(i - 2) << '.'
1861 << par->getCounter(i - 1) << '.'
1862 << par->getCounter(i);
1864 case LABEL_COUNTER_SUBSUBSECTION:
1865 s << par->getCounter(i - 3) << '.'
1866 << par->getCounter(i - 2) << '.'
1867 << par->getCounter(i - 1) << '.'
1868 << par->getCounter(i);
1871 case LABEL_COUNTER_PARAGRAPH:
1872 s << par->getCounter(i - 4) << '.'
1873 << par->getCounter(i - 3) << '.'
1874 << par->getCounter(i - 2) << '.'
1875 << par->getCounter(i - 1) << '.'
1876 << par->getCounter(i);
1878 case LABEL_COUNTER_SUBPARAGRAPH:
1879 s << par->getCounter(i - 5) << '.'
1880 << par->getCounter(i - 4) << '.'
1881 << par->getCounter(i - 3) << '.'
1882 << par->getCounter(i - 2) << '.'
1883 << par->getCounter(i - 1) << '.'
1884 << par->getCounter(i);
1888 // Can this ever be reached? And in the
1889 // case it is, how can this be correct?
1891 s << par->getCounter(i) << '.';
1894 } else { // appendix
1895 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1896 case LABEL_COUNTER_CHAPTER:
1897 if (par->isRightToLeftPar(buf->params))
1898 s << hebrewCounter(par->getCounter(i));
1900 s << alphaCounter(par->getCounter(i));
1902 case LABEL_COUNTER_SECTION:
1903 if (par->isRightToLeftPar(buf->params))
1904 s << hebrewCounter(par->getCounter(i - 1));
1906 s << alphaCounter(par->getCounter(i - 1));
1909 << par->getCounter(i);
1912 case LABEL_COUNTER_SUBSECTION:
1913 if (par->isRightToLeftPar(buf->params))
1914 s << hebrewCounter(par->getCounter(i - 2));
1916 s << alphaCounter(par->getCounter(i - 2));
1919 << par->getCounter(i-1) << '.'
1920 << par->getCounter(i);
1923 case LABEL_COUNTER_SUBSUBSECTION:
1924 if (par->isRightToLeftPar(buf->params))
1925 s << hebrewCounter(par->getCounter(i-3));
1927 s << alphaCounter(par->getCounter(i-3));
1930 << par->getCounter(i-2) << '.'
1931 << par->getCounter(i-1) << '.'
1932 << par->getCounter(i);
1935 case LABEL_COUNTER_PARAGRAPH:
1936 if (par->isRightToLeftPar(buf->params))
1937 s << hebrewCounter(par->getCounter(i-4));
1939 s << alphaCounter(par->getCounter(i-4));
1942 << par->getCounter(i-3) << '.'
1943 << par->getCounter(i-2) << '.'
1944 << par->getCounter(i-1) << '.'
1945 << par->getCounter(i);
1948 case LABEL_COUNTER_SUBPARAGRAPH:
1949 if (par->isRightToLeftPar(buf->params))
1950 s << hebrewCounter(par->getCounter(i-5));
1952 s << alphaCounter(par->getCounter(i-5));
1955 << par->getCounter(i-4) << '.'
1956 << par->getCounter(i-3) << '.'
1957 << par->getCounter(i-2) << '.'
1958 << par->getCounter(i-1) << '.'
1959 << par->getCounter(i);
1963 // Can this ever be reached? And in the
1964 // case it is, how can this be correct?
1966 s << par->getCounter(i) << '.';
1972 par->params.labelString(par->params.labelString() +s.str().c_str());
1973 // We really want to remove the c_str as soon as
1976 for (i++; i < 10; ++i) {
1977 // reset the following counters
1978 par->setCounter(i, 0);
1980 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1981 for (i++; i < 10; ++i) {
1982 // reset the following counters
1983 par->setCounter(i, 0);
1985 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1986 par->incCounter(i + par->enumdepth);
1987 int number = par->getCounter(i + par->enumdepth);
1989 std::ostringstream s;
1991 switch (par->enumdepth) {
1993 if (par->isRightToLeftPar(buf->params))
1995 << hebrewCounter(number)
1999 << loweralphaCounter(number)
2003 if (par->isRightToLeftPar(buf->params))
2004 s << '.' << romanCounter(number);
2006 s << romanCounter(number) << '.';
2009 if (par->isRightToLeftPar(buf->params))
2011 << alphaCounter(number);
2013 s << alphaCounter(number)
2017 if (par->isRightToLeftPar(buf->params))
2024 par->params.labelString(s.str().c_str());
2025 // we really want to get rid of that c_str()
2027 for (i += par->enumdepth + 1; i < 10; ++i)
2028 par->setCounter(i, 0); /* reset the following counters */
2031 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2032 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2034 int number = par->getCounter(i);
2036 InsetCommandParams p( "bibitem" );
2037 par->bibkey = new InsetBibKey(p);
2039 par->bibkey->setCounter(number);
2040 par->params.labelString(layout.labelstring());
2042 // In biblio should't be following counters but...
2044 string s = layout.labelstring();
2046 // the caption hack:
2047 if (layout.labeltype == LABEL_SENSITIVE) {
2048 bool isOK (par->InInset() && par->InInset()->owner() &&
2049 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2051 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2052 && (par->footnotekind == LyXParagraph::FIG
2053 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2054 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2055 ? ":øåéà " : "Figure:";
2056 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2057 && (par->footnotekind == LyXParagraph::TAB
2058 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2059 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2060 ? ":äìáè" : "Table:";
2061 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2062 && par->footnotekind == LyXParagraph::ALGORITHM) {
2063 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2064 ? ":Ãúéøåâìà " : "Algorithm:";
2068 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2070 = floatList.getType(tmp->type());
2071 // We should get the correct number here too.
2072 s = fl.name() + " #:";
2074 /* par->SetLayout(0);
2075 s = layout->labelstring; */
2076 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2077 ? " :úåòîùî øñç" : "Senseless: ";
2080 par->params.labelString(s);
2082 /* reset the enumeration counter. They are always resetted
2083 * when there is any other layout between */
2084 for (int i = 6 + par->enumdepth; i < 10; ++i)
2085 par->setCounter(i, 0);
2090 /* Updates all counters BEHIND the row. Changed paragraphs
2091 * with a dynamic left margin will be rebroken. */
2092 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2099 } else if (row->par()->next_
2100 && row->par()->next_->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
2101 par = row->par()->LastPhysicalPar()->next();
2103 par = row->par()->next_;
2110 par = row->par()->next();
2115 while (row->par() != par)
2118 SetCounter(bview->buffer(), par);
2120 /* now check for the headline layouts. remember that they
2121 * have a dynamic left margin */
2126 ( textclasslist.Style(bview->buffer()->params.textclass,
2127 par->layout).margintype == MARGIN_DYNAMIC
2128 || textclasslist.Style(bview->buffer()->params.textclass,
2129 par->layout).labeltype == LABEL_SENSITIVE)
2132 /* Rebreak the paragraph */
2133 RemoveParagraph(row);
2134 AppendParagraph(bview, row);
2137 /* think about the damned open footnotes! */
2138 while (par->next() &&
2139 (par->next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2140 || par->next()->IsDummy())){
2142 if (par->IsDummy()) {
2143 while (row->par() != par)
2145 RemoveParagraph(row);
2146 AppendParagraph(bview, row);
2152 par = par->LastPhysicalPar()->next();
2161 /* insets an inset. */
2162 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2164 if (!cursor.par()->InsertInsetAllowed(inset))
2166 SetUndo(bview->buffer(), Undo::INSERT,
2168 cursor.par()->ParFromPos(cursor.pos())->previous_,
2169 cursor.par()->ParFromPos(cursor.pos())->next_
2171 cursor.par()->previous(),
2172 cursor.par()->next()
2175 cursor.par()->InsertInset(cursor.pos(), inset);
2176 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2177 * The character will not be inserted a
2180 // If we enter a highly editable inset the cursor should be to before
2181 // the inset. This couldn't happen before as Undo was not handled inside
2182 // inset now after the Undo LyX tries to call inset->Edit(...) again
2183 // and cannot do this as the cursor is behind the inset and GetInset
2184 // does not return the inset!
2185 if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
2186 CursorLeft(bview, true);
2192 void LyXText::copyEnvironmentType()
2194 copylayouttype = cursor.par()->GetLayout();
2198 void LyXText::pasteEnvironmentType(BufferView * bview)
2200 SetLayout(bview, copylayouttype);
2204 void LyXText::CutSelection(BufferView * bview, bool doclear)
2206 // Stuff what we got on the clipboard. Even if there is no selection.
2208 // There is a problem with having the stuffing here in that the
2209 // larger the selection the slower LyX will get. This can be
2210 // solved by running the line below only when the selection has
2211 // finished. The solution used currently just works, to make it
2212 // faster we need to be more clever and probably also have more
2213 // calls to stuffClipboard. (Lgb)
2214 bview->stuffClipboard(selectionAsString(bview->buffer()));
2216 // This doesn't make sense, if there is no selection
2220 // OK, we have a selection. This is always between sel_start_cursor
2221 // and sel_end_cursor
2223 // Check whether there are half footnotes in the selection
2224 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2225 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2226 LyXParagraph * tmppar = sel_start_cursor.par();
2227 while (tmppar != sel_end_cursor.par()){
2228 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2229 WriteAlert(_("Impossible operation"),
2230 _("Don't know what to do with half floats."),
2234 tmppar = tmppar->next();
2239 // make sure that the depth behind the selection are restored, too
2241 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
2243 LyXParagraph * endpar = sel_end_cursor.par()->next();
2245 LyXParagraph * undoendpar = endpar;
2247 if (endpar && endpar->GetDepth()) {
2248 while (endpar && endpar->GetDepth()) {
2250 endpar = endpar->LastPhysicalPar()->next();
2252 endpar = endpar->next();
2254 undoendpar = endpar;
2256 } else if (endpar) {
2257 endpar = endpar->next(); // because of parindents etc.
2260 SetUndo(bview->buffer(), Undo::DELETE,
2263 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
2265 sel_start_cursor.par()->previous(),
2271 // there are two cases: cut only within one paragraph or
2272 // more than one paragraph
2274 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2275 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2277 if (sel_start_cursor.par() == sel_end_cursor.par())
2280 // only within one paragraph
2281 endpar = sel_start_cursor.par();
2282 int pos = sel_end_cursor.pos();
2283 cap.cutSelection(sel_start_cursor.par(), &endpar,
2284 sel_start_cursor.pos(), pos,
2285 bview->buffer()->params.textclass, doclear);
2286 sel_end_cursor.pos(pos);
2288 endpar = sel_end_cursor.par();
2290 int pos = sel_end_cursor.pos();
2291 cap.cutSelection(sel_start_cursor.par(), &endpar,
2292 sel_start_cursor.pos(), pos,
2293 bview->buffer()->params.textclass, doclear);
2295 sel_end_cursor.par(endpar);
2296 sel_end_cursor.pos(pos);
2297 cursor.pos(sel_end_cursor.pos());
2299 endpar = endpar->next();
2301 // sometimes necessary
2303 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2305 RedoParagraphs(bview, sel_start_cursor, endpar);
2307 ClearSelection(bview);
2308 cursor = sel_start_cursor;
2309 SetCursor(bview, cursor.par(), cursor.pos());
2310 sel_cursor = cursor;
2311 UpdateCounters(bview, cursor.row());
2315 void LyXText::CopySelection(BufferView * bview)
2317 // Stuff what we got on the clipboard. Even if there is no selection.
2319 // There is a problem with having the stuffing here in that the
2320 // larger the selection the slower LyX will get. This can be
2321 // solved by running the line below only when the selection has
2322 // finished. The solution used currently just works, to make it
2323 // faster we need to be more clever and probably also have more
2324 // calls to stuffClipboard. (Lgb)
2325 bview->stuffClipboard(selectionAsString(bview->buffer()));
2327 // this doesnt make sense, if there is no selection
2331 // ok we have a selection. This is always between sel_start_cursor
2332 // and sel_end cursor
2335 /* check wether there are half footnotes in the selection */
2336 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2337 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2338 LyXParagraph * tmppar = sel_start_cursor.par();
2339 while (tmppar != sel_end_cursor.par()) {
2340 if (tmppar->footnoteflag !=
2341 sel_end_cursor.par()->footnoteflag) {
2342 WriteAlert(_("Impossible operation"),
2343 _("Don't know what to do"
2344 " with half floats."),
2348 tmppar = tmppar->next();
2353 // copy behind a space if there is one
2355 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2357 while (sel_start_cursor.par()->size() > sel_start_cursor.pos()
2359 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2360 && (sel_start_cursor.par() != sel_end_cursor.par()
2361 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2362 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2366 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2367 sel_start_cursor.pos(), sel_end_cursor.pos(),
2368 bview->buffer()->params.textclass);
2372 void LyXText::PasteSelection(BufferView * bview)
2376 // this does not make sense, if there is nothing to paste
2377 if (!cap.checkPastePossible(cursor.par()))
2380 SetUndo(bview->buffer(), Undo::INSERT,
2382 cursor.par()->ParFromPos(cursor.pos())->previous_,
2383 cursor.par()->ParFromPos(cursor.pos())->next_
2385 cursor.par()->previous(),
2386 cursor.par()->next()
2390 LyXParagraph * endpar;
2391 LyXParagraph * actpar = cursor.par();
2393 int pos = cursor.pos();
2394 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2396 RedoParagraphs(bview, cursor, endpar);
2398 SetCursor(bview, cursor.par(), cursor.pos());
2399 ClearSelection(bview);
2401 sel_cursor = cursor;
2402 SetCursor(bview, actpar, pos);
2403 SetSelection(bview);
2404 UpdateCounters(bview, cursor.row());
2408 // returns a pointer to the very first LyXParagraph
2409 LyXParagraph * LyXText::FirstParagraph() const
2411 return OwnerParagraph();
2415 // sets the selection over the number of characters of string, no check!!
2416 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2418 sel_cursor = cursor;
2419 for (int i = 0; str[i]; ++i)
2421 SetSelection(bview);
2425 // simple replacing. The font of the first selected character is used
2426 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2429 SetCursorParUndo(bview->buffer());
2432 if (!selection) { // create a dummy selection
2433 sel_end_cursor = cursor;
2434 sel_start_cursor = cursor;
2437 // Get font setting before we cut
2438 LyXParagraph::size_type pos = sel_end_cursor.pos();
2439 LyXFont const font = sel_start_cursor.par()
2440 ->GetFontSettings(bview->buffer()->params,
2441 sel_start_cursor.pos());
2443 // Insert the new string
2444 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2445 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2449 // Cut the selection
2450 CutSelection(bview);
2456 // needed to insert the selection
2457 void LyXText::InsertStringA(BufferView * bview, string const & str)
2459 LyXParagraph * par = cursor.par();
2460 LyXParagraph::size_type pos = cursor.pos();
2461 LyXParagraph::size_type a = 0;
2462 LyXParagraph * endpar = cursor.par()->next();
2464 SetCursorParUndo(bview->buffer());
2467 textclasslist.Style(bview->buffer()->params.textclass,
2468 cursor.par()->GetLayout()).isEnvironment();
2469 // only to be sure, should not be neccessary
2470 ClearSelection(bview);
2472 // insert the string, don't insert doublespace
2473 string::size_type i = 0;
2474 while (i < str.length()) {
2475 if (str[i] != '\n') {
2477 && i + 1 < str.length() && str[i + 1] != ' '
2478 && pos && par->GetChar(pos - 1)!= ' ') {
2479 par->InsertChar(pos, ' ', current_font);
2481 } else if (str[i] == ' ') {
2482 InsetSpecialChar * new_inset =
2483 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2484 if (par->InsertInsetAllowed(new_inset)) {
2485 par->InsertInset(pos, new_inset,
2491 } else if (str[i] == '\t') {
2492 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2493 InsetSpecialChar * new_inset =
2494 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2495 if (par->InsertInsetAllowed(new_inset)) {
2496 par->InsertInset(pos, new_inset,
2503 } else if (str[i] != 13 &&
2504 // Ignore unprintables
2505 (str[i] & 127) >= ' ') {
2506 par->InsertChar(pos, str[i], current_font);
2510 if (!par->size()) { // par is empty
2511 InsetSpecialChar * new_inset =
2512 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2513 if (par->InsertInsetAllowed(new_inset)) {
2514 par->InsertInset(pos,
2522 par->BreakParagraph(bview->buffer()->params, pos, flag);
2529 RedoParagraphs(bview, cursor, endpar);
2530 SetCursor(bview, cursor.par(), cursor.pos());
2531 sel_cursor = cursor;
2532 SetCursor(bview, par, pos);
2533 SetSelection(bview);
2537 /* turns double-CR to single CR, others where converted into one blank and 13s
2538 * that are ignored .Double spaces are also converted into one. Spaces at
2539 * the beginning of a paragraph are forbidden. tabs are converted into one
2540 * space. then InsertStringA is called */
2541 void LyXText::InsertStringB(BufferView * bview, string const & s)
2544 string::size_type i = 1;
2545 while (i < str.length()) {
2548 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2550 if (str[i] == '\n' && i + 1 < str.length()) {
2551 if (str[i + 1] != '\n') {
2552 if (str[i - 1] != ' ')
2557 while (i + 1 < str.length()
2558 && (str[i + 1] == ' '
2559 || str[i + 1] == '\t'
2560 || str[i + 1] == '\n'
2561 || str[i + 1] == 13)) {
2568 InsertStringA(bview, str);
2572 bool LyXText::GotoNextInset(BufferView * bview,
2573 std::vector<Inset::Code> const & codes,
2574 string const & contents) const
2576 LyXCursor res = cursor;
2580 if (res.pos() < res.par()->Last() - 1) {
2582 if (res.pos() < res.par()->size() - 1) {
2584 res.pos(res.pos() + 1);
2586 res.par(res.par()->next());
2590 } while (res.par() &&
2591 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2592 && (inset = res.par()->GetInset(res.pos())) != 0
2593 && find(codes.begin(), codes.end(), inset->LyxCode())
2595 && (contents.empty() ||
2596 static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
2600 SetCursor(bview, res.par(), res.pos());
2607 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2608 LyXParagraph::size_type pos)
2610 LyXCursor tmpcursor;
2613 LyXParagraph::size_type z;
2614 Row * row = GetRow(par, pos, y);
2616 // is there a break one row above
2617 if (row->previous() && row->previous()->par() == row->par()) {
2618 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2619 if (z >= row->pos()) {
2620 // set the dimensions of the row above
2621 y -= row->previous()->height();
2623 refresh_row = row->previous();
2624 status = LyXText::NEED_MORE_REFRESH;
2626 BreakAgain(bview, row->previous());
2628 // set the cursor again. Otherwise
2629 // dangling pointers are possible
2630 SetCursor(bview, cursor.par(), cursor.pos(),
2631 false, cursor.boundary());
2632 sel_cursor = cursor;
2637 int const tmpheight = row->height();
2638 LyXParagraph::size_type const tmplast = RowLast(row);
2642 BreakAgain(bview, row);
2643 if (row->height() == tmpheight && RowLast(row) == tmplast)
2644 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2646 status = LyXText::NEED_MORE_REFRESH;
2648 // check the special right address boxes
2649 if (textclasslist.Style(bview->buffer()->params.textclass,
2650 par->GetLayout()).margintype
2651 == MARGIN_RIGHT_ADDRESS_BOX) {
2658 RedoDrawingOfParagraph(bview, tmpcursor);
2661 // set the cursor again. Otherwise dangling pointers are possible
2662 // also set the selection
2666 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2667 false, sel_cursor.boundary());
2668 sel_cursor = cursor;
2669 SetCursorIntern(bview, sel_start_cursor.par(),
2670 sel_start_cursor.pos(),
2671 false, sel_start_cursor.boundary());
2672 sel_start_cursor = cursor;
2673 SetCursorIntern(bview, sel_end_cursor.par(),
2674 sel_end_cursor.pos(),
2675 false, sel_end_cursor.boundary());
2676 sel_end_cursor = cursor;
2677 SetCursorIntern(bview, last_sel_cursor.par(),
2678 last_sel_cursor.pos(),
2679 false, last_sel_cursor.boundary());
2680 last_sel_cursor = cursor;
2683 SetCursorIntern(bview, cursor.par(), cursor.pos(),
2684 false, cursor.boundary());
2688 // returns false if inset wasn't found
2689 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2691 // first check the current paragraph
2692 int pos = cursor.par()->GetPositionOfInset(inset);
2694 CheckParagraph(bview, cursor.par(), pos);
2698 // check every paragraph
2700 LyXParagraph * par = FirstParagraph();
2703 // make sure the paragraph is open
2704 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2706 pos = par->GetPositionOfInset(inset);
2708 CheckParagraph(bview, par, pos);
2721 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2722 LyXParagraph::size_type pos,
2723 bool setfont, bool boundary) const
2725 LyXCursor old_cursor = cursor;
2726 SetCursorIntern(bview, par, pos, setfont, boundary);
2727 DeleteEmptyParagraphMechanism(bview, old_cursor);
2731 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2732 LyXParagraph::size_type pos, bool boundary) const
2735 // correct the cursor position if impossible
2736 if (pos > par->Last()){
2737 LyXParagraph * tmppar = par->ParFromPos(pos);
2738 pos = par->PositionInParFromPos(pos);
2741 if (par->IsDummy() && par->previous_ &&
2742 par->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2743 while (par->previous_ &&
2744 ((par->previous_->IsDummy() &&
2745 (par->previous_->previous_->footnoteflag ==
2746 LyXParagraph::CLOSED_FOOTNOTE)) ||
2747 (par->previous_->footnoteflag ==
2748 LyXParagraph::CLOSED_FOOTNOTE))) {
2749 par = par->previous_;
2750 if (par->IsDummy() &&
2751 (par->previous_->footnoteflag ==
2752 LyXParagraph::CLOSED_FOOTNOTE))
2753 pos += par->size() + 1;
2755 if (par->previous_) {
2756 par = par->previous_;
2758 pos += par->size() + 1;
2763 cur.boundary(boundary);
2765 /* get the cursor y position in text */
2767 Row * row = GetRow(par, pos, y);
2768 /* y is now the beginning of the cursor row */
2769 y += row->baseline();
2770 /* y is now the cursor baseline */
2773 /* now get the cursors x position */
2775 float fill_separator, fill_hfill, fill_label_hfill;
2776 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2778 LyXParagraph::size_type cursor_vpos = 0;
2779 LyXParagraph::size_type last = RowLastPrintable(row);
2781 if (pos > last + 1) // This shouldn't happen.
2783 else if (pos < row->pos())
2786 if (last < row->pos())
2787 cursor_vpos = row->pos();
2788 else if (pos > last && !boundary)
2789 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2790 ? row->pos() : last + 1;
2791 else if (pos > row->pos() &&
2792 (pos > last || boundary))
2793 /// Place cursor after char at (logical) position pos - 1
2794 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2795 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2797 /// Place cursor before char at (logical) position pos
2798 cursor_vpos = (bidi_level(pos) % 2 == 0)
2799 ? log2vis(pos) : log2vis(pos) + 1;
2801 LyXParagraph::size_type main_body =
2802 BeginningOfMainBody(bview->buffer(), row->par());
2803 if ((main_body > 0) &&
2804 ((main_body-1 > last) ||
2805 !row->par()->IsLineSeparator(main_body-1)))
2808 for (LyXParagraph::size_type vpos = row->pos();
2809 vpos < cursor_vpos; ++vpos) {
2810 pos = vis2log(vpos);
2811 if (main_body > 0 && pos == main_body - 1) {
2812 x += fill_label_hfill +
2813 lyxfont::width(textclasslist.Style(
2814 bview->buffer()->params.textclass,
2815 row->par()->GetLayout())
2817 GetFont(bview->buffer(), row->par(), -2));
2818 if (row->par()->IsLineSeparator(main_body-1))
2819 x -= SingleWidth(bview, row->par(),main_body-1);
2821 if (HfillExpansion(bview->buffer(), row, pos)) {
2822 x += SingleWidth(bview, row->par(), pos);
2823 if (pos >= main_body)
2826 x += fill_label_hfill;
2827 } else if (row->par()->IsSeparator(pos)) {
2828 x += SingleWidth(bview, row->par(), pos);
2829 if (pos >= main_body)
2830 x += fill_separator;
2832 x += SingleWidth(bview, row->par(), pos);
2841 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2842 LyXParagraph::size_type pos,
2843 bool setfont, bool boundary) const
2845 SetCursor(bview, cursor, par, pos, boundary);
2847 SetCurrentFont(bview);
2851 void LyXText::SetCurrentFont(BufferView * bview) const
2853 LyXParagraph::size_type pos = cursor.pos();
2854 if (cursor.boundary() && pos > 0)
2859 if (pos == cursor.par()->Last())
2861 if (pos == cursor.par()->size())
2864 else if (cursor.par()->IsSeparator(pos)) {
2865 if (pos > cursor.row()->pos() &&
2866 bidi_level(pos) % 2 ==
2867 bidi_level(pos - 1) % 2)
2870 else if (pos + 1 < cursor.par()->Last())
2872 else if (pos + 1 < cursor.par()->size())
2879 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2880 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2883 if (cursor.pos() == cursor.par()->Last() &&
2885 if (cursor.pos() == cursor.par()->size() &&
2887 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2888 !cursor.boundary()) {
2889 Language const * lang =
2890 cursor.par()->getParLanguage(bview->buffer()->params);
2891 current_font.setLanguage(lang);
2892 current_font.setNumber(LyXFont::OFF);
2893 real_current_font.setLanguage(lang);
2894 real_current_font.setNumber(LyXFont::OFF);
2899 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2901 LyXCursor old_cursor = cursor;
2903 /* get the row first */
2905 Row * row = GetRowNearY(y);
2906 cursor.par(row->par());
2909 int column = GetColumnNearX(bview, row, x, bound);
2910 cursor.pos(row->pos() + column);
2912 cursor.y(y + row->baseline());
2914 cursor.boundary(bound);
2915 SetCurrentFont(bview);
2916 DeleteEmptyParagraphMechanism(bview, old_cursor);
2920 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2923 /* get the row first */
2925 Row * row = GetRowNearY(y);
2927 int column = GetColumnNearX(bview, row, x, bound);
2929 cur.par(row->par());
2930 cur.pos(row->pos() + column);
2932 cur.y(y + row->baseline());
2934 cur.boundary(bound);
2938 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2940 if (cursor.pos() > 0) {
2941 bool boundary = cursor.boundary();
2942 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2943 if (!internal && !boundary &&
2944 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2945 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2946 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2947 LyXParagraph * par = cursor.par()->previous();
2949 SetCursor(bview, par, par->Last());
2951 SetCursor(bview, par, par->size());
2957 void LyXText::CursorRight(BufferView * bview, bool internal) const
2959 if (!internal && cursor.boundary() &&
2960 !cursor.par()->IsNewline(cursor.pos()))
2961 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2963 else if (cursor.pos() < cursor.par()->Last()) {
2965 else if (cursor.pos() < cursor.par()->size()) {
2967 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2969 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2970 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2971 } else if (cursor.par()->next())
2972 SetCursor(bview, cursor.par()->next(), 0);
2976 void LyXText::CursorUp(BufferView * bview) const
2978 SetCursorFromCoordinates(bview, cursor.x_fix(),
2979 cursor.y() - cursor.row()->baseline() - 1);
2983 void LyXText::CursorDown(BufferView * bview) const
2985 SetCursorFromCoordinates(bview, cursor.x_fix(),
2986 cursor.y() - cursor.row()->baseline()
2987 + cursor.row()->height() + 1);
2991 void LyXText::CursorUpParagraph(BufferView * bview) const
2993 if (cursor.pos() > 0) {
2994 SetCursor(bview, cursor.par(), 0);
2996 else if (cursor.par()->previous()) {
2997 SetCursor(bview, cursor.par()->previous(), 0);
3002 void LyXText::CursorDownParagraph(BufferView * bview) const
3004 if (cursor.par()->next()) {
3005 SetCursor(bview, cursor.par()->next(), 0);
3008 SetCursor(bview, cursor.par(), cursor.par()->Last());
3010 SetCursor(bview, cursor.par(), cursor.par()->size());
3016 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3017 LyXCursor const & old_cursor) const
3019 // Would be wrong to delete anything if we have a selection.
3020 if (selection) return;
3022 // We allow all kinds of "mumbo-jumbo" when freespacing.
3023 if (textclasslist.Style(bview->buffer()->params.textclass,
3024 old_cursor.par()->GetLayout()).free_spacing)
3027 bool deleted = false;
3029 /* Ok I'll put some comments here about what is missing.
3030 I have fixed BackSpace (and thus Delete) to not delete
3031 double-spaces automagically. I have also changed Cut,
3032 Copy and Paste to hopefully do some sensible things.
3033 There are still some small problems that can lead to
3034 double spaces stored in the document file or space at
3035 the beginning of paragraphs. This happens if you have
3036 the cursor betwenn to spaces and then save. Or if you
3037 cut and paste and the selection have a space at the
3038 beginning and then save right after the paste. I am
3039 sure none of these are very hard to fix, but I will
3040 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3041 that I can get some feedback. (Lgb)
3044 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3045 // delete the LineSeparator.
3048 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3049 // delete the LineSeparator.
3052 // If the pos around the old_cursor were spaces, delete one of them.
3053 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3054 // Only if the cursor has really moved
3056 if (old_cursor.pos() > 0
3058 && old_cursor.pos() < old_cursor.par()->Last()
3060 && old_cursor.pos() < old_cursor.par()->size()
3062 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3063 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3064 old_cursor.par()->Erase(old_cursor.pos() - 1);
3065 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3067 if (old_cursor.par() == cursor.par() &&
3068 cursor.pos() > old_cursor.pos()) {
3069 SetCursorIntern(bview, cursor.par(),
3072 SetCursorIntern(bview, cursor.par(),
3078 // Do not delete empty paragraphs with keepempty set.
3079 if ((textclasslist.Style(bview->buffer()->params.textclass,
3080 old_cursor.par()->GetLayout())).keepempty)
3083 LyXCursor tmpcursor;
3086 if (old_cursor.par() != cursor.par()) {
3087 if ((old_cursor.par()->Last() == 0
3088 || (old_cursor.par()->Last() == 1
3089 && old_cursor.par()->IsLineSeparator(0)))
3090 && old_cursor.par()->FirstPhysicalPar()
3091 == old_cursor.par()->LastPhysicalPar()
3093 if (old_cursor.par() != cursor.par()) {
3094 if ((old_cursor.par()->size() == 0
3095 || (old_cursor.par()->size() == 1
3096 && old_cursor.par()->IsLineSeparator(0)))
3099 // ok, we will delete anything
3101 // make sure that you do not delete any environments
3104 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3105 !(old_cursor.row()->previous()
3106 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3107 && !(old_cursor.row()->next()
3108 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3109 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3110 && ((old_cursor.row()->previous()
3111 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3112 || (old_cursor.row()->next()
3113 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3116 status = LyXText::NEED_MORE_REFRESH;
3119 if (old_cursor.row()->previous()) {
3120 refresh_row = old_cursor.row()->previous();
3121 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3123 cursor = old_cursor; // that undo can restore the right cursor position
3125 LyXParagraph * endpar = old_cursor.par()->next_;
3126 if (endpar && endpar->GetDepth()) {
3127 while (endpar && endpar->GetDepth()) {
3128 endpar = endpar->LastPhysicalPar()->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 LyXParagraph * endpar = old_cursor.par()->next();
3143 if (endpar && endpar->GetDepth()) {
3144 while (endpar && endpar->GetDepth()) {
3145 endpar = endpar->next();
3148 SetUndo(bview->buffer(), Undo::DELETE,
3149 old_cursor.par()->previous(),
3154 RemoveRow(old_cursor.row());
3155 if (OwnerParagraph() == old_cursor.par()) {
3156 OwnerParagraph(OwnerParagraph()->next());
3160 delete old_cursor.par();
3162 /* Breakagain the next par. Needed
3163 * because of the parindent that
3164 * can occur or dissappear. The
3165 * next row can change its height,
3166 * if there is another layout before */
3167 if (refresh_row->next()) {
3168 BreakAgain(bview, refresh_row->next());
3169 UpdateCounters(bview, refresh_row);
3171 SetHeightOfRow(bview, refresh_row);
3173 refresh_row = old_cursor.row()->next();
3174 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3177 cursor = old_cursor; // that undo can restore the right cursor position
3179 LyXParagraph * endpar = old_cursor.par()->next_;
3180 if (endpar && endpar->GetDepth()) {
3181 while (endpar && endpar->GetDepth()) {
3182 endpar = endpar->LastPhysicalPar()->next();
3185 SetUndo(bview->buffer(), Undo::DELETE,
3186 old_cursor.par()->previous_,
3191 RemoveRow(old_cursor.row());
3193 if (OwnerParagraph() == old_cursor.par()) {
3194 OwnerParagraph(OwnerParagraph()->next_);
3197 LyXParagraph * endpar = old_cursor.par()->next();
3198 if (endpar && endpar->GetDepth()) {
3199 while (endpar && endpar->GetDepth()) {
3200 endpar = endpar->next();
3203 SetUndo(bview->buffer(), Undo::DELETE,
3204 old_cursor.par()->previous(),
3209 RemoveRow(old_cursor.row());
3211 if (OwnerParagraph() == old_cursor.par()) {
3212 OwnerParagraph(OwnerParagraph()->next());
3215 delete old_cursor.par();
3217 /* Breakagain the next par. Needed
3218 because of the parindent that can
3219 occur or dissappear.
3220 The next row can change its height,
3221 if there is another layout before
3224 BreakAgain(bview, refresh_row);
3225 UpdateCounters(bview, refresh_row->previous());
3231 SetCursorIntern(bview, cursor.par(), cursor.pos());
3233 if (sel_cursor.par() == old_cursor.par()
3234 && sel_cursor.pos() == sel_cursor.pos()) {
3235 // correct selection
3236 sel_cursor = cursor;
3243 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3244 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3246 SetCursorIntern(bview, cursor.par(), cursor.pos());
3247 sel_cursor = cursor;
3255 LyXParagraph * LyXText::GetParFromID(int id)
3257 LyXParagraph * result = FirstParagraph();
3258 while (result && result->id() != id)
3259 result = result->next_;
3263 LyXParagraph * LyXText::GetParFromID(int id)
3265 LyXParagraph * result = FirstParagraph();
3266 while (result && result->id() != id)
3267 result = result->next();
3274 bool LyXText::TextUndo(BufferView * bview)
3278 // returns false if no undo possible
3279 Undo * undo = bview->buffer()->undostack.pop();
3283 bview->buffer()->redostack
3284 .push(CreateUndo(bview->buffer(), undo->kind,
3285 GetParFromID(undo->number_of_before_par),
3286 GetParFromID(undo->number_of_behind_par)));
3288 return TextHandleUndo(bview, undo);
3292 bool LyXText::TextRedo(BufferView * bview)
3296 // returns false if no redo possible
3297 Undo * undo = bview->buffer()->redostack.pop();
3301 bview->buffer()->undostack
3302 .push(CreateUndo(bview->buffer(), undo->kind,
3303 GetParFromID(undo->number_of_before_par),
3304 GetParFromID(undo->number_of_behind_par)));
3306 return TextHandleUndo(bview, undo);
3310 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3314 // returns false if no undo possible
3315 bool result = false;
3317 LyXParagraph * before =
3318 GetParFromID(undo->number_of_before_par);
3319 LyXParagraph * behind =
3320 GetParFromID(undo->number_of_behind_par);
3321 LyXParagraph * tmppar;
3322 LyXParagraph * tmppar2;
3323 LyXParagraph * endpar;
3324 LyXParagraph * tmppar5;
3326 // if there's no before take the beginning
3327 // of the document for redoing
3329 SetCursorIntern(bview, FirstParagraph(), 0);
3331 // replace the paragraphs with the undo informations
3333 LyXParagraph * tmppar3 = undo->par;
3334 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3335 LyXParagraph * tmppar4 = tmppar3;
3338 while (tmppar4->next_)
3339 tmppar4 = tmppar4->next_;
3340 } // get last undo par
3342 // now remove the old text if there is any
3343 if (before != behind || (!behind && !before)) {
3345 tmppar5 = before->next();
3347 tmppar5 = OwnerParagraph();
3349 while (tmppar5 && tmppar5 != behind) {
3351 tmppar5 = tmppar5->next();
3352 // a memory optimization for edit: Only layout information
3353 // is stored in the undo. So restore the text informations.
3354 if (undo->kind == Undo::EDIT) {
3355 tmppar2->setContentsFromPar(tmppar);
3356 tmppar->clearContents();
3357 tmppar2 = tmppar2->next();
3364 while (tmppar4->next())
3365 tmppar4 = tmppar4->next();
3366 } // get last undo par
3368 // now remove the old text if there is any
3369 if (before != behind || (!behind && !before)) {
3371 tmppar5 = before->next();
3373 tmppar5 = OwnerParagraph();
3375 while (tmppar5 && tmppar5 != behind) {
3377 tmppar5 = tmppar5->next();
3378 // a memory optimization for edit: Only layout information
3379 // is stored in the undo. So restore the text informations.
3380 if (undo->kind == Undo::EDIT) {
3381 tmppar2->setContentsFromPar(tmppar);
3382 tmppar->clearContents();
3383 tmppar2 = tmppar2->next();
3389 // put the new stuff in the list if there is one
3392 before->next(tmppar3);
3394 OwnerParagraph(tmppar3);
3395 tmppar3->previous(before);
3398 OwnerParagraph(behind);
3401 tmppar4->next(behind);
3403 behind->previous(tmppar4);
3407 // Set the cursor for redoing
3410 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3412 SetCursorIntern(bview, before, 0);
3415 // check wether before points to a closed float and open it if necessary
3416 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3417 && before->next_ && before->next_->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3419 while (tmppar4->previous_ &&
3420 tmppar4->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3421 tmppar4 = tmppar4->previous_;
3422 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3423 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3424 tmppar4 = tmppar4->next_;
3431 // open a cosed footnote at the end if necessary
3432 if (behind && behind->previous_ &&
3433 behind->previous_->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3434 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3435 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3436 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3437 behind = behind->next_;
3442 // calculate the endpar for redoing the paragraphs.
3445 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3446 endpar = behind->LastPhysicalPar()->next();
3448 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->next();
3450 endpar = behind->next();
3455 tmppar = GetParFromID(undo->number_of_cursor_par);
3456 RedoParagraphs(bview, cursor, endpar);
3458 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3459 UpdateCounters(bview, cursor.row());
3469 void LyXText::FinishUndo()
3473 // makes sure the next operation will be stored
3474 undo_finished = true;
3478 void LyXText::FreezeUndo()
3482 // this is dangerous and for internal use only
3487 void LyXText::UnFreezeUndo()
3491 // this is dangerous and for internal use only
3492 undo_frozen = false;
3496 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3497 LyXParagraph const * before,
3498 LyXParagraph const * behind) const
3503 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3504 buf->redostack.clear();
3508 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3509 LyXParagraph const * before, LyXParagraph const * behind)
3513 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3517 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3518 LyXParagraph const * before,
3519 LyXParagraph const * behind) const
3524 int before_number = -1;
3525 int behind_number = -1;
3527 before_number = before->id();
3529 behind_number = behind->id();
3530 // Undo::EDIT and Undo::FINISH are
3531 // always finished. (no overlapping there)
3532 // overlapping only with insert and delete inside one paragraph:
3533 // Nobody wants all removed character
3534 // appear one by one when undoing.
3535 // EDIT is special since only layout information, not the
3536 // contents of a paragaph are stored.
3537 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3538 // check wether storing is needed
3539 if (!buf->undostack.empty() &&
3540 buf->undostack.top()->kind == kind &&
3541 buf->undostack.top()->number_of_before_par == before_number &&
3542 buf->undostack.top()->number_of_behind_par == behind_number ){
3547 // create a new Undo
3548 LyXParagraph * undopar;
3549 LyXParagraph * tmppar;
3550 LyXParagraph * tmppar2;
3552 LyXParagraph * start = 0;
3553 LyXParagraph * end = 0;
3557 start = before->next_;
3559 start = FirstParagraph();
3561 end = behind->previous_;
3563 end = FirstParagraph();
3567 if (start && end && (start != end->next_) &&
3568 ((before != behind) || (!before && !behind))) {
3570 tmppar2 = tmppar->Clone();
3571 tmppar2->id(tmppar->id());
3573 // a memory optimization: Just store the layout information
3575 if (kind == Undo::EDIT){
3576 //tmppar2->text.clear();
3577 tmppar2->clearContents();
3582 while (tmppar != end && tmppar->next_) {
3583 tmppar = tmppar->next_;
3584 tmppar2->next(tmppar->Clone());
3585 tmppar2->next_->id(tmppar->id());
3586 // a memory optimization: Just store the layout
3587 // information when only edit
3588 if (kind == Undo::EDIT){
3589 //tmppar2->next->text.clear();
3590 tmppar2->clearContents();
3592 tmppar2->next_->previous(tmppar2);
3593 tmppar2 = tmppar2->next_;
3597 undopar = 0; // nothing to replace (undo of delete maybe)
3599 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3600 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3603 start = const_cast<LyXParagraph*>(before->next());
3605 start = FirstParagraph();
3607 end = const_cast<LyXParagraph*>(behind->previous());
3609 end = FirstParagraph();
3613 if (start && end && (start != end->next()) &&
3614 ((before != behind) || (!before && !behind))) {
3616 tmppar2 = tmppar->Clone();
3617 tmppar2->id(tmppar->id());
3619 // a memory optimization: Just store the layout information
3621 if (kind == Undo::EDIT){
3622 //tmppar2->text.clear();
3623 tmppar2->clearContents();
3628 while (tmppar != end && tmppar->next()) {
3629 tmppar = tmppar->next();
3630 tmppar2->next(tmppar->Clone());
3631 tmppar2->next()->id(tmppar->id());
3632 // a memory optimization: Just store the layout
3633 // information when only edit
3634 if (kind == Undo::EDIT){
3635 //tmppar2->next->text.clear();
3636 tmppar2->clearContents();
3638 tmppar2->next()->previous(tmppar2);
3639 tmppar2 = tmppar2->next();
3643 undopar = 0; // nothing to replace (undo of delete maybe)
3645 int cursor_par = cursor.par()->id();
3646 int cursor_pos = cursor.pos();
3649 Undo * undo = new Undo(kind,
3650 before_number, behind_number,
3651 cursor_par, cursor_pos,
3654 undo_finished = false;
3659 void LyXText::SetCursorParUndo(Buffer * buf)
3663 SetUndo(buf, Undo::FINISH,
3665 cursor.par()->ParFromPos(cursor.pos())->previous_,
3666 cursor.par()->ParFromPos(cursor.pos())->next_
3668 cursor.par()->previous(),
3669 cursor.par()->next()
3675 void LyXText::toggleAppendix(BufferView * bview)
3678 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3680 LyXParagraph * par = cursor.par();
3682 bool start = !par->params.startOfAppendix();
3684 // ensure that we have only one start_of_appendix in this document
3685 LyXParagraph * tmp = FirstParagraph();
3687 for (; tmp; tmp = tmp->next_)
3688 tmp->params.startOfAppendix(false);
3690 for (; tmp; tmp = tmp->next())
3691 tmp->params.startOfAppendix(false);
3693 par->params.startOfAppendix(start);
3695 // we can set the refreshing parameters now
3696 status = LyXText::NEED_MORE_REFRESH;
3698 refresh_row = 0; // not needed for full update
3699 UpdateCounters(bview, 0);
3700 SetCursor(bview, cursor.par(), cursor.pos());
3704 LyXParagraph * LyXText::OwnerParagraph() const
3707 return inset_owner->par;
3709 return bv_owner->buffer()->paragraph;
3713 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3716 inset_owner->par = p;
3718 bv_owner->buffer()->paragraph = p;