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);
1558 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1559 string const & width,
1560 string const & widthp,
1561 int alignment, bool hfill,
1562 bool start_minipage)
1564 LyXCursor tmpcursor = cursor;
1565 LyXParagraph * tmppar;
1567 sel_start_cursor = cursor;
1568 sel_end_cursor = cursor;
1571 // make sure that the depth behind the selection are restored, too
1573 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
1575 LyXParagraph * endpar = sel_end_cursor.par()->next();
1577 LyXParagraph * undoendpar = endpar;
1579 if (endpar && endpar->GetDepth()) {
1580 while (endpar && endpar->GetDepth()) {
1582 endpar = endpar->LastPhysicalPar()->next();
1584 endpar = endpar->next();
1586 undoendpar = endpar;
1590 endpar = endpar->next(); // because of parindents etc.
1593 SetUndo(bview->buffer(), Undo::EDIT,
1596 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
1598 sel_start_cursor.par()->previous(),
1602 tmppar = sel_end_cursor.par();
1604 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->previous()) {
1605 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1607 while(tmppar != sel_start_cursor.par()->previous()) {
1608 SetCursor(bview, tmppar, 0);
1610 status = LyXText::NEED_MORE_REFRESH;
1611 refresh_row = cursor.row();
1612 refresh_y = cursor.y() - cursor.row()->baseline();
1614 if (cursor.par()->footnoteflag ==
1615 sel_start_cursor.par()->footnoteflag) {
1618 if (type == LyXParagraph::PEXTRA_NONE) {
1619 if (cursor.par()->params.pextraType() != LyXParagraph::PEXTRA_NONE) {
1620 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1621 cursor.par()->params.pextraType(LyXParagraph::PEXTRA_NONE);
1624 cursor.par()->SetPExtraType(bview->buffer()->params,
1625 type, width, widthp);
1626 cursor.par()->params.pextraHfill(hfill);
1627 cursor.par()->params.pextraStartMinipage(start_minipage);
1628 cursor.par()->params.pextraAlignment(alignment);
1633 tmppar = cursor.par()->FirstPhysicalPar()->previous();
1635 tmppar = cursor.par()->previous();
1638 RedoParagraphs(bview, sel_start_cursor, endpar);
1639 ClearSelection(bview);
1640 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1641 sel_cursor = cursor;
1642 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1643 SetSelection(bview);
1644 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1649 char loweralphaCounter(int n)
1651 if (n < 1 || n > 26)
1659 char alphaCounter(int n)
1661 if (n < 1 || n > 26)
1669 char hebrewCounter(int n)
1671 static const char hebrew[22] = {
1672 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1673 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1674 '÷', 'ø', 'ù', 'ú'
1676 if (n < 1 || n > 22)
1684 string const romanCounter(int n)
1686 static char const * roman[20] = {
1687 "i", "ii", "iii", "iv", "v",
1688 "vi", "vii", "viii", "ix", "x",
1689 "xi", "xii", "xiii", "xiv", "xv",
1690 "xvi", "xvii", "xviii", "xix", "xx"
1692 if (n < 1 || n > 20)
1699 // set the counter of a paragraph. This includes the labels
1700 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1703 // this is only relevant for the beginning of paragraph
1704 par = par->FirstPhysicalPar();
1706 LyXLayout const & layout =
1707 textclasslist.Style(buf->params.textclass,
1710 LyXTextClass const & textclass =
1711 textclasslist.TextClass(buf->params.textclass);
1713 /* copy the prev-counters to this one, unless this is the start of a
1714 footnote or of a bibliography or the very first paragraph */
1717 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1718 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1719 && par->footnotekind == LyXParagraph::FOOTNOTE)
1721 && !(textclasslist.Style(buf->params.textclass,
1722 par->previous()->GetLayout()
1723 ).labeltype != LABEL_BIBLIO
1724 && layout.labeltype == LABEL_BIBLIO)) {
1725 for (int i = 0; i < 10; ++i) {
1726 par->setCounter(i, par->previous()->GetFirstCounter(i));
1729 par->params.appendix(par->previous()->FirstPhysicalPar()->params.appendix());
1731 par->params.appendix(par->previous()->params.appendix());
1733 if (!par->params.appendix() && par->params.startOfAppendix()) {
1734 par->params.appendix(true);
1735 for (int i = 0; i < 10; ++i) {
1736 par->setCounter(i, 0);
1740 par->enumdepth = par->previous()->FirstPhysicalPar()->enumdepth;
1741 par->itemdepth = par->previous()->FirstPhysicalPar()->itemdepth;
1743 par->enumdepth = par->previous()->enumdepth;
1744 par->itemdepth = par->previous()->itemdepth;
1747 for (int i = 0; i < 10; ++i) {
1748 par->setCounter(i, 0);
1750 par->params.appendix(par->params.startOfAppendix());
1756 // if this is an open marginnote and this is the first
1757 // entry in the marginnote and the enclosing
1758 // environment is an enum/item then correct for the
1759 // LaTeX behaviour (ARRae)
1760 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1761 && par->footnotekind == LyXParagraph::MARGIN
1763 && par->previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1764 && (par->PreviousBeforeFootnote()
1765 && textclasslist.Style(buf->params.textclass,
1766 par->PreviousBeforeFootnote()->GetLayout()
1767 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1768 // Any itemize or enumerate environment in a marginnote
1769 // that is embedded in an itemize or enumerate
1770 // paragraph is seen by LaTeX as being at a deeper
1771 // level within that enclosing itemization/enumeration
1772 // even if there is a "standard" layout at the start of
1778 /* Maybe we have to increment the enumeration depth.
1779 * BUT, enumeration in a footnote is considered in isolation from its
1780 * surrounding paragraph so don't increment if this is the
1781 * first line of the footnote
1782 * AND, bibliographies can't have their depth changed ie. they
1783 * are always of depth 0
1786 && par->previous()->GetDepth() < par->GetDepth()
1787 && textclasslist.Style(buf->params.textclass,
1788 par->previous()->GetLayout()
1789 ).labeltype == LABEL_COUNTER_ENUMI
1790 && par->enumdepth < 3
1792 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1793 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1794 && par->footnotekind == LyXParagraph::FOOTNOTE)
1796 && layout.labeltype != LABEL_BIBLIO) {
1800 /* Maybe we have to decrement the enumeration depth, see note above */
1802 && par->previous()->GetDepth() > par->GetDepth()
1804 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1805 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1806 && par->footnotekind == LyXParagraph::FOOTNOTE)
1808 && layout.labeltype != LABEL_BIBLIO) {
1809 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1810 par->setCounter(6 + par->enumdepth,
1811 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1812 /* reset the counters.
1813 * A depth change is like a breaking layout
1815 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1816 par->setCounter(i, 0);
1819 if (!par->params.labelString().empty()) {
1820 par->params.labelString(string());
1823 if (layout.margintype == MARGIN_MANUAL) {
1824 if (par->params.labelWidthString().empty()) {
1825 par->SetLabelWidthString(layout.labelstring());
1828 par->SetLabelWidthString(string());
1831 /* is it a layout that has an automatic label ? */
1832 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1834 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1835 if (i >= 0 && i<= buf->params.secnumdepth) {
1836 par->incCounter(i); // increment the counter
1838 // Is there a label? Useful for Chapter layout
1839 if (!par->params.appendix()) {
1840 if (!layout.labelstring().empty())
1841 par->params.labelString(layout.labelstring());
1843 par->params.labelString(string());
1845 if (!layout.labelstring_appendix().empty())
1846 par->params.labelString(layout.labelstring_appendix());
1848 par->params.labelString(string());
1851 std::ostringstream s;
1853 if (!par->params.appendix()) {
1854 switch (2 * LABEL_COUNTER_CHAPTER -
1855 textclass.maxcounter() + i) {
1856 case LABEL_COUNTER_CHAPTER:
1857 s << par->getCounter(i);
1859 case LABEL_COUNTER_SECTION:
1860 s << par->getCounter(i - 1) << '.'
1861 << par->getCounter(i);
1863 case LABEL_COUNTER_SUBSECTION:
1864 s << par->getCounter(i - 2) << '.'
1865 << par->getCounter(i - 1) << '.'
1866 << par->getCounter(i);
1868 case LABEL_COUNTER_SUBSUBSECTION:
1869 s << par->getCounter(i - 3) << '.'
1870 << par->getCounter(i - 2) << '.'
1871 << par->getCounter(i - 1) << '.'
1872 << par->getCounter(i);
1875 case LABEL_COUNTER_PARAGRAPH:
1876 s << par->getCounter(i - 4) << '.'
1877 << par->getCounter(i - 3) << '.'
1878 << par->getCounter(i - 2) << '.'
1879 << par->getCounter(i - 1) << '.'
1880 << par->getCounter(i);
1882 case LABEL_COUNTER_SUBPARAGRAPH:
1883 s << par->getCounter(i - 5) << '.'
1884 << par->getCounter(i - 4) << '.'
1885 << par->getCounter(i - 3) << '.'
1886 << par->getCounter(i - 2) << '.'
1887 << par->getCounter(i - 1) << '.'
1888 << par->getCounter(i);
1892 // Can this ever be reached? And in the
1893 // case it is, how can this be correct?
1895 s << par->getCounter(i) << '.';
1898 } else { // appendix
1899 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1900 case LABEL_COUNTER_CHAPTER:
1901 if (par->isRightToLeftPar(buf->params))
1902 s << hebrewCounter(par->getCounter(i));
1904 s << alphaCounter(par->getCounter(i));
1906 case LABEL_COUNTER_SECTION:
1907 if (par->isRightToLeftPar(buf->params))
1908 s << hebrewCounter(par->getCounter(i - 1));
1910 s << alphaCounter(par->getCounter(i - 1));
1913 << par->getCounter(i);
1916 case LABEL_COUNTER_SUBSECTION:
1917 if (par->isRightToLeftPar(buf->params))
1918 s << hebrewCounter(par->getCounter(i - 2));
1920 s << alphaCounter(par->getCounter(i - 2));
1923 << par->getCounter(i-1) << '.'
1924 << par->getCounter(i);
1927 case LABEL_COUNTER_SUBSUBSECTION:
1928 if (par->isRightToLeftPar(buf->params))
1929 s << hebrewCounter(par->getCounter(i-3));
1931 s << alphaCounter(par->getCounter(i-3));
1934 << par->getCounter(i-2) << '.'
1935 << par->getCounter(i-1) << '.'
1936 << par->getCounter(i);
1939 case LABEL_COUNTER_PARAGRAPH:
1940 if (par->isRightToLeftPar(buf->params))
1941 s << hebrewCounter(par->getCounter(i-4));
1943 s << alphaCounter(par->getCounter(i-4));
1946 << par->getCounter(i-3) << '.'
1947 << par->getCounter(i-2) << '.'
1948 << par->getCounter(i-1) << '.'
1949 << par->getCounter(i);
1952 case LABEL_COUNTER_SUBPARAGRAPH:
1953 if (par->isRightToLeftPar(buf->params))
1954 s << hebrewCounter(par->getCounter(i-5));
1956 s << alphaCounter(par->getCounter(i-5));
1959 << par->getCounter(i-4) << '.'
1960 << par->getCounter(i-3) << '.'
1961 << par->getCounter(i-2) << '.'
1962 << par->getCounter(i-1) << '.'
1963 << par->getCounter(i);
1967 // Can this ever be reached? And in the
1968 // case it is, how can this be correct?
1970 s << par->getCounter(i) << '.';
1976 par->params.labelString(par->params.labelString() +s.str().c_str());
1977 // We really want to remove the c_str as soon as
1980 for (i++; i < 10; ++i) {
1981 // reset the following counters
1982 par->setCounter(i, 0);
1984 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1985 for (i++; i < 10; ++i) {
1986 // reset the following counters
1987 par->setCounter(i, 0);
1989 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1990 par->incCounter(i + par->enumdepth);
1991 int number = par->getCounter(i + par->enumdepth);
1993 std::ostringstream s;
1995 switch (par->enumdepth) {
1997 if (par->isRightToLeftPar(buf->params))
1999 << hebrewCounter(number)
2003 << loweralphaCounter(number)
2007 if (par->isRightToLeftPar(buf->params))
2008 s << '.' << romanCounter(number);
2010 s << romanCounter(number) << '.';
2013 if (par->isRightToLeftPar(buf->params))
2015 << alphaCounter(number);
2017 s << alphaCounter(number)
2021 if (par->isRightToLeftPar(buf->params))
2028 par->params.labelString(s.str().c_str());
2029 // we really want to get rid of that c_str()
2031 for (i += par->enumdepth + 1; i < 10; ++i)
2032 par->setCounter(i, 0); /* reset the following counters */
2035 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2036 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2038 int number = par->getCounter(i);
2040 InsetCommandParams p( "bibitem" );
2041 par->bibkey = new InsetBibKey(p);
2043 par->bibkey->setCounter(number);
2044 par->params.labelString(layout.labelstring());
2046 // In biblio should't be following counters but...
2048 string s = layout.labelstring();
2050 // the caption hack:
2051 if (layout.labeltype == LABEL_SENSITIVE) {
2052 bool isOK (par->InInset() && par->InInset()->owner() &&
2053 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2055 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2056 && (par->footnotekind == LyXParagraph::FIG
2057 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2058 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2059 ? ":øåéà " : "Figure:";
2060 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2061 && (par->footnotekind == LyXParagraph::TAB
2062 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2063 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2064 ? ":äìáè" : "Table:";
2065 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2066 && par->footnotekind == LyXParagraph::ALGORITHM) {
2067 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2068 ? ":Ãúéøåâìà " : "Algorithm:";
2072 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2074 = floatList.getType(tmp->type());
2075 // We should get the correct number here too.
2076 s = fl.name() + " #:";
2078 /* par->SetLayout(0);
2079 s = layout->labelstring; */
2080 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2081 ? " :úåòîùî øñç" : "Senseless: ";
2084 par->params.labelString(s);
2086 /* reset the enumeration counter. They are always resetted
2087 * when there is any other layout between */
2088 for (int i = 6 + par->enumdepth; i < 10; ++i)
2089 par->setCounter(i, 0);
2094 /* Updates all counters BEHIND the row. Changed paragraphs
2095 * with a dynamic left margin will be rebroken. */
2096 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2103 } else if (row->par()->next_
2104 && row->par()->next_->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
2105 par = row->par()->LastPhysicalPar()->next();
2107 par = row->par()->next_;
2114 par = row->par()->next();
2119 while (row->par() != par)
2122 SetCounter(bview->buffer(), par);
2124 /* now check for the headline layouts. remember that they
2125 * have a dynamic left margin */
2130 ( textclasslist.Style(bview->buffer()->params.textclass,
2131 par->layout).margintype == MARGIN_DYNAMIC
2132 || textclasslist.Style(bview->buffer()->params.textclass,
2133 par->layout).labeltype == LABEL_SENSITIVE)
2136 /* Rebreak the paragraph */
2137 RemoveParagraph(row);
2138 AppendParagraph(bview, row);
2141 /* think about the damned open footnotes! */
2142 while (par->next() &&
2143 (par->next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2144 || par->next()->IsDummy())){
2146 if (par->IsDummy()) {
2147 while (row->par() != par)
2149 RemoveParagraph(row);
2150 AppendParagraph(bview, row);
2156 par = par->LastPhysicalPar()->next();
2165 /* insets an inset. */
2166 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2168 if (!cursor.par()->InsertInsetAllowed(inset))
2170 SetUndo(bview->buffer(), Undo::INSERT,
2172 cursor.par()->ParFromPos(cursor.pos())->previous_,
2173 cursor.par()->ParFromPos(cursor.pos())->next_
2175 cursor.par()->previous(),
2176 cursor.par()->next()
2179 cursor.par()->InsertInset(cursor.pos(), inset);
2180 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2181 * The character will not be inserted a
2184 // If we enter a highly editable inset the cursor should be to before
2185 // the inset. This couldn't happen before as Undo was not handled inside
2186 // inset now after the Undo LyX tries to call inset->Edit(...) again
2187 // and cannot do this as the cursor is behind the inset and GetInset
2188 // does not return the inset!
2189 if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
2190 CursorLeft(bview, true);
2196 void LyXText::copyEnvironmentType()
2198 copylayouttype = cursor.par()->GetLayout();
2202 void LyXText::pasteEnvironmentType(BufferView * bview)
2204 SetLayout(bview, copylayouttype);
2208 void LyXText::CutSelection(BufferView * bview, bool doclear)
2210 // Stuff what we got on the clipboard. Even if there is no selection.
2212 // There is a problem with having the stuffing here in that the
2213 // larger the selection the slower LyX will get. This can be
2214 // solved by running the line below only when the selection has
2215 // finished. The solution used currently just works, to make it
2216 // faster we need to be more clever and probably also have more
2217 // calls to stuffClipboard. (Lgb)
2218 bview->stuffClipboard(selectionAsString(bview->buffer()));
2220 // This doesn't make sense, if there is no selection
2224 // OK, we have a selection. This is always between sel_start_cursor
2225 // and sel_end_cursor
2227 // Check whether there are half footnotes in the selection
2228 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2229 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2230 LyXParagraph * tmppar = sel_start_cursor.par();
2231 while (tmppar != sel_end_cursor.par()){
2232 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2233 WriteAlert(_("Impossible operation"),
2234 _("Don't know what to do with half floats."),
2238 tmppar = tmppar->next();
2243 // make sure that the depth behind the selection are restored, too
2245 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
2247 LyXParagraph * endpar = sel_end_cursor.par()->next();
2249 LyXParagraph * undoendpar = endpar;
2251 if (endpar && endpar->GetDepth()) {
2252 while (endpar && endpar->GetDepth()) {
2254 endpar = endpar->LastPhysicalPar()->next();
2256 endpar = endpar->next();
2258 undoendpar = endpar;
2260 } else if (endpar) {
2261 endpar = endpar->next(); // because of parindents etc.
2264 SetUndo(bview->buffer(), Undo::DELETE,
2267 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
2269 sel_start_cursor.par()->previous(),
2275 // there are two cases: cut only within one paragraph or
2276 // more than one paragraph
2278 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2279 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2281 if (sel_start_cursor.par() == sel_end_cursor.par())
2284 // only within one paragraph
2285 endpar = sel_start_cursor.par();
2286 int pos = sel_end_cursor.pos();
2287 cap.cutSelection(sel_start_cursor.par(), &endpar,
2288 sel_start_cursor.pos(), pos,
2289 bview->buffer()->params.textclass, doclear);
2290 sel_end_cursor.pos(pos);
2292 endpar = sel_end_cursor.par();
2294 int pos = sel_end_cursor.pos();
2295 cap.cutSelection(sel_start_cursor.par(), &endpar,
2296 sel_start_cursor.pos(), pos,
2297 bview->buffer()->params.textclass, doclear);
2299 sel_end_cursor.par(endpar);
2300 sel_end_cursor.pos(pos);
2301 cursor.pos(sel_end_cursor.pos());
2303 endpar = endpar->next();
2305 // sometimes necessary
2307 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2309 RedoParagraphs(bview, sel_start_cursor, endpar);
2311 ClearSelection(bview);
2312 cursor = sel_start_cursor;
2313 SetCursor(bview, cursor.par(), cursor.pos());
2314 sel_cursor = cursor;
2315 UpdateCounters(bview, cursor.row());
2319 void LyXText::CopySelection(BufferView * bview)
2321 // Stuff what we got on the clipboard. Even if there is no selection.
2323 // There is a problem with having the stuffing here in that the
2324 // larger the selection the slower LyX will get. This can be
2325 // solved by running the line below only when the selection has
2326 // finished. The solution used currently just works, to make it
2327 // faster we need to be more clever and probably also have more
2328 // calls to stuffClipboard. (Lgb)
2329 bview->stuffClipboard(selectionAsString(bview->buffer()));
2331 // this doesnt make sense, if there is no selection
2335 // ok we have a selection. This is always between sel_start_cursor
2336 // and sel_end cursor
2339 /* check wether there are half footnotes in the selection */
2340 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2341 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2342 LyXParagraph * tmppar = sel_start_cursor.par();
2343 while (tmppar != sel_end_cursor.par()) {
2344 if (tmppar->footnoteflag !=
2345 sel_end_cursor.par()->footnoteflag) {
2346 WriteAlert(_("Impossible operation"),
2347 _("Don't know what to do"
2348 " with half floats."),
2352 tmppar = tmppar->next();
2357 // copy behind a space if there is one
2359 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2361 while (sel_start_cursor.par()->size() > sel_start_cursor.pos()
2363 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2364 && (sel_start_cursor.par() != sel_end_cursor.par()
2365 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2366 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2370 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2371 sel_start_cursor.pos(), sel_end_cursor.pos(),
2372 bview->buffer()->params.textclass);
2376 void LyXText::PasteSelection(BufferView * bview)
2380 // this does not make sense, if there is nothing to paste
2381 if (!cap.checkPastePossible(cursor.par()))
2384 SetUndo(bview->buffer(), Undo::INSERT,
2386 cursor.par()->ParFromPos(cursor.pos())->previous_,
2387 cursor.par()->ParFromPos(cursor.pos())->next_
2389 cursor.par()->previous(),
2390 cursor.par()->next()
2394 LyXParagraph * endpar;
2395 LyXParagraph * actpar = cursor.par();
2397 int pos = cursor.pos();
2398 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2400 RedoParagraphs(bview, cursor, endpar);
2402 SetCursor(bview, cursor.par(), cursor.pos());
2403 ClearSelection(bview);
2405 sel_cursor = cursor;
2406 SetCursor(bview, actpar, pos);
2407 SetSelection(bview);
2408 UpdateCounters(bview, cursor.row());
2412 // returns a pointer to the very first LyXParagraph
2413 LyXParagraph * LyXText::FirstParagraph() const
2415 return OwnerParagraph();
2419 // sets the selection over the number of characters of string, no check!!
2420 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2422 sel_cursor = cursor;
2423 for (int i = 0; str[i]; ++i)
2425 SetSelection(bview);
2429 // simple replacing. The font of the first selected character is used
2430 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2433 SetCursorParUndo(bview->buffer());
2436 if (!selection) { // create a dummy selection
2437 sel_end_cursor = cursor;
2438 sel_start_cursor = cursor;
2441 // Get font setting before we cut
2442 LyXParagraph::size_type pos = sel_end_cursor.pos();
2443 LyXFont const font = sel_start_cursor.par()
2444 ->GetFontSettings(bview->buffer()->params,
2445 sel_start_cursor.pos());
2447 // Insert the new string
2448 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2449 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2453 // Cut the selection
2454 CutSelection(bview);
2460 // needed to insert the selection
2461 void LyXText::InsertStringA(BufferView * bview, string const & str)
2463 LyXParagraph * par = cursor.par();
2464 LyXParagraph::size_type pos = cursor.pos();
2465 LyXParagraph::size_type a = 0;
2466 LyXParagraph * endpar = cursor.par()->next();
2468 SetCursorParUndo(bview->buffer());
2471 textclasslist.Style(bview->buffer()->params.textclass,
2472 cursor.par()->GetLayout()).isEnvironment();
2473 // only to be sure, should not be neccessary
2474 ClearSelection(bview);
2476 // insert the string, don't insert doublespace
2477 string::size_type i = 0;
2478 while (i < str.length()) {
2479 if (str[i] != '\n') {
2481 && i + 1 < str.length() && str[i + 1] != ' '
2482 && pos && par->GetChar(pos - 1)!= ' ') {
2483 par->InsertChar(pos, ' ', current_font);
2485 } else if (str[i] == ' ') {
2486 InsetSpecialChar * new_inset =
2487 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2488 if (par->InsertInsetAllowed(new_inset)) {
2489 par->InsertInset(pos, new_inset,
2495 } else if (str[i] == '\t') {
2496 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2497 InsetSpecialChar * new_inset =
2498 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2499 if (par->InsertInsetAllowed(new_inset)) {
2500 par->InsertInset(pos, new_inset,
2507 } else if (str[i] != 13 &&
2508 // Ignore unprintables
2509 (str[i] & 127) >= ' ') {
2510 par->InsertChar(pos, str[i], current_font);
2514 if (!par->size()) { // par is empty
2515 InsetSpecialChar * new_inset =
2516 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2517 if (par->InsertInsetAllowed(new_inset)) {
2518 par->InsertInset(pos,
2526 par->BreakParagraph(bview->buffer()->params, pos, flag);
2533 RedoParagraphs(bview, cursor, endpar);
2534 SetCursor(bview, cursor.par(), cursor.pos());
2535 sel_cursor = cursor;
2536 SetCursor(bview, par, pos);
2537 SetSelection(bview);
2541 /* turns double-CR to single CR, others where converted into one blank and 13s
2542 * that are ignored .Double spaces are also converted into one. Spaces at
2543 * the beginning of a paragraph are forbidden. tabs are converted into one
2544 * space. then InsertStringA is called */
2545 void LyXText::InsertStringB(BufferView * bview, string const & s)
2548 string::size_type i = 1;
2549 while (i < str.length()) {
2552 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2554 if (str[i] == '\n' && i + 1 < str.length()) {
2555 if (str[i + 1] != '\n') {
2556 if (str[i - 1] != ' ')
2561 while (i + 1 < str.length()
2562 && (str[i + 1] == ' '
2563 || str[i + 1] == '\t'
2564 || str[i + 1] == '\n'
2565 || str[i + 1] == 13)) {
2572 InsertStringA(bview, str);
2576 bool LyXText::GotoNextInset(BufferView * bview,
2577 std::vector<Inset::Code> const & codes,
2578 string const & contents) const
2580 LyXCursor res = cursor;
2584 if (res.pos() < res.par()->Last() - 1) {
2586 if (res.pos() < res.par()->size() - 1) {
2588 res.pos(res.pos() + 1);
2590 res.par(res.par()->next());
2594 } while (res.par() &&
2595 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2596 && (inset = res.par()->GetInset(res.pos())) != 0
2597 && find(codes.begin(), codes.end(), inset->LyxCode())
2599 && (contents.empty() ||
2600 static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
2604 SetCursor(bview, res.par(), res.pos());
2611 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2612 LyXParagraph::size_type pos)
2614 LyXCursor tmpcursor;
2617 LyXParagraph::size_type z;
2618 Row * row = GetRow(par, pos, y);
2620 // is there a break one row above
2621 if (row->previous() && row->previous()->par() == row->par()) {
2622 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2623 if (z >= row->pos()) {
2624 // set the dimensions of the row above
2625 y -= row->previous()->height();
2627 refresh_row = row->previous();
2628 status = LyXText::NEED_MORE_REFRESH;
2630 BreakAgain(bview, row->previous());
2632 // set the cursor again. Otherwise
2633 // dangling pointers are possible
2634 SetCursor(bview, cursor.par(), cursor.pos(),
2635 false, cursor.boundary());
2636 sel_cursor = cursor;
2641 int const tmpheight = row->height();
2642 LyXParagraph::size_type const tmplast = RowLast(row);
2646 BreakAgain(bview, row);
2647 if (row->height() == tmpheight && RowLast(row) == tmplast)
2648 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2650 status = LyXText::NEED_MORE_REFRESH;
2652 // check the special right address boxes
2653 if (textclasslist.Style(bview->buffer()->params.textclass,
2654 par->GetLayout()).margintype
2655 == MARGIN_RIGHT_ADDRESS_BOX) {
2662 RedoDrawingOfParagraph(bview, tmpcursor);
2665 // set the cursor again. Otherwise dangling pointers are possible
2666 // also set the selection
2670 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2671 false, sel_cursor.boundary());
2672 sel_cursor = cursor;
2673 SetCursorIntern(bview, sel_start_cursor.par(),
2674 sel_start_cursor.pos(),
2675 false, sel_start_cursor.boundary());
2676 sel_start_cursor = cursor;
2677 SetCursorIntern(bview, sel_end_cursor.par(),
2678 sel_end_cursor.pos(),
2679 false, sel_end_cursor.boundary());
2680 sel_end_cursor = cursor;
2681 SetCursorIntern(bview, last_sel_cursor.par(),
2682 last_sel_cursor.pos(),
2683 false, last_sel_cursor.boundary());
2684 last_sel_cursor = cursor;
2687 SetCursorIntern(bview, cursor.par(), cursor.pos(),
2688 false, cursor.boundary());
2692 // returns false if inset wasn't found
2693 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2695 // first check the current paragraph
2696 int pos = cursor.par()->GetPositionOfInset(inset);
2698 CheckParagraph(bview, cursor.par(), pos);
2702 // check every paragraph
2704 LyXParagraph * par = FirstParagraph();
2707 // make sure the paragraph is open
2708 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2710 pos = par->GetPositionOfInset(inset);
2712 CheckParagraph(bview, par, pos);
2725 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2726 LyXParagraph::size_type pos,
2727 bool setfont, bool boundary) const
2729 LyXCursor old_cursor = cursor;
2730 SetCursorIntern(bview, par, pos, setfont, boundary);
2731 DeleteEmptyParagraphMechanism(bview, old_cursor);
2735 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2736 LyXParagraph::size_type pos, bool boundary) const
2739 // correct the cursor position if impossible
2740 if (pos > par->Last()){
2741 LyXParagraph * tmppar = par->ParFromPos(pos);
2742 pos = par->PositionInParFromPos(pos);
2745 if (par->IsDummy() && par->previous_ &&
2746 par->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2747 while (par->previous_ &&
2748 ((par->previous_->IsDummy() &&
2749 (par->previous_->previous_->footnoteflag ==
2750 LyXParagraph::CLOSED_FOOTNOTE)) ||
2751 (par->previous_->footnoteflag ==
2752 LyXParagraph::CLOSED_FOOTNOTE))) {
2753 par = par->previous_;
2754 if (par->IsDummy() &&
2755 (par->previous_->footnoteflag ==
2756 LyXParagraph::CLOSED_FOOTNOTE))
2757 pos += par->size() + 1;
2759 if (par->previous_) {
2760 par = par->previous_;
2762 pos += par->size() + 1;
2767 cur.boundary(boundary);
2769 /* get the cursor y position in text */
2771 Row * row = GetRow(par, pos, y);
2772 /* y is now the beginning of the cursor row */
2773 y += row->baseline();
2774 /* y is now the cursor baseline */
2777 /* now get the cursors x position */
2779 float fill_separator, fill_hfill, fill_label_hfill;
2780 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2782 LyXParagraph::size_type cursor_vpos = 0;
2783 LyXParagraph::size_type last = RowLastPrintable(row);
2785 if (pos > last + 1) // This shouldn't happen.
2787 else if (pos < row->pos())
2790 if (last < row->pos())
2791 cursor_vpos = row->pos();
2792 else if (pos > last && !boundary)
2793 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2794 ? row->pos() : last + 1;
2795 else if (pos > row->pos() &&
2796 (pos > last || boundary))
2797 /// Place cursor after char at (logical) position pos - 1
2798 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2799 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2801 /// Place cursor before char at (logical) position pos
2802 cursor_vpos = (bidi_level(pos) % 2 == 0)
2803 ? log2vis(pos) : log2vis(pos) + 1;
2805 LyXParagraph::size_type main_body =
2806 BeginningOfMainBody(bview->buffer(), row->par());
2807 if ((main_body > 0) &&
2808 ((main_body-1 > last) ||
2809 !row->par()->IsLineSeparator(main_body-1)))
2812 for (LyXParagraph::size_type vpos = row->pos();
2813 vpos < cursor_vpos; ++vpos) {
2814 pos = vis2log(vpos);
2815 if (main_body > 0 && pos == main_body - 1) {
2816 x += fill_label_hfill +
2817 lyxfont::width(textclasslist.Style(
2818 bview->buffer()->params.textclass,
2819 row->par()->GetLayout())
2821 GetFont(bview->buffer(), row->par(), -2));
2822 if (row->par()->IsLineSeparator(main_body-1))
2823 x -= SingleWidth(bview, row->par(),main_body-1);
2825 if (HfillExpansion(bview->buffer(), row, pos)) {
2826 x += SingleWidth(bview, row->par(), pos);
2827 if (pos >= main_body)
2830 x += fill_label_hfill;
2831 } else if (row->par()->IsSeparator(pos)) {
2832 x += SingleWidth(bview, row->par(), pos);
2833 if (pos >= main_body)
2834 x += fill_separator;
2836 x += SingleWidth(bview, row->par(), pos);
2845 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2846 LyXParagraph::size_type pos,
2847 bool setfont, bool boundary) const
2849 SetCursor(bview, cursor, par, pos, boundary);
2851 SetCurrentFont(bview);
2855 void LyXText::SetCurrentFont(BufferView * bview) const
2857 LyXParagraph::size_type pos = cursor.pos();
2858 if (cursor.boundary() && pos > 0)
2863 if (pos == cursor.par()->Last())
2865 if (pos == cursor.par()->size())
2868 else if (cursor.par()->IsSeparator(pos)) {
2869 if (pos > cursor.row()->pos() &&
2870 bidi_level(pos) % 2 ==
2871 bidi_level(pos - 1) % 2)
2874 else if (pos + 1 < cursor.par()->Last())
2876 else if (pos + 1 < cursor.par()->size())
2883 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2884 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2887 if (cursor.pos() == cursor.par()->Last() &&
2889 if (cursor.pos() == cursor.par()->size() &&
2891 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2892 !cursor.boundary()) {
2893 Language const * lang =
2894 cursor.par()->getParLanguage(bview->buffer()->params);
2895 current_font.setLanguage(lang);
2896 current_font.setNumber(LyXFont::OFF);
2897 real_current_font.setLanguage(lang);
2898 real_current_font.setNumber(LyXFont::OFF);
2903 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2905 LyXCursor old_cursor = cursor;
2907 /* get the row first */
2909 Row * row = GetRowNearY(y);
2910 cursor.par(row->par());
2913 int column = GetColumnNearX(bview, row, x, bound);
2914 cursor.pos(row->pos() + column);
2916 cursor.y(y + row->baseline());
2918 cursor.boundary(bound);
2919 SetCurrentFont(bview);
2920 DeleteEmptyParagraphMechanism(bview, old_cursor);
2924 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2927 /* get the row first */
2929 Row * row = GetRowNearY(y);
2931 int column = GetColumnNearX(bview, row, x, bound);
2933 cur.par(row->par());
2934 cur.pos(row->pos() + column);
2936 cur.y(y + row->baseline());
2938 cur.boundary(bound);
2942 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2944 if (cursor.pos() > 0) {
2945 bool boundary = cursor.boundary();
2946 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2947 if (!internal && !boundary &&
2948 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2949 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2950 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2951 LyXParagraph * par = cursor.par()->previous();
2953 SetCursor(bview, par, par->Last());
2955 SetCursor(bview, par, par->size());
2961 void LyXText::CursorRight(BufferView * bview, bool internal) const
2963 if (!internal && cursor.boundary() &&
2964 !cursor.par()->IsNewline(cursor.pos()))
2965 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2967 else if (cursor.pos() < cursor.par()->Last()) {
2969 else if (cursor.pos() < cursor.par()->size()) {
2971 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2973 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2974 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2975 } else if (cursor.par()->next())
2976 SetCursor(bview, cursor.par()->next(), 0);
2980 void LyXText::CursorUp(BufferView * bview) const
2982 SetCursorFromCoordinates(bview, cursor.x_fix(),
2983 cursor.y() - cursor.row()->baseline() - 1);
2987 void LyXText::CursorDown(BufferView * bview) const
2989 SetCursorFromCoordinates(bview, cursor.x_fix(),
2990 cursor.y() - cursor.row()->baseline()
2991 + cursor.row()->height() + 1);
2995 void LyXText::CursorUpParagraph(BufferView * bview) const
2997 if (cursor.pos() > 0) {
2998 SetCursor(bview, cursor.par(), 0);
3000 else if (cursor.par()->previous()) {
3001 SetCursor(bview, cursor.par()->previous(), 0);
3006 void LyXText::CursorDownParagraph(BufferView * bview) const
3008 if (cursor.par()->next()) {
3009 SetCursor(bview, cursor.par()->next(), 0);
3012 SetCursor(bview, cursor.par(), cursor.par()->Last());
3014 SetCursor(bview, cursor.par(), cursor.par()->size());
3020 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3021 LyXCursor const & old_cursor) const
3023 // Would be wrong to delete anything if we have a selection.
3024 if (selection) return;
3026 // We allow all kinds of "mumbo-jumbo" when freespacing.
3027 if (textclasslist.Style(bview->buffer()->params.textclass,
3028 old_cursor.par()->GetLayout()).free_spacing)
3031 bool deleted = false;
3033 /* Ok I'll put some comments here about what is missing.
3034 I have fixed BackSpace (and thus Delete) to not delete
3035 double-spaces automagically. I have also changed Cut,
3036 Copy and Paste to hopefully do some sensible things.
3037 There are still some small problems that can lead to
3038 double spaces stored in the document file or space at
3039 the beginning of paragraphs. This happens if you have
3040 the cursor betwenn to spaces and then save. Or if you
3041 cut and paste and the selection have a space at the
3042 beginning and then save right after the paste. I am
3043 sure none of these are very hard to fix, but I will
3044 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3045 that I can get some feedback. (Lgb)
3048 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3049 // delete the LineSeparator.
3052 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3053 // delete the LineSeparator.
3056 // If the pos around the old_cursor were spaces, delete one of them.
3057 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3058 // Only if the cursor has really moved
3060 if (old_cursor.pos() > 0
3062 && old_cursor.pos() < old_cursor.par()->Last()
3064 && old_cursor.pos() < old_cursor.par()->size()
3066 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3067 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3068 old_cursor.par()->Erase(old_cursor.pos() - 1);
3069 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3071 if (old_cursor.par() == cursor.par() &&
3072 cursor.pos() > old_cursor.pos()) {
3073 SetCursorIntern(bview, cursor.par(),
3076 SetCursorIntern(bview, cursor.par(),
3082 // Do not delete empty paragraphs with keepempty set.
3083 if ((textclasslist.Style(bview->buffer()->params.textclass,
3084 old_cursor.par()->GetLayout())).keepempty)
3087 LyXCursor tmpcursor;
3090 if (old_cursor.par() != cursor.par()) {
3091 if ((old_cursor.par()->Last() == 0
3092 || (old_cursor.par()->Last() == 1
3093 && old_cursor.par()->IsLineSeparator(0)))
3094 && old_cursor.par()->FirstPhysicalPar()
3095 == old_cursor.par()->LastPhysicalPar()
3097 if (old_cursor.par() != cursor.par()) {
3098 if ((old_cursor.par()->size() == 0
3099 || (old_cursor.par()->size() == 1
3100 && old_cursor.par()->IsLineSeparator(0)))
3103 // ok, we will delete anything
3105 // make sure that you do not delete any environments
3108 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3109 !(old_cursor.row()->previous()
3110 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3111 && !(old_cursor.row()->next()
3112 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3113 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3114 && ((old_cursor.row()->previous()
3115 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3116 || (old_cursor.row()->next()
3117 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3120 status = LyXText::NEED_MORE_REFRESH;
3123 if (old_cursor.row()->previous()) {
3124 refresh_row = old_cursor.row()->previous();
3125 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3127 cursor = old_cursor; // that undo can restore the right cursor position
3129 LyXParagraph * endpar = old_cursor.par()->next_;
3130 if (endpar && endpar->GetDepth()) {
3131 while (endpar && endpar->GetDepth()) {
3132 endpar = endpar->LastPhysicalPar()->next();
3135 SetUndo(bview->buffer(), Undo::DELETE,
3136 old_cursor.par()->previous_,
3141 RemoveRow(old_cursor.row());
3142 if (OwnerParagraph() == old_cursor.par()) {
3143 OwnerParagraph(OwnerParagraph()->next_);
3146 LyXParagraph * endpar = old_cursor.par()->next();
3147 if (endpar && endpar->GetDepth()) {
3148 while (endpar && endpar->GetDepth()) {
3149 endpar = endpar->next();
3152 SetUndo(bview->buffer(), Undo::DELETE,
3153 old_cursor.par()->previous(),
3158 RemoveRow(old_cursor.row());
3159 if (OwnerParagraph() == old_cursor.par()) {
3160 OwnerParagraph(OwnerParagraph()->next());
3164 delete old_cursor.par();
3166 /* Breakagain the next par. Needed
3167 * because of the parindent that
3168 * can occur or dissappear. The
3169 * next row can change its height,
3170 * if there is another layout before */
3171 if (refresh_row->next()) {
3172 BreakAgain(bview, refresh_row->next());
3173 UpdateCounters(bview, refresh_row);
3175 SetHeightOfRow(bview, refresh_row);
3177 refresh_row = old_cursor.row()->next();
3178 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3181 cursor = old_cursor; // that undo can restore the right cursor position
3183 LyXParagraph * endpar = old_cursor.par()->next_;
3184 if (endpar && endpar->GetDepth()) {
3185 while (endpar && endpar->GetDepth()) {
3186 endpar = endpar->LastPhysicalPar()->next();
3189 SetUndo(bview->buffer(), Undo::DELETE,
3190 old_cursor.par()->previous_,
3195 RemoveRow(old_cursor.row());
3197 if (OwnerParagraph() == old_cursor.par()) {
3198 OwnerParagraph(OwnerParagraph()->next_);
3201 LyXParagraph * endpar = old_cursor.par()->next();
3202 if (endpar && endpar->GetDepth()) {
3203 while (endpar && endpar->GetDepth()) {
3204 endpar = endpar->next();
3207 SetUndo(bview->buffer(), Undo::DELETE,
3208 old_cursor.par()->previous(),
3213 RemoveRow(old_cursor.row());
3215 if (OwnerParagraph() == old_cursor.par()) {
3216 OwnerParagraph(OwnerParagraph()->next());
3219 delete old_cursor.par();
3221 /* Breakagain the next par. Needed
3222 because of the parindent that can
3223 occur or dissappear.
3224 The next row can change its height,
3225 if there is another layout before
3228 BreakAgain(bview, refresh_row);
3229 UpdateCounters(bview, refresh_row->previous());
3235 SetCursorIntern(bview, cursor.par(), cursor.pos());
3237 if (sel_cursor.par() == old_cursor.par()
3238 && sel_cursor.pos() == sel_cursor.pos()) {
3239 // correct selection
3240 sel_cursor = cursor;
3247 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3248 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3250 SetCursorIntern(bview, cursor.par(), cursor.pos());
3251 sel_cursor = cursor;
3259 LyXParagraph * LyXText::GetParFromID(int id)
3261 LyXParagraph * result = FirstParagraph();
3262 while (result && result->id() != id)
3263 result = result->next_;
3267 LyXParagraph * LyXText::GetParFromID(int id)
3269 LyXParagraph * result = FirstParagraph();
3270 while (result && result->id() != id)
3271 result = result->next();
3278 bool LyXText::TextUndo(BufferView * bview)
3282 // returns false if no undo possible
3283 Undo * undo = bview->buffer()->undostack.pop();
3287 bview->buffer()->redostack
3288 .push(CreateUndo(bview->buffer(), undo->kind,
3289 GetParFromID(undo->number_of_before_par),
3290 GetParFromID(undo->number_of_behind_par)));
3292 return TextHandleUndo(bview, undo);
3296 bool LyXText::TextRedo(BufferView * bview)
3300 // returns false if no redo possible
3301 Undo * undo = bview->buffer()->redostack.pop();
3305 bview->buffer()->undostack
3306 .push(CreateUndo(bview->buffer(), undo->kind,
3307 GetParFromID(undo->number_of_before_par),
3308 GetParFromID(undo->number_of_behind_par)));
3310 return TextHandleUndo(bview, undo);
3314 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3318 // returns false if no undo possible
3319 bool result = false;
3321 LyXParagraph * before =
3322 GetParFromID(undo->number_of_before_par);
3323 LyXParagraph * behind =
3324 GetParFromID(undo->number_of_behind_par);
3325 LyXParagraph * tmppar;
3326 LyXParagraph * tmppar2;
3327 LyXParagraph * endpar;
3328 LyXParagraph * tmppar5;
3330 // if there's no before take the beginning
3331 // of the document for redoing
3333 SetCursorIntern(bview, FirstParagraph(), 0);
3335 // replace the paragraphs with the undo informations
3337 LyXParagraph * tmppar3 = undo->par;
3338 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3339 LyXParagraph * tmppar4 = tmppar3;
3342 while (tmppar4->next_)
3343 tmppar4 = tmppar4->next_;
3344 } // get last undo par
3346 // now remove the old text if there is any
3347 if (before != behind || (!behind && !before)) {
3349 tmppar5 = before->next();
3351 tmppar5 = OwnerParagraph();
3353 while (tmppar5 && tmppar5 != behind) {
3355 tmppar5 = tmppar5->next();
3356 // a memory optimization for edit: Only layout information
3357 // is stored in the undo. So restore the text informations.
3358 if (undo->kind == Undo::EDIT) {
3359 tmppar2->setContentsFromPar(tmppar);
3360 tmppar->clearContents();
3361 tmppar2 = tmppar2->next();
3368 while (tmppar4->next())
3369 tmppar4 = tmppar4->next();
3370 } // get last undo par
3372 // now remove the old text if there is any
3373 if (before != behind || (!behind && !before)) {
3375 tmppar5 = before->next();
3377 tmppar5 = OwnerParagraph();
3379 while (tmppar5 && tmppar5 != behind) {
3381 tmppar5 = tmppar5->next();
3382 // a memory optimization for edit: Only layout information
3383 // is stored in the undo. So restore the text informations.
3384 if (undo->kind == Undo::EDIT) {
3385 tmppar2->setContentsFromPar(tmppar);
3386 tmppar->clearContents();
3387 tmppar2 = tmppar2->next();
3393 // put the new stuff in the list if there is one
3396 before->next(tmppar3);
3398 OwnerParagraph(tmppar3);
3399 tmppar3->previous(before);
3402 OwnerParagraph(behind);
3405 tmppar4->next(behind);
3407 behind->previous(tmppar4);
3411 // Set the cursor for redoing
3414 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3416 SetCursorIntern(bview, before, 0);
3419 // check wether before points to a closed float and open it if necessary
3420 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3421 && before->next_ && before->next_->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3423 while (tmppar4->previous_ &&
3424 tmppar4->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3425 tmppar4 = tmppar4->previous_;
3426 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3427 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3428 tmppar4 = tmppar4->next_;
3435 // open a cosed footnote at the end if necessary
3436 if (behind && behind->previous_ &&
3437 behind->previous_->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3438 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3439 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3440 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3441 behind = behind->next_;
3446 // calculate the endpar for redoing the paragraphs.
3449 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3450 endpar = behind->LastPhysicalPar()->next();
3452 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->next();
3454 endpar = behind->next();
3459 tmppar = GetParFromID(undo->number_of_cursor_par);
3460 RedoParagraphs(bview, cursor, endpar);
3462 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3463 UpdateCounters(bview, cursor.row());
3473 void LyXText::FinishUndo()
3477 // makes sure the next operation will be stored
3478 undo_finished = true;
3482 void LyXText::FreezeUndo()
3486 // this is dangerous and for internal use only
3491 void LyXText::UnFreezeUndo()
3495 // this is dangerous and for internal use only
3496 undo_frozen = false;
3500 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3501 LyXParagraph const * before,
3502 LyXParagraph const * behind) const
3507 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3508 buf->redostack.clear();
3512 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3513 LyXParagraph const * before, LyXParagraph const * behind)
3517 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3521 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3522 LyXParagraph const * before,
3523 LyXParagraph const * behind) const
3528 int before_number = -1;
3529 int behind_number = -1;
3531 before_number = before->id();
3533 behind_number = behind->id();
3534 // Undo::EDIT and Undo::FINISH are
3535 // always finished. (no overlapping there)
3536 // overlapping only with insert and delete inside one paragraph:
3537 // Nobody wants all removed character
3538 // appear one by one when undoing.
3539 // EDIT is special since only layout information, not the
3540 // contents of a paragaph are stored.
3541 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3542 // check wether storing is needed
3543 if (!buf->undostack.empty() &&
3544 buf->undostack.top()->kind == kind &&
3545 buf->undostack.top()->number_of_before_par == before_number &&
3546 buf->undostack.top()->number_of_behind_par == behind_number ){
3551 // create a new Undo
3552 LyXParagraph * undopar;
3553 LyXParagraph * tmppar;
3554 LyXParagraph * tmppar2;
3556 LyXParagraph * start = 0;
3557 LyXParagraph * end = 0;
3561 start = before->next_;
3563 start = FirstParagraph();
3565 end = behind->previous_;
3567 end = FirstParagraph();
3571 if (start && end && (start != end->next_) &&
3572 ((before != behind) || (!before && !behind))) {
3574 tmppar2 = tmppar->Clone();
3575 tmppar2->id(tmppar->id());
3577 // a memory optimization: Just store the layout information
3579 if (kind == Undo::EDIT){
3580 //tmppar2->text.clear();
3581 tmppar2->clearContents();
3586 while (tmppar != end && tmppar->next_) {
3587 tmppar = tmppar->next_;
3588 tmppar2->next(tmppar->Clone());
3589 tmppar2->next_->id(tmppar->id());
3590 // a memory optimization: Just store the layout
3591 // information when only edit
3592 if (kind == Undo::EDIT){
3593 //tmppar2->next->text.clear();
3594 tmppar2->clearContents();
3596 tmppar2->next_->previous(tmppar2);
3597 tmppar2 = tmppar2->next_;
3601 undopar = 0; // nothing to replace (undo of delete maybe)
3603 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3604 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3607 start = const_cast<LyXParagraph*>(before->next());
3609 start = FirstParagraph();
3611 end = const_cast<LyXParagraph*>(behind->previous());
3613 end = FirstParagraph();
3617 if (start && end && (start != end->next()) &&
3618 ((before != behind) || (!before && !behind))) {
3620 tmppar2 = tmppar->Clone();
3621 tmppar2->id(tmppar->id());
3623 // a memory optimization: Just store the layout information
3625 if (kind == Undo::EDIT){
3626 //tmppar2->text.clear();
3627 tmppar2->clearContents();
3632 while (tmppar != end && tmppar->next()) {
3633 tmppar = tmppar->next();
3634 tmppar2->next(tmppar->Clone());
3635 tmppar2->next()->id(tmppar->id());
3636 // a memory optimization: Just store the layout
3637 // information when only edit
3638 if (kind == Undo::EDIT){
3639 //tmppar2->next->text.clear();
3640 tmppar2->clearContents();
3642 tmppar2->next()->previous(tmppar2);
3643 tmppar2 = tmppar2->next();
3647 undopar = 0; // nothing to replace (undo of delete maybe)
3649 int cursor_par = cursor.par()->id();
3650 int cursor_pos = cursor.pos();
3653 Undo * undo = new Undo(kind,
3654 before_number, behind_number,
3655 cursor_par, cursor_pos,
3658 undo_finished = false;
3663 void LyXText::SetCursorParUndo(Buffer * buf)
3667 SetUndo(buf, Undo::FINISH,
3669 cursor.par()->ParFromPos(cursor.pos())->previous_,
3670 cursor.par()->ParFromPos(cursor.pos())->next_
3672 cursor.par()->previous(),
3673 cursor.par()->next()
3679 void LyXText::toggleAppendix(BufferView * bview)
3682 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3684 LyXParagraph * par = cursor.par();
3686 bool start = !par->params.startOfAppendix();
3688 // ensure that we have only one start_of_appendix in this document
3689 LyXParagraph * tmp = FirstParagraph();
3691 for (; tmp; tmp = tmp->next_)
3692 tmp->params.startOfAppendix(false);
3694 for (; tmp; tmp = tmp->next())
3695 tmp->params.startOfAppendix(false);
3697 par->params.startOfAppendix(start);
3699 // we can set the refreshing parameters now
3700 status = LyXText::NEED_MORE_REFRESH;
3702 refresh_row = 0; // not needed for full update
3703 UpdateCounters(bview, 0);
3704 SetCursor(bview, cursor.par(), cursor.pos());
3708 LyXParagraph * LyXText::OwnerParagraph() const
3711 return inset_owner->par;
3713 return bv_owner->buffer()->paragraph;
3717 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3720 inset_owner->par = p;
3722 bv_owner->buffer()->paragraph = p;