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)
1661 char alphaCounter(int n)
1663 if (n < 1 || n > 26)
1671 char hebrewCounter(int n)
1673 static const char hebrew[22] = {
1674 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1675 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1676 '÷', 'ø', 'ù', 'ú'
1678 if (n < 1 || n > 22)
1686 string const romanCounter(int n)
1688 static char const * roman[20] = {
1689 "i", "ii", "iii", "iv", "v",
1690 "vi", "vii", "viii", "ix", "x",
1691 "xi", "xii", "xiii", "xiv", "xv",
1692 "xvi", "xvii", "xviii", "xix", "xx"
1694 if (n < 1 || n > 20)
1703 // set the counter of a paragraph. This includes the labels
1704 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1707 // this is only relevant for the beginning of paragraph
1708 par = par->FirstPhysicalPar();
1710 LyXLayout const & layout =
1711 textclasslist.Style(buf->params.textclass,
1714 LyXTextClass const & textclass =
1715 textclasslist.TextClass(buf->params.textclass);
1717 /* copy the prev-counters to this one, unless this is the start of a
1718 footnote or of a bibliography or the very first paragraph */
1721 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1722 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1723 && par->footnotekind == LyXParagraph::FOOTNOTE)
1725 && !(textclasslist.Style(buf->params.textclass,
1726 par->previous()->GetLayout()
1727 ).labeltype != LABEL_BIBLIO
1728 && layout.labeltype == LABEL_BIBLIO)) {
1729 for (int i = 0; i < 10; ++i) {
1730 par->setCounter(i, par->previous()->GetFirstCounter(i));
1733 par->params.appendix(par->previous()->FirstPhysicalPar()->params.appendix());
1735 par->params.appendix(par->previous()->params.appendix());
1737 if (!par->params.appendix() && par->params.startOfAppendix()) {
1738 par->params.appendix(true);
1739 for (int i = 0; i < 10; ++i) {
1740 par->setCounter(i, 0);
1744 par->enumdepth = par->previous()->FirstPhysicalPar()->enumdepth;
1745 par->itemdepth = par->previous()->FirstPhysicalPar()->itemdepth;
1747 par->enumdepth = par->previous()->enumdepth;
1748 par->itemdepth = par->previous()->itemdepth;
1751 for (int i = 0; i < 10; ++i) {
1752 par->setCounter(i, 0);
1754 par->params.appendix(par->params.startOfAppendix());
1760 // if this is an open marginnote and this is the first
1761 // entry in the marginnote and the enclosing
1762 // environment is an enum/item then correct for the
1763 // LaTeX behaviour (ARRae)
1764 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1765 && par->footnotekind == LyXParagraph::MARGIN
1767 && par->previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1768 && (par->PreviousBeforeFootnote()
1769 && textclasslist.Style(buf->params.textclass,
1770 par->PreviousBeforeFootnote()->GetLayout()
1771 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1772 // Any itemize or enumerate environment in a marginnote
1773 // that is embedded in an itemize or enumerate
1774 // paragraph is seen by LaTeX as being at a deeper
1775 // level within that enclosing itemization/enumeration
1776 // even if there is a "standard" layout at the start of
1782 /* Maybe we have to increment the enumeration depth.
1783 * BUT, enumeration in a footnote is considered in isolation from its
1784 * surrounding paragraph so don't increment if this is the
1785 * first line of the footnote
1786 * AND, bibliographies can't have their depth changed ie. they
1787 * are always of depth 0
1790 && par->previous()->GetDepth() < par->GetDepth()
1791 && textclasslist.Style(buf->params.textclass,
1792 par->previous()->GetLayout()
1793 ).labeltype == LABEL_COUNTER_ENUMI
1794 && par->enumdepth < 3
1796 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1797 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1798 && par->footnotekind == LyXParagraph::FOOTNOTE)
1800 && layout.labeltype != LABEL_BIBLIO) {
1804 /* Maybe we have to decrement the enumeration depth, see note above */
1806 && par->previous()->GetDepth() > par->GetDepth()
1808 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1809 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1810 && par->footnotekind == LyXParagraph::FOOTNOTE)
1812 && layout.labeltype != LABEL_BIBLIO) {
1813 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1814 par->setCounter(6 + par->enumdepth,
1815 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1816 /* reset the counters.
1817 * A depth change is like a breaking layout
1819 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1820 par->setCounter(i, 0);
1823 if (!par->params.labelString().empty()) {
1824 par->params.labelString(string());
1827 if (layout.margintype == MARGIN_MANUAL) {
1828 if (par->params.labelWidthString().empty()) {
1829 par->SetLabelWidthString(layout.labelstring());
1832 par->SetLabelWidthString(string());
1835 /* is it a layout that has an automatic label ? */
1836 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1838 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1839 if (i >= 0 && i<= buf->params.secnumdepth) {
1840 par->incCounter(i); // increment the counter
1842 // Is there a label? Useful for Chapter layout
1843 if (!par->params.appendix()) {
1844 if (!layout.labelstring().empty())
1845 par->params.labelString(layout.labelstring());
1847 par->params.labelString(string());
1849 if (!layout.labelstring_appendix().empty())
1850 par->params.labelString(layout.labelstring_appendix());
1852 par->params.labelString(string());
1855 std::ostringstream s;
1857 if (!par->params.appendix()) {
1858 switch (2 * LABEL_COUNTER_CHAPTER -
1859 textclass.maxcounter() + i) {
1860 case LABEL_COUNTER_CHAPTER:
1861 s << par->getCounter(i);
1863 case LABEL_COUNTER_SECTION:
1864 s << par->getCounter(i - 1) << '.'
1865 << par->getCounter(i);
1867 case LABEL_COUNTER_SUBSECTION:
1868 s << par->getCounter(i - 2) << '.'
1869 << par->getCounter(i - 1) << '.'
1870 << par->getCounter(i);
1872 case LABEL_COUNTER_SUBSUBSECTION:
1873 s << par->getCounter(i - 3) << '.'
1874 << par->getCounter(i - 2) << '.'
1875 << par->getCounter(i - 1) << '.'
1876 << par->getCounter(i);
1879 case LABEL_COUNTER_PARAGRAPH:
1880 s << par->getCounter(i - 4) << '.'
1881 << par->getCounter(i - 3) << '.'
1882 << par->getCounter(i - 2) << '.'
1883 << par->getCounter(i - 1) << '.'
1884 << par->getCounter(i);
1886 case LABEL_COUNTER_SUBPARAGRAPH:
1887 s << par->getCounter(i - 5) << '.'
1888 << par->getCounter(i - 4) << '.'
1889 << par->getCounter(i - 3) << '.'
1890 << par->getCounter(i - 2) << '.'
1891 << par->getCounter(i - 1) << '.'
1892 << par->getCounter(i);
1896 // Can this ever be reached? And in the
1897 // case it is, how can this be correct?
1899 s << par->getCounter(i) << '.';
1902 } else { // appendix
1903 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1904 case LABEL_COUNTER_CHAPTER:
1905 if (par->isRightToLeftPar(buf->params))
1906 s << hebrewCounter(par->getCounter(i));
1908 s << alphaCounter(par->getCounter(i));
1910 case LABEL_COUNTER_SECTION:
1911 if (par->isRightToLeftPar(buf->params))
1912 s << hebrewCounter(par->getCounter(i - 1));
1914 s << alphaCounter(par->getCounter(i - 1));
1917 << par->getCounter(i);
1920 case LABEL_COUNTER_SUBSECTION:
1921 if (par->isRightToLeftPar(buf->params))
1922 s << hebrewCounter(par->getCounter(i - 2));
1924 s << alphaCounter(par->getCounter(i - 2));
1927 << par->getCounter(i-1) << '.'
1928 << par->getCounter(i);
1931 case LABEL_COUNTER_SUBSUBSECTION:
1932 if (par->isRightToLeftPar(buf->params))
1933 s << hebrewCounter(par->getCounter(i-3));
1935 s << alphaCounter(par->getCounter(i-3));
1938 << par->getCounter(i-2) << '.'
1939 << par->getCounter(i-1) << '.'
1940 << par->getCounter(i);
1943 case LABEL_COUNTER_PARAGRAPH:
1944 if (par->isRightToLeftPar(buf->params))
1945 s << hebrewCounter(par->getCounter(i-4));
1947 s << alphaCounter(par->getCounter(i-4));
1950 << par->getCounter(i-3) << '.'
1951 << par->getCounter(i-2) << '.'
1952 << par->getCounter(i-1) << '.'
1953 << par->getCounter(i);
1956 case LABEL_COUNTER_SUBPARAGRAPH:
1957 if (par->isRightToLeftPar(buf->params))
1958 s << hebrewCounter(par->getCounter(i-5));
1960 s << alphaCounter(par->getCounter(i-5));
1963 << par->getCounter(i-4) << '.'
1964 << par->getCounter(i-3) << '.'
1965 << par->getCounter(i-2) << '.'
1966 << par->getCounter(i-1) << '.'
1967 << par->getCounter(i);
1971 // Can this ever be reached? And in the
1972 // case it is, how can this be correct?
1974 s << par->getCounter(i) << '.';
1980 par->params.labelString(par->params.labelString() +s.str().c_str());
1981 // We really want to remove the c_str as soon as
1984 for (i++; i < 10; ++i) {
1985 // reset the following counters
1986 par->setCounter(i, 0);
1988 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1989 for (i++; i < 10; ++i) {
1990 // reset the following counters
1991 par->setCounter(i, 0);
1993 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1994 par->incCounter(i + par->enumdepth);
1995 int number = par->getCounter(i + par->enumdepth);
1997 std::ostringstream s;
1999 switch (par->enumdepth) {
2001 if (par->isRightToLeftPar(buf->params))
2003 << hebrewCounter(number)
2007 << loweralphaCounter(number)
2011 if (par->isRightToLeftPar(buf->params))
2012 s << '.' << romanCounter(number);
2014 s << romanCounter(number) << '.';
2017 if (par->isRightToLeftPar(buf->params))
2019 << alphaCounter(number);
2021 s << alphaCounter(number)
2025 if (par->isRightToLeftPar(buf->params))
2032 par->params.labelString(s.str().c_str());
2033 // we really want to get rid of that c_str()
2035 for (i += par->enumdepth + 1; i < 10; ++i)
2036 par->setCounter(i, 0); /* reset the following counters */
2039 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2040 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2042 int number = par->getCounter(i);
2044 InsetCommandParams p( "bibitem" );
2045 par->bibkey = new InsetBibKey(p);
2047 par->bibkey->setCounter(number);
2048 par->params.labelString(layout.labelstring());
2050 // In biblio should't be following counters but...
2052 string s = layout.labelstring();
2054 // the caption hack:
2055 if (layout.labeltype == LABEL_SENSITIVE) {
2056 bool isOK (par->InInset() && par->InInset()->owner() &&
2057 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2059 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2060 && (par->footnotekind == LyXParagraph::FIG
2061 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2062 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2063 ? ":øåéà " : "Figure:";
2064 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2065 && (par->footnotekind == LyXParagraph::TAB
2066 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2067 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2068 ? ":äìáè" : "Table:";
2069 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2070 && par->footnotekind == LyXParagraph::ALGORITHM) {
2071 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2072 ? ":Ãúéøåâìà " : "Algorithm:";
2076 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2078 = floatList.getType(tmp->type());
2079 // We should get the correct number here too.
2080 s = fl.name() + " #:";
2082 /* par->SetLayout(0);
2083 s = layout->labelstring; */
2084 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2085 ? " :úåòîùî øñç" : "Senseless: ";
2088 par->params.labelString(s);
2090 /* reset the enumeration counter. They are always resetted
2091 * when there is any other layout between */
2092 for (int i = 6 + par->enumdepth; i < 10; ++i)
2093 par->setCounter(i, 0);
2098 /* Updates all counters BEHIND the row. Changed paragraphs
2099 * with a dynamic left margin will be rebroken. */
2100 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2107 } else if (row->par()->next_
2108 && row->par()->next_->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
2109 par = row->par()->LastPhysicalPar()->next();
2111 par = row->par()->next_;
2118 par = row->par()->next();
2123 while (row->par() != par)
2126 SetCounter(bview->buffer(), par);
2128 /* now check for the headline layouts. remember that they
2129 * have a dynamic left margin */
2134 ( textclasslist.Style(bview->buffer()->params.textclass,
2135 par->layout).margintype == MARGIN_DYNAMIC
2136 || textclasslist.Style(bview->buffer()->params.textclass,
2137 par->layout).labeltype == LABEL_SENSITIVE)
2140 /* Rebreak the paragraph */
2141 RemoveParagraph(row);
2142 AppendParagraph(bview, row);
2145 /* think about the damned open footnotes! */
2146 while (par->next() &&
2147 (par->next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2148 || par->next()->IsDummy())){
2150 if (par->IsDummy()) {
2151 while (row->par() != par)
2153 RemoveParagraph(row);
2154 AppendParagraph(bview, row);
2160 par = par->LastPhysicalPar()->next();
2169 /* insets an inset. */
2170 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2172 if (!cursor.par()->InsertInsetAllowed(inset))
2174 SetUndo(bview->buffer(), Undo::INSERT,
2176 cursor.par()->ParFromPos(cursor.pos())->previous_,
2177 cursor.par()->ParFromPos(cursor.pos())->next_
2179 cursor.par()->previous(),
2180 cursor.par()->next()
2183 cursor.par()->InsertInset(cursor.pos(), inset);
2184 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2185 * The character will not be inserted a
2188 // If we enter a highly editable inset the cursor should be to before
2189 // the inset. This couldn't happen before as Undo was not handled inside
2190 // inset now after the Undo LyX tries to call inset->Edit(...) again
2191 // and cannot do this as the cursor is behind the inset and GetInset
2192 // does not return the inset!
2193 if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
2194 CursorLeft(bview, true);
2200 void LyXText::copyEnvironmentType()
2202 copylayouttype = cursor.par()->GetLayout();
2206 void LyXText::pasteEnvironmentType(BufferView * bview)
2208 SetLayout(bview, copylayouttype);
2212 void LyXText::CutSelection(BufferView * bview, bool doclear)
2214 // Stuff what we got on the clipboard. Even if there is no selection.
2216 // There is a problem with having the stuffing here in that the
2217 // larger the selection the slower LyX will get. This can be
2218 // solved by running the line below only when the selection has
2219 // finished. The solution used currently just works, to make it
2220 // faster we need to be more clever and probably also have more
2221 // calls to stuffClipboard. (Lgb)
2222 bview->stuffClipboard(selectionAsString(bview->buffer()));
2224 // This doesn't make sense, if there is no selection
2228 // OK, we have a selection. This is always between sel_start_cursor
2229 // and sel_end_cursor
2231 // Check whether there are half footnotes in the selection
2232 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2233 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2234 LyXParagraph * tmppar = sel_start_cursor.par();
2235 while (tmppar != sel_end_cursor.par()){
2236 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2237 WriteAlert(_("Impossible operation"),
2238 _("Don't know what to do with half floats."),
2242 tmppar = tmppar->next();
2247 // make sure that the depth behind the selection are restored, too
2249 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
2251 LyXParagraph * endpar = sel_end_cursor.par()->next();
2253 LyXParagraph * undoendpar = endpar;
2255 if (endpar && endpar->GetDepth()) {
2256 while (endpar && endpar->GetDepth()) {
2258 endpar = endpar->LastPhysicalPar()->next();
2260 endpar = endpar->next();
2262 undoendpar = endpar;
2264 } else if (endpar) {
2265 endpar = endpar->next(); // because of parindents etc.
2268 SetUndo(bview->buffer(), Undo::DELETE,
2271 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
2273 sel_start_cursor.par()->previous(),
2279 // there are two cases: cut only within one paragraph or
2280 // more than one paragraph
2282 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2283 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2285 if (sel_start_cursor.par() == sel_end_cursor.par())
2288 // only within one paragraph
2289 endpar = sel_start_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);
2294 sel_end_cursor.pos(pos);
2296 endpar = sel_end_cursor.par();
2298 int pos = sel_end_cursor.pos();
2299 cap.cutSelection(sel_start_cursor.par(), &endpar,
2300 sel_start_cursor.pos(), pos,
2301 bview->buffer()->params.textclass, doclear);
2303 sel_end_cursor.par(endpar);
2304 sel_end_cursor.pos(pos);
2305 cursor.pos(sel_end_cursor.pos());
2307 endpar = endpar->next();
2309 // sometimes necessary
2311 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2313 RedoParagraphs(bview, sel_start_cursor, endpar);
2315 ClearSelection(bview);
2316 cursor = sel_start_cursor;
2317 SetCursor(bview, cursor.par(), cursor.pos());
2318 sel_cursor = cursor;
2319 UpdateCounters(bview, cursor.row());
2323 void LyXText::CopySelection(BufferView * bview)
2325 // Stuff what we got on the clipboard. Even if there is no selection.
2327 // There is a problem with having the stuffing here in that the
2328 // larger the selection the slower LyX will get. This can be
2329 // solved by running the line below only when the selection has
2330 // finished. The solution used currently just works, to make it
2331 // faster we need to be more clever and probably also have more
2332 // calls to stuffClipboard. (Lgb)
2333 bview->stuffClipboard(selectionAsString(bview->buffer()));
2335 // this doesnt make sense, if there is no selection
2339 // ok we have a selection. This is always between sel_start_cursor
2340 // and sel_end cursor
2343 /* check wether there are half footnotes in the selection */
2344 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2345 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2346 LyXParagraph * tmppar = sel_start_cursor.par();
2347 while (tmppar != sel_end_cursor.par()) {
2348 if (tmppar->footnoteflag !=
2349 sel_end_cursor.par()->footnoteflag) {
2350 WriteAlert(_("Impossible operation"),
2351 _("Don't know what to do"
2352 " with half floats."),
2356 tmppar = tmppar->next();
2361 // copy behind a space if there is one
2363 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2365 while (sel_start_cursor.par()->size() > sel_start_cursor.pos()
2367 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2368 && (sel_start_cursor.par() != sel_end_cursor.par()
2369 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2370 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2374 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2375 sel_start_cursor.pos(), sel_end_cursor.pos(),
2376 bview->buffer()->params.textclass);
2380 void LyXText::PasteSelection(BufferView * bview)
2384 // this does not make sense, if there is nothing to paste
2385 if (!cap.checkPastePossible(cursor.par()))
2388 SetUndo(bview->buffer(), Undo::INSERT,
2390 cursor.par()->ParFromPos(cursor.pos())->previous_,
2391 cursor.par()->ParFromPos(cursor.pos())->next_
2393 cursor.par()->previous(),
2394 cursor.par()->next()
2398 LyXParagraph * endpar;
2399 LyXParagraph * actpar = cursor.par();
2401 int pos = cursor.pos();
2402 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2404 RedoParagraphs(bview, cursor, endpar);
2406 SetCursor(bview, cursor.par(), cursor.pos());
2407 ClearSelection(bview);
2409 sel_cursor = cursor;
2410 SetCursor(bview, actpar, pos);
2411 SetSelection(bview);
2412 UpdateCounters(bview, cursor.row());
2416 // returns a pointer to the very first LyXParagraph
2417 LyXParagraph * LyXText::FirstParagraph() const
2419 return OwnerParagraph();
2423 // sets the selection over the number of characters of string, no check!!
2424 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2426 sel_cursor = cursor;
2427 for (int i = 0; str[i]; ++i)
2429 SetSelection(bview);
2433 // simple replacing. The font of the first selected character is used
2434 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2437 SetCursorParUndo(bview->buffer());
2440 if (!selection) { // create a dummy selection
2441 sel_end_cursor = cursor;
2442 sel_start_cursor = cursor;
2445 // Get font setting before we cut
2446 LyXParagraph::size_type pos = sel_end_cursor.pos();
2447 LyXFont const font = sel_start_cursor.par()
2448 ->GetFontSettings(bview->buffer()->params,
2449 sel_start_cursor.pos());
2451 // Insert the new string
2452 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2453 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2457 // Cut the selection
2458 CutSelection(bview);
2464 // needed to insert the selection
2465 void LyXText::InsertStringA(BufferView * bview, string const & str)
2467 LyXParagraph * par = cursor.par();
2468 LyXParagraph::size_type pos = cursor.pos();
2469 LyXParagraph::size_type a = 0;
2470 LyXParagraph * endpar = cursor.par()->next();
2472 SetCursorParUndo(bview->buffer());
2475 textclasslist.Style(bview->buffer()->params.textclass,
2476 cursor.par()->GetLayout()).isEnvironment();
2477 // only to be sure, should not be neccessary
2478 ClearSelection(bview);
2480 // insert the string, don't insert doublespace
2481 string::size_type i = 0;
2482 while (i < str.length()) {
2483 if (str[i] != '\n') {
2485 && i + 1 < str.length() && str[i + 1] != ' '
2486 && pos && par->GetChar(pos - 1)!= ' ') {
2487 par->InsertChar(pos, ' ', current_font);
2489 } else if (str[i] == ' ') {
2490 InsetSpecialChar * new_inset =
2491 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2492 if (par->InsertInsetAllowed(new_inset)) {
2493 par->InsertInset(pos, new_inset,
2499 } else if (str[i] == '\t') {
2500 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2501 InsetSpecialChar * new_inset =
2502 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2503 if (par->InsertInsetAllowed(new_inset)) {
2504 par->InsertInset(pos, new_inset,
2511 } else if (str[i] != 13 &&
2512 // Ignore unprintables
2513 (str[i] & 127) >= ' ') {
2514 par->InsertChar(pos, str[i], current_font);
2518 if (!par->size()) { // par is empty
2519 InsetSpecialChar * new_inset =
2520 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2521 if (par->InsertInsetAllowed(new_inset)) {
2522 par->InsertInset(pos,
2530 par->BreakParagraph(bview->buffer()->params, pos, flag);
2537 RedoParagraphs(bview, cursor, endpar);
2538 SetCursor(bview, cursor.par(), cursor.pos());
2539 sel_cursor = cursor;
2540 SetCursor(bview, par, pos);
2541 SetSelection(bview);
2545 /* turns double-CR to single CR, others where converted into one blank and 13s
2546 * that are ignored .Double spaces are also converted into one. Spaces at
2547 * the beginning of a paragraph are forbidden. tabs are converted into one
2548 * space. then InsertStringA is called */
2549 void LyXText::InsertStringB(BufferView * bview, string const & s)
2552 string::size_type i = 1;
2553 while (i < str.length()) {
2556 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2558 if (str[i] == '\n' && i + 1 < str.length()) {
2559 if (str[i + 1] != '\n') {
2560 if (str[i - 1] != ' ')
2565 while (i + 1 < str.length()
2566 && (str[i + 1] == ' '
2567 || str[i + 1] == '\t'
2568 || str[i + 1] == '\n'
2569 || str[i + 1] == 13)) {
2576 InsertStringA(bview, str);
2580 bool LyXText::GotoNextInset(BufferView * bview,
2581 std::vector<Inset::Code> const & codes,
2582 string const & contents) const
2584 LyXCursor res = cursor;
2588 if (res.pos() < res.par()->Last() - 1) {
2590 if (res.pos() < res.par()->size() - 1) {
2592 res.pos(res.pos() + 1);
2594 res.par(res.par()->next());
2598 } while (res.par() &&
2599 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2600 && (inset = res.par()->GetInset(res.pos())) != 0
2601 && find(codes.begin(), codes.end(), inset->LyxCode())
2603 && (contents.empty() ||
2604 static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
2608 SetCursor(bview, res.par(), res.pos());
2615 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2616 LyXParagraph::size_type pos)
2618 LyXCursor tmpcursor;
2621 LyXParagraph::size_type z;
2622 Row * row = GetRow(par, pos, y);
2624 // is there a break one row above
2625 if (row->previous() && row->previous()->par() == row->par()) {
2626 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2627 if (z >= row->pos()) {
2628 // set the dimensions of the row above
2629 y -= row->previous()->height();
2631 refresh_row = row->previous();
2632 status = LyXText::NEED_MORE_REFRESH;
2634 BreakAgain(bview, row->previous());
2636 // set the cursor again. Otherwise
2637 // dangling pointers are possible
2638 SetCursor(bview, cursor.par(), cursor.pos(),
2639 false, cursor.boundary());
2640 sel_cursor = cursor;
2645 int const tmpheight = row->height();
2646 LyXParagraph::size_type const tmplast = RowLast(row);
2650 BreakAgain(bview, row);
2651 if (row->height() == tmpheight && RowLast(row) == tmplast)
2652 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2654 status = LyXText::NEED_MORE_REFRESH;
2656 // check the special right address boxes
2657 if (textclasslist.Style(bview->buffer()->params.textclass,
2658 par->GetLayout()).margintype
2659 == MARGIN_RIGHT_ADDRESS_BOX) {
2666 RedoDrawingOfParagraph(bview, tmpcursor);
2669 // set the cursor again. Otherwise dangling pointers are possible
2670 // also set the selection
2674 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2675 false, sel_cursor.boundary());
2676 sel_cursor = cursor;
2677 SetCursorIntern(bview, sel_start_cursor.par(),
2678 sel_start_cursor.pos(),
2679 false, sel_start_cursor.boundary());
2680 sel_start_cursor = cursor;
2681 SetCursorIntern(bview, sel_end_cursor.par(),
2682 sel_end_cursor.pos(),
2683 false, sel_end_cursor.boundary());
2684 sel_end_cursor = cursor;
2685 SetCursorIntern(bview, last_sel_cursor.par(),
2686 last_sel_cursor.pos(),
2687 false, last_sel_cursor.boundary());
2688 last_sel_cursor = cursor;
2691 SetCursorIntern(bview, cursor.par(), cursor.pos(),
2692 false, cursor.boundary());
2696 // returns false if inset wasn't found
2697 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2699 // first check the current paragraph
2700 int pos = cursor.par()->GetPositionOfInset(inset);
2702 CheckParagraph(bview, cursor.par(), pos);
2706 // check every paragraph
2708 LyXParagraph * par = FirstParagraph();
2711 // make sure the paragraph is open
2712 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2714 pos = par->GetPositionOfInset(inset);
2716 CheckParagraph(bview, par, pos);
2729 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2730 LyXParagraph::size_type pos,
2731 bool setfont, bool boundary) const
2733 LyXCursor old_cursor = cursor;
2734 SetCursorIntern(bview, par, pos, setfont, boundary);
2735 DeleteEmptyParagraphMechanism(bview, old_cursor);
2739 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2740 LyXParagraph::size_type pos, bool boundary) const
2743 // correct the cursor position if impossible
2744 if (pos > par->Last()){
2745 LyXParagraph * tmppar = par->ParFromPos(pos);
2746 pos = par->PositionInParFromPos(pos);
2749 if (par->IsDummy() && par->previous_ &&
2750 par->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2751 while (par->previous_ &&
2752 ((par->previous_->IsDummy() &&
2753 (par->previous_->previous_->footnoteflag ==
2754 LyXParagraph::CLOSED_FOOTNOTE)) ||
2755 (par->previous_->footnoteflag ==
2756 LyXParagraph::CLOSED_FOOTNOTE))) {
2757 par = par->previous_;
2758 if (par->IsDummy() &&
2759 (par->previous_->footnoteflag ==
2760 LyXParagraph::CLOSED_FOOTNOTE))
2761 pos += par->size() + 1;
2763 if (par->previous_) {
2764 par = par->previous_;
2766 pos += par->size() + 1;
2771 cur.boundary(boundary);
2773 /* get the cursor y position in text */
2775 Row * row = GetRow(par, pos, y);
2776 /* y is now the beginning of the cursor row */
2777 y += row->baseline();
2778 /* y is now the cursor baseline */
2781 /* now get the cursors x position */
2783 float fill_separator, fill_hfill, fill_label_hfill;
2784 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2786 LyXParagraph::size_type cursor_vpos = 0;
2787 LyXParagraph::size_type last = RowLastPrintable(row);
2789 if (pos > last + 1) // This shouldn't happen.
2791 else if (pos < row->pos())
2794 if (last < row->pos())
2795 cursor_vpos = row->pos();
2796 else if (pos > last && !boundary)
2797 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2798 ? row->pos() : last + 1;
2799 else if (pos > row->pos() &&
2800 (pos > last || boundary))
2801 /// Place cursor after char at (logical) position pos - 1
2802 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2803 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2805 /// Place cursor before char at (logical) position pos
2806 cursor_vpos = (bidi_level(pos) % 2 == 0)
2807 ? log2vis(pos) : log2vis(pos) + 1;
2809 LyXParagraph::size_type main_body =
2810 BeginningOfMainBody(bview->buffer(), row->par());
2811 if ((main_body > 0) &&
2812 ((main_body-1 > last) ||
2813 !row->par()->IsLineSeparator(main_body-1)))
2816 for (LyXParagraph::size_type vpos = row->pos();
2817 vpos < cursor_vpos; ++vpos) {
2818 pos = vis2log(vpos);
2819 if (main_body > 0 && pos == main_body - 1) {
2820 x += fill_label_hfill +
2821 lyxfont::width(textclasslist.Style(
2822 bview->buffer()->params.textclass,
2823 row->par()->GetLayout())
2825 GetFont(bview->buffer(), row->par(), -2));
2826 if (row->par()->IsLineSeparator(main_body-1))
2827 x -= SingleWidth(bview, row->par(),main_body-1);
2829 if (HfillExpansion(bview->buffer(), row, pos)) {
2830 x += SingleWidth(bview, row->par(), pos);
2831 if (pos >= main_body)
2834 x += fill_label_hfill;
2835 } else if (row->par()->IsSeparator(pos)) {
2836 x += SingleWidth(bview, row->par(), pos);
2837 if (pos >= main_body)
2838 x += fill_separator;
2840 x += SingleWidth(bview, row->par(), pos);
2849 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2850 LyXParagraph::size_type pos,
2851 bool setfont, bool boundary) const
2853 SetCursor(bview, cursor, par, pos, boundary);
2855 SetCurrentFont(bview);
2859 void LyXText::SetCurrentFont(BufferView * bview) const
2861 LyXParagraph::size_type pos = cursor.pos();
2862 if (cursor.boundary() && pos > 0)
2867 if (pos == cursor.par()->Last())
2869 if (pos == cursor.par()->size())
2872 else if (cursor.par()->IsSeparator(pos)) {
2873 if (pos > cursor.row()->pos() &&
2874 bidi_level(pos) % 2 ==
2875 bidi_level(pos - 1) % 2)
2878 else if (pos + 1 < cursor.par()->Last())
2880 else if (pos + 1 < cursor.par()->size())
2887 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2888 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2891 if (cursor.pos() == cursor.par()->Last() &&
2893 if (cursor.pos() == cursor.par()->size() &&
2895 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2896 !cursor.boundary()) {
2897 Language const * lang =
2898 cursor.par()->getParLanguage(bview->buffer()->params);
2899 current_font.setLanguage(lang);
2900 current_font.setNumber(LyXFont::OFF);
2901 real_current_font.setLanguage(lang);
2902 real_current_font.setNumber(LyXFont::OFF);
2907 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2909 LyXCursor old_cursor = cursor;
2911 /* get the row first */
2913 Row * row = GetRowNearY(y);
2914 cursor.par(row->par());
2917 int column = GetColumnNearX(bview, row, x, bound);
2918 cursor.pos(row->pos() + column);
2920 cursor.y(y + row->baseline());
2922 cursor.boundary(bound);
2923 SetCurrentFont(bview);
2924 DeleteEmptyParagraphMechanism(bview, old_cursor);
2928 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2931 /* get the row first */
2933 Row * row = GetRowNearY(y);
2935 int column = GetColumnNearX(bview, row, x, bound);
2937 cur.par(row->par());
2938 cur.pos(row->pos() + column);
2940 cur.y(y + row->baseline());
2942 cur.boundary(bound);
2946 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2948 if (cursor.pos() > 0) {
2949 bool boundary = cursor.boundary();
2950 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2951 if (!internal && !boundary &&
2952 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2953 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2954 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2955 LyXParagraph * par = cursor.par()->previous();
2957 SetCursor(bview, par, par->Last());
2959 SetCursor(bview, par, par->size());
2965 void LyXText::CursorRight(BufferView * bview, bool internal) const
2967 if (!internal && cursor.boundary() &&
2968 !cursor.par()->IsNewline(cursor.pos()))
2969 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2971 else if (cursor.pos() < cursor.par()->Last()) {
2973 else if (cursor.pos() < cursor.par()->size()) {
2975 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2977 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2978 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2979 } else if (cursor.par()->next())
2980 SetCursor(bview, cursor.par()->next(), 0);
2984 void LyXText::CursorUp(BufferView * bview) const
2986 SetCursorFromCoordinates(bview, cursor.x_fix(),
2987 cursor.y() - cursor.row()->baseline() - 1);
2991 void LyXText::CursorDown(BufferView * bview) const
2993 SetCursorFromCoordinates(bview, cursor.x_fix(),
2994 cursor.y() - cursor.row()->baseline()
2995 + cursor.row()->height() + 1);
2999 void LyXText::CursorUpParagraph(BufferView * bview) const
3001 if (cursor.pos() > 0) {
3002 SetCursor(bview, cursor.par(), 0);
3004 else if (cursor.par()->previous()) {
3005 SetCursor(bview, cursor.par()->previous(), 0);
3010 void LyXText::CursorDownParagraph(BufferView * bview) const
3012 if (cursor.par()->next()) {
3013 SetCursor(bview, cursor.par()->next(), 0);
3016 SetCursor(bview, cursor.par(), cursor.par()->Last());
3018 SetCursor(bview, cursor.par(), cursor.par()->size());
3024 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3025 LyXCursor const & old_cursor) const
3027 // Would be wrong to delete anything if we have a selection.
3028 if (selection) return;
3030 // We allow all kinds of "mumbo-jumbo" when freespacing.
3031 if (textclasslist.Style(bview->buffer()->params.textclass,
3032 old_cursor.par()->GetLayout()).free_spacing)
3035 bool deleted = false;
3037 /* Ok I'll put some comments here about what is missing.
3038 I have fixed BackSpace (and thus Delete) to not delete
3039 double-spaces automagically. I have also changed Cut,
3040 Copy and Paste to hopefully do some sensible things.
3041 There are still some small problems that can lead to
3042 double spaces stored in the document file or space at
3043 the beginning of paragraphs. This happens if you have
3044 the cursor betwenn to spaces and then save. Or if you
3045 cut and paste and the selection have a space at the
3046 beginning and then save right after the paste. I am
3047 sure none of these are very hard to fix, but I will
3048 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3049 that I can get some feedback. (Lgb)
3052 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3053 // delete the LineSeparator.
3056 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3057 // delete the LineSeparator.
3060 // If the pos around the old_cursor were spaces, delete one of them.
3061 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3062 // Only if the cursor has really moved
3064 if (old_cursor.pos() > 0
3066 && old_cursor.pos() < old_cursor.par()->Last()
3068 && old_cursor.pos() < old_cursor.par()->size()
3070 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3071 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3072 old_cursor.par()->Erase(old_cursor.pos() - 1);
3073 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3075 if (old_cursor.par() == cursor.par() &&
3076 cursor.pos() > old_cursor.pos()) {
3077 SetCursorIntern(bview, cursor.par(),
3080 SetCursorIntern(bview, cursor.par(),
3086 // Do not delete empty paragraphs with keepempty set.
3087 if ((textclasslist.Style(bview->buffer()->params.textclass,
3088 old_cursor.par()->GetLayout())).keepempty)
3091 LyXCursor tmpcursor;
3094 if (old_cursor.par() != cursor.par()) {
3095 if ((old_cursor.par()->Last() == 0
3096 || (old_cursor.par()->Last() == 1
3097 && old_cursor.par()->IsLineSeparator(0)))
3098 && old_cursor.par()->FirstPhysicalPar()
3099 == old_cursor.par()->LastPhysicalPar()
3101 if (old_cursor.par() != cursor.par()) {
3102 if ((old_cursor.par()->size() == 0
3103 || (old_cursor.par()->size() == 1
3104 && old_cursor.par()->IsLineSeparator(0)))
3107 // ok, we will delete anything
3109 // make sure that you do not delete any environments
3112 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3113 !(old_cursor.row()->previous()
3114 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3115 && !(old_cursor.row()->next()
3116 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3117 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3118 && ((old_cursor.row()->previous()
3119 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3120 || (old_cursor.row()->next()
3121 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3124 status = LyXText::NEED_MORE_REFRESH;
3127 if (old_cursor.row()->previous()) {
3128 refresh_row = old_cursor.row()->previous();
3129 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3131 cursor = old_cursor; // that undo can restore the right cursor position
3133 LyXParagraph * endpar = old_cursor.par()->next_;
3134 if (endpar && endpar->GetDepth()) {
3135 while (endpar && endpar->GetDepth()) {
3136 endpar = endpar->LastPhysicalPar()->next();
3139 SetUndo(bview->buffer(), Undo::DELETE,
3140 old_cursor.par()->previous_,
3145 RemoveRow(old_cursor.row());
3146 if (OwnerParagraph() == old_cursor.par()) {
3147 OwnerParagraph(OwnerParagraph()->next_);
3150 LyXParagraph * endpar = old_cursor.par()->next();
3151 if (endpar && endpar->GetDepth()) {
3152 while (endpar && endpar->GetDepth()) {
3153 endpar = endpar->next();
3156 SetUndo(bview->buffer(), Undo::DELETE,
3157 old_cursor.par()->previous(),
3162 RemoveRow(old_cursor.row());
3163 if (OwnerParagraph() == old_cursor.par()) {
3164 OwnerParagraph(OwnerParagraph()->next());
3168 delete old_cursor.par();
3170 /* Breakagain the next par. Needed
3171 * because of the parindent that
3172 * can occur or dissappear. The
3173 * next row can change its height,
3174 * if there is another layout before */
3175 if (refresh_row->next()) {
3176 BreakAgain(bview, refresh_row->next());
3177 UpdateCounters(bview, refresh_row);
3179 SetHeightOfRow(bview, refresh_row);
3181 refresh_row = old_cursor.row()->next();
3182 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3185 cursor = old_cursor; // that undo can restore the right cursor position
3187 LyXParagraph * endpar = old_cursor.par()->next_;
3188 if (endpar && endpar->GetDepth()) {
3189 while (endpar && endpar->GetDepth()) {
3190 endpar = endpar->LastPhysicalPar()->next();
3193 SetUndo(bview->buffer(), Undo::DELETE,
3194 old_cursor.par()->previous_,
3199 RemoveRow(old_cursor.row());
3201 if (OwnerParagraph() == old_cursor.par()) {
3202 OwnerParagraph(OwnerParagraph()->next_);
3205 LyXParagraph * endpar = old_cursor.par()->next();
3206 if (endpar && endpar->GetDepth()) {
3207 while (endpar && endpar->GetDepth()) {
3208 endpar = endpar->next();
3211 SetUndo(bview->buffer(), Undo::DELETE,
3212 old_cursor.par()->previous(),
3217 RemoveRow(old_cursor.row());
3219 if (OwnerParagraph() == old_cursor.par()) {
3220 OwnerParagraph(OwnerParagraph()->next());
3223 delete old_cursor.par();
3225 /* Breakagain the next par. Needed
3226 because of the parindent that can
3227 occur or dissappear.
3228 The next row can change its height,
3229 if there is another layout before
3232 BreakAgain(bview, refresh_row);
3233 UpdateCounters(bview, refresh_row->previous());
3239 SetCursorIntern(bview, cursor.par(), cursor.pos());
3241 if (sel_cursor.par() == old_cursor.par()
3242 && sel_cursor.pos() == sel_cursor.pos()) {
3243 // correct selection
3244 sel_cursor = cursor;
3251 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3252 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3254 SetCursorIntern(bview, cursor.par(), cursor.pos());
3255 sel_cursor = cursor;
3263 LyXParagraph * LyXText::GetParFromID(int id)
3265 LyXParagraph * result = FirstParagraph();
3266 while (result && result->id() != id)
3267 result = result->next_;
3271 LyXParagraph * LyXText::GetParFromID(int id)
3273 LyXParagraph * result = FirstParagraph();
3274 while (result && result->id() != id)
3275 result = result->next();
3282 bool LyXText::TextUndo(BufferView * bview)
3286 // returns false if no undo possible
3287 Undo * undo = bview->buffer()->undostack.pop();
3291 bview->buffer()->redostack
3292 .push(CreateUndo(bview->buffer(), undo->kind,
3293 GetParFromID(undo->number_of_before_par),
3294 GetParFromID(undo->number_of_behind_par)));
3296 return TextHandleUndo(bview, undo);
3300 bool LyXText::TextRedo(BufferView * bview)
3304 // returns false if no redo possible
3305 Undo * undo = bview->buffer()->redostack.pop();
3309 bview->buffer()->undostack
3310 .push(CreateUndo(bview->buffer(), undo->kind,
3311 GetParFromID(undo->number_of_before_par),
3312 GetParFromID(undo->number_of_behind_par)));
3314 return TextHandleUndo(bview, undo);
3318 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3322 // returns false if no undo possible
3323 bool result = false;
3325 LyXParagraph * before =
3326 GetParFromID(undo->number_of_before_par);
3327 LyXParagraph * behind =
3328 GetParFromID(undo->number_of_behind_par);
3329 LyXParagraph * tmppar;
3330 LyXParagraph * tmppar2;
3331 LyXParagraph * endpar;
3332 LyXParagraph * tmppar5;
3334 // if there's no before take the beginning
3335 // of the document for redoing
3337 SetCursorIntern(bview, FirstParagraph(), 0);
3339 // replace the paragraphs with the undo informations
3341 LyXParagraph * tmppar3 = undo->par;
3342 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3343 LyXParagraph * tmppar4 = tmppar3;
3346 while (tmppar4->next_)
3347 tmppar4 = tmppar4->next_;
3348 } // get last undo par
3350 // now remove the old text if there is any
3351 if (before != behind || (!behind && !before)) {
3353 tmppar5 = before->next();
3355 tmppar5 = OwnerParagraph();
3357 while (tmppar5 && tmppar5 != behind) {
3359 tmppar5 = tmppar5->next();
3360 // a memory optimization for edit: Only layout information
3361 // is stored in the undo. So restore the text informations.
3362 if (undo->kind == Undo::EDIT) {
3363 tmppar2->setContentsFromPar(tmppar);
3364 tmppar->clearContents();
3365 tmppar2 = tmppar2->next();
3372 while (tmppar4->next())
3373 tmppar4 = tmppar4->next();
3374 } // get last undo par
3376 // now remove the old text if there is any
3377 if (before != behind || (!behind && !before)) {
3379 tmppar5 = before->next();
3381 tmppar5 = OwnerParagraph();
3383 while (tmppar5 && tmppar5 != behind) {
3385 tmppar5 = tmppar5->next();
3386 // a memory optimization for edit: Only layout information
3387 // is stored in the undo. So restore the text informations.
3388 if (undo->kind == Undo::EDIT) {
3389 tmppar2->setContentsFromPar(tmppar);
3390 tmppar->clearContents();
3391 tmppar2 = tmppar2->next();
3397 // put the new stuff in the list if there is one
3400 before->next(tmppar3);
3402 OwnerParagraph(tmppar3);
3403 tmppar3->previous(before);
3406 OwnerParagraph(behind);
3409 tmppar4->next(behind);
3411 behind->previous(tmppar4);
3415 // Set the cursor for redoing
3418 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3420 SetCursorIntern(bview, before, 0);
3423 // check wether before points to a closed float and open it if necessary
3424 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3425 && before->next_ && before->next_->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3427 while (tmppar4->previous_ &&
3428 tmppar4->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3429 tmppar4 = tmppar4->previous_;
3430 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3431 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3432 tmppar4 = tmppar4->next_;
3439 // open a cosed footnote at the end if necessary
3440 if (behind && behind->previous_ &&
3441 behind->previous_->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3442 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3443 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3444 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3445 behind = behind->next_;
3450 // calculate the endpar for redoing the paragraphs.
3453 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3454 endpar = behind->LastPhysicalPar()->next();
3456 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->next();
3458 endpar = behind->next();
3463 tmppar = GetParFromID(undo->number_of_cursor_par);
3464 RedoParagraphs(bview, cursor, endpar);
3466 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3467 UpdateCounters(bview, cursor.row());
3477 void LyXText::FinishUndo()
3481 // makes sure the next operation will be stored
3482 undo_finished = true;
3486 void LyXText::FreezeUndo()
3490 // this is dangerous and for internal use only
3495 void LyXText::UnFreezeUndo()
3499 // this is dangerous and for internal use only
3500 undo_frozen = false;
3504 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3505 LyXParagraph const * before,
3506 LyXParagraph const * behind) const
3511 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3512 buf->redostack.clear();
3516 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3517 LyXParagraph const * before, LyXParagraph const * behind)
3521 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3525 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3526 LyXParagraph const * before,
3527 LyXParagraph const * behind) const
3532 int before_number = -1;
3533 int behind_number = -1;
3535 before_number = before->id();
3537 behind_number = behind->id();
3538 // Undo::EDIT and Undo::FINISH are
3539 // always finished. (no overlapping there)
3540 // overlapping only with insert and delete inside one paragraph:
3541 // Nobody wants all removed character
3542 // appear one by one when undoing.
3543 // EDIT is special since only layout information, not the
3544 // contents of a paragaph are stored.
3545 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3546 // check wether storing is needed
3547 if (!buf->undostack.empty() &&
3548 buf->undostack.top()->kind == kind &&
3549 buf->undostack.top()->number_of_before_par == before_number &&
3550 buf->undostack.top()->number_of_behind_par == behind_number ){
3555 // create a new Undo
3556 LyXParagraph * undopar;
3557 LyXParagraph * tmppar;
3558 LyXParagraph * tmppar2;
3560 LyXParagraph * start = 0;
3561 LyXParagraph * end = 0;
3565 start = before->next_;
3567 start = FirstParagraph();
3569 end = behind->previous_;
3571 end = FirstParagraph();
3575 if (start && end && (start != end->next_) &&
3576 ((before != behind) || (!before && !behind))) {
3578 tmppar2 = tmppar->Clone();
3579 tmppar2->id(tmppar->id());
3581 // a memory optimization: Just store the layout information
3583 if (kind == Undo::EDIT){
3584 //tmppar2->text.clear();
3585 tmppar2->clearContents();
3590 while (tmppar != end && tmppar->next_) {
3591 tmppar = tmppar->next_;
3592 tmppar2->next(tmppar->Clone());
3593 tmppar2->next_->id(tmppar->id());
3594 // a memory optimization: Just store the layout
3595 // information when only edit
3596 if (kind == Undo::EDIT){
3597 //tmppar2->next->text.clear();
3598 tmppar2->clearContents();
3600 tmppar2->next_->previous(tmppar2);
3601 tmppar2 = tmppar2->next_;
3605 undopar = 0; // nothing to replace (undo of delete maybe)
3607 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3608 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3611 start = const_cast<LyXParagraph*>(before->next());
3613 start = FirstParagraph();
3615 end = const_cast<LyXParagraph*>(behind->previous());
3617 end = FirstParagraph();
3621 if (start && end && (start != end->next()) &&
3622 ((before != behind) || (!before && !behind))) {
3624 tmppar2 = tmppar->Clone();
3625 tmppar2->id(tmppar->id());
3627 // a memory optimization: Just store the layout information
3629 if (kind == Undo::EDIT){
3630 //tmppar2->text.clear();
3631 tmppar2->clearContents();
3636 while (tmppar != end && tmppar->next()) {
3637 tmppar = tmppar->next();
3638 tmppar2->next(tmppar->Clone());
3639 tmppar2->next()->id(tmppar->id());
3640 // a memory optimization: Just store the layout
3641 // information when only edit
3642 if (kind == Undo::EDIT){
3643 //tmppar2->next->text.clear();
3644 tmppar2->clearContents();
3646 tmppar2->next()->previous(tmppar2);
3647 tmppar2 = tmppar2->next();
3651 undopar = 0; // nothing to replace (undo of delete maybe)
3653 int cursor_par = cursor.par()->id();
3654 int cursor_pos = cursor.pos();
3657 Undo * undo = new Undo(kind,
3658 before_number, behind_number,
3659 cursor_par, cursor_pos,
3662 undo_finished = false;
3667 void LyXText::SetCursorParUndo(Buffer * buf)
3671 SetUndo(buf, Undo::FINISH,
3673 cursor.par()->ParFromPos(cursor.pos())->previous_,
3674 cursor.par()->ParFromPos(cursor.pos())->next_
3676 cursor.par()->previous(),
3677 cursor.par()->next()
3683 void LyXText::toggleAppendix(BufferView * bview)
3686 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3688 LyXParagraph * par = cursor.par();
3690 bool start = !par->params.startOfAppendix();
3692 // ensure that we have only one start_of_appendix in this document
3693 LyXParagraph * tmp = FirstParagraph();
3695 for (; tmp; tmp = tmp->next_)
3696 tmp->params.startOfAppendix(false);
3698 for (; tmp; tmp = tmp->next())
3699 tmp->params.startOfAppendix(false);
3701 par->params.startOfAppendix(start);
3703 // we can set the refreshing parameters now
3704 status = LyXText::NEED_MORE_REFRESH;
3706 refresh_row = 0; // not needed for full update
3707 UpdateCounters(bview, 0);
3708 SetCursor(bview, cursor.par(), cursor.pos());
3712 LyXParagraph * LyXText::OwnerParagraph() const
3715 return inset_owner->par;
3717 return bv_owner->buffer()->paragraph;
3721 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3724 inset_owner->par = p;
3726 bv_owner->buffer()->paragraph = p;