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"
55 LyXText::LyXText(BufferView * bv)
63 LyXText::LyXText(InsetText * inset)
73 the_locking_inset = 0;
81 status = LyXText::UNCHANGED;
82 // set cursor at the very top position
83 selection = true; /* these setting is necessary
84 because of the delete-empty-
85 paragraph mechanism in
88 LyXParagraph * par = OwnerParagraph();
89 current_font = GetFont(bv_owner->buffer(), par, 0);
91 InsertParagraph(bv_owner, par, lastrow);
94 SetCursor(bv_owner, firstrow->par(), 0);
96 current_font = LyXFont(LyXFont::ALL_SANE);
102 // no rebreak necessary
105 undo_finished = true;
108 // Default layouttype for copy environment type
112 // Dump all rowinformation:
113 Row * tmprow = firstrow;
114 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
116 lyxerr << tmprow->baseline() << '\t'
117 << tmprow->par << '\t'
118 << tmprow->pos() << '\t'
119 << tmprow->height << '\t'
120 << tmprow->ascent_of_text << '\t'
121 << tmprow->fill << '\n';
122 tmprow = tmprow->next();
129 void LyXText::init(BufferView * bview)
134 LyXParagraph * par = OwnerParagraph();
135 current_font = GetFont(bview->buffer(), par, 0);
137 InsertParagraph(bview, par, lastrow);
140 SetCursorIntern(bview, firstrow->par(), 0);
143 // Dump all rowinformation:
144 Row * tmprow = firstrow;
145 lyxerr << "Width = " << width << endl;
146 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
148 lyxerr << tmprow->baseline() << '\t'
149 << tmprow->par() << '\t'
150 << tmprow->pos() << '\t'
151 << tmprow->height() << '\t'
152 << tmprow->ascent_of_text() << '\t'
153 << tmprow->fill() << '\n';
154 tmprow = tmprow->next();
162 // Delete all rows, this does not touch the paragraphs!
163 Row * tmprow = firstrow;
165 tmprow = firstrow->next();
172 // Gets the fully instantiated font at a given position in a paragraph
173 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
174 // The difference is that this one is used for displaying, and thus we
175 // are allowed to make cosmetic improvements. For instance make footnotes
177 // If position is -1, we get the layout font of the paragraph.
178 // If position is -2, we get the font of the manual label of the paragraph.
179 LyXFont const LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
180 LyXParagraph::size_type pos) const
182 LyXLayout const & layout =
183 textclasslist.Style(buf->params.textclass, par->GetLayout());
185 char par_depth = par->GetDepth();
186 // We specialize the 95% common case:
189 par->footnoteflag == LyXParagraph::NO_FOOTNOTE &&
194 if (layout.labeltype == LABEL_MANUAL
195 && pos < BeginningOfMainBody(buf, par)) {
197 LyXFont f = par->GetFontSettings(buf->params,
199 return f.realize(layout.reslabelfont);
201 LyXFont f = par->GetFontSettings(buf->params, pos);
202 return f.realize(layout.resfont);
207 // process layoutfont for pos == -1 and labelfont for pos < -1
209 return layout.resfont;
211 return layout.reslabelfont;
215 // The uncommon case need not be optimized as much
217 LyXFont layoutfont, tmpfont;
221 if (pos < BeginningOfMainBody(buf, par)) {
223 layoutfont = layout.labelfont;
226 layoutfont = layout.font;
228 tmpfont = par->GetFontSettings(buf->params, pos);
229 tmpfont.realize(layoutfont);
232 // process layoutfont for pos == -1 and labelfont for pos < -1
234 tmpfont = layout.font;
236 tmpfont = layout.labelfont;
239 // Resolve against environment font information
240 while (par && par_depth && !tmpfont.resolved()) {
241 par = par->DepthHook(par_depth - 1);
243 tmpfont.realize(textclasslist.
244 Style(buf->params.textclass,
245 par->GetLayout()).font);
246 par_depth = par->GetDepth();
250 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
253 // Cosmetic improvement: If this is an open footnote, make the font
255 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
256 && par->footnotekind == LyXParagraph::FOOTNOTE) {
264 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
265 LyXParagraph::size_type pos,
269 // Let the insets convert their font
270 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
271 if (par->GetInset(pos))
272 font = par->GetInset(pos)->ConvertFont(font);
275 LyXLayout const & layout =
276 textclasslist.Style(buf->params.textclass,
279 // Get concrete layout font to reduce against
282 if (pos < BeginningOfMainBody(buf, par))
283 layoutfont = layout.labelfont;
285 layoutfont = layout.font;
287 // Realize against environment font information
288 if (par->GetDepth()){
289 LyXParagraph * tp = par;
290 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
291 tp = tp->DepthHook(tp->GetDepth()-1);
293 layoutfont.realize(textclasslist.
294 Style(buf->params.textclass,
295 tp->GetLayout()).font);
299 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
302 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
303 && par->footnotekind == LyXParagraph::FOOTNOTE) {
304 layoutfont.decSize();
307 // Now, reduce font against full layout font
308 font.reduce(layoutfont);
310 par->SetFont(pos, font);
314 /* inserts a new row behind the specified row, increments
315 * the touched counters */
316 void LyXText::InsertRow(Row * row, LyXParagraph * par,
317 LyXParagraph::size_type pos) const
319 Row * tmprow = new Row;
322 tmprow->next(firstrow);
325 tmprow->previous(row);
326 tmprow->next(row->next());
331 tmprow->next()->previous(tmprow);
333 if (tmprow->previous())
334 tmprow->previous()->next(tmprow);
342 ++number_of_rows; // one more row
346 // removes the row and reset the touched counters
347 void LyXText::RemoveRow(Row * row) const
349 /* this must not happen before the currentrow for clear reasons.
350 so the trick is just to set the current row onto the previous
353 GetRow(row->par(), row->pos(), unused_y);
356 row->next()->previous(row->previous());
357 if (!row->previous()) {
358 firstrow = row->next();
360 row->previous()->next(row->next());
363 lastrow = row->previous();
365 height -= row->height(); // the text becomes smaller
368 --number_of_rows; // one row less
372 // remove all following rows of the paragraph of the specified row.
373 void LyXText::RemoveParagraph(Row * row) const
375 LyXParagraph * tmppar = row->par();
379 while (row && row->par() == tmppar) {
380 tmprow = row->next();
387 // insert the specified paragraph behind the specified row
388 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
391 InsertRow(row, par, 0); /* insert a new row, starting
394 SetCounter(bview->buffer(), par); // set the counters
396 // and now append the whole paragraph behind the new row
399 AppendParagraph(bview, firstrow);
401 row->next()->height(0);
402 AppendParagraph(bview, row->next());
408 void LyXText::ToggleFootnote(BufferView * bview)
410 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
412 && par->next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
414 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
416 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
417 CloseFootnote(bview);
424 void LyXText::OpenStuff(BufferView * bview)
426 if (cursor.pos() == 0 && cursor.par()->bibkey){
427 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
428 } else if (cursor.pos() < cursor.par()->Last()
429 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
430 && cursor.par()->GetInset(cursor.pos())->Editable()) {
431 bview->owner()->getMiniBuffer()
432 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
433 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
434 SetCursorParUndo(bview->buffer());
435 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
439 ToggleFootnote(bview);
447 void LyXText::CloseFootnote(BufferView * bview)
449 LyXParagraph * tmppar;
450 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
452 // if the cursor is not in an open footnote, or
453 // there is no open footnote in this paragraph, just return.
454 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
457 par->next_->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
458 bview->owner()->getMiniBuffer()
459 ->Set(_("Nothing to do"));
463 // ok, move the cursor right before the footnote
464 // just a little faster than using CursorRight()
466 cursor.par()->ParFromPos(cursor.pos()) != par;) {
467 cursor.pos(cursor.pos() + 1);
470 // now the cursor is at the beginning of the physical par
471 SetCursor(bview, cursor.par(),
473 cursor.par()->ParFromPos(cursor.pos())->size());
475 /* we are in a footnote, so let us move at the beginning */
476 /* this is just faster than using just CursorLeft() */
478 tmppar = cursor.par();
479 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
480 // just a little bit faster than movin the cursor
481 tmppar = tmppar->previous();
483 SetCursor(bview, tmppar, tmppar->Last());
486 // the cursor must be exactly before the footnote
487 par = cursor.par()->ParFromPos(cursor.pos());
489 status = LyXText::NEED_MORE_REFRESH;
490 refresh_row = cursor.row();
491 refresh_y = cursor.y() - cursor.row()->baseline();
493 tmppar = cursor.par();
494 LyXParagraph * endpar = par->NextAfterFootnote()->next();
495 Row * row = cursor.row();
497 tmppar->CloseFootnote(cursor.pos());
499 while (tmppar != endpar) {
500 RemoveRow(row->next());
502 tmppar = row->next()->par();
507 AppendParagraph(bview, cursor.row());
509 SetCursor(bview, cursor.par(), cursor.pos());
513 if (cursor.row()->next())
514 SetHeightOfRow(bview, cursor.row()->next());
519 /* used in setlayout */
520 // Asger is not sure we want to do this...
521 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
525 LyXLayout const & layout =
526 textclasslist.Style(buf->params.textclass, par->GetLayout());
528 LyXFont layoutfont, tmpfont;
529 for (LyXParagraph::size_type pos = 0;
531 pos < par->Last(); ++pos) {
533 pos < par->size(); ++pos) {
535 if (pos < BeginningOfMainBody(buf, par))
536 layoutfont = layout.labelfont;
538 layoutfont = layout.font;
540 tmpfont = par->GetFontSettings(buf->params, pos);
541 tmpfont.reduce(layoutfont);
542 par->SetFont(pos, tmpfont);
548 LyXParagraph * LyXText::SetLayout(BufferView * bview,
549 LyXCursor & cur, LyXCursor & sstart_cur,
550 LyXCursor & send_cur,
551 LyXTextClass::size_type layout)
553 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->next();
554 LyXParagraph * undoendpar = endpar;
556 if (endpar && endpar->GetDepth()) {
557 while (endpar && endpar->GetDepth()) {
558 endpar = endpar->LastPhysicalPar()->next();
562 endpar = endpar->next(); // because of parindents etc.
565 SetUndo(bview->buffer(), Undo::EDIT,
566 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous_,
569 /* ok we have a selection. This is always between sstart_cur
570 * and sel_end cursor */
573 LyXLayout const & lyxlayout =
574 textclasslist.Style(bview->buffer()->params.textclass, layout);
576 while (cur.par() != send_cur.par()) {
577 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
578 cur.par()->SetLayout(bview->buffer()->params, layout);
579 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
580 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
581 fppar->params.spaceTop(lyxlayout.fill_top ?
582 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
583 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
584 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
585 if (lyxlayout.margintype == MARGIN_MANUAL)
586 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
587 if (lyxlayout.labeltype != LABEL_BIBLIO
589 delete fppar->bibkey;
593 cur.par(cur.par()->next());
595 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
596 cur.par()->SetLayout(bview->buffer()->params, layout);
597 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
598 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
599 fppar->params.spaceTop(lyxlayout.fill_top ?
600 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
601 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
602 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
603 if (lyxlayout.margintype == MARGIN_MANUAL)
604 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
605 if (lyxlayout.labeltype != LABEL_BIBLIO
607 delete fppar->bibkey;
614 LyXParagraph * LyXText::SetLayout(BufferView * bview,
615 LyXCursor & cur, LyXCursor & sstart_cur,
616 LyXCursor & send_cur,
617 LyXTextClass::size_type layout)
619 LyXParagraph * endpar = send_cur.par()->next();
620 LyXParagraph * undoendpar = endpar;
622 if (endpar && endpar->GetDepth()) {
623 while (endpar && endpar->GetDepth()) {
624 endpar = endpar->next();
628 endpar = endpar->next(); // because of parindents etc.
631 SetUndo(bview->buffer(), Undo::EDIT,
632 sstart_cur.par()->previous(),
635 /* ok we have a selection. This is always between sstart_cur
636 * and sel_end cursor */
639 LyXLayout const & lyxlayout =
640 textclasslist.Style(bview->buffer()->params.textclass, layout);
642 while (cur.par() != send_cur.par()) {
643 cur.par()->SetLayout(layout);
644 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
645 LyXParagraph * fppar = cur.par();
646 fppar->params.spaceTop(lyxlayout.fill_top ?
647 VSpace(VSpace::VFILL)
648 : VSpace(VSpace::NONE));
649 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
650 VSpace(VSpace::VFILL)
651 : VSpace(VSpace::NONE));
652 if (lyxlayout.margintype == MARGIN_MANUAL)
653 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
654 if (lyxlayout.labeltype != LABEL_BIBLIO
656 delete fppar->bibkey;
659 cur.par(cur.par()->next());
661 cur.par()->SetLayout(layout);
662 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
663 LyXParagraph * fppar = cur.par();
664 fppar->params.spaceTop(lyxlayout.fill_top ?
665 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
666 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
667 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
668 if (lyxlayout.margintype == MARGIN_MANUAL)
669 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
670 if (lyxlayout.labeltype != LABEL_BIBLIO
672 delete fppar->bibkey;
680 // set layout over selection and make a total rebreak of those paragraphs
681 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
683 LyXCursor tmpcursor = cursor; /* store the current cursor */
685 // if there is no selection just set the layout
686 // of the current paragraph */
688 sel_start_cursor = cursor; // dummy selection
689 sel_end_cursor = cursor;
692 endpar = SetLayout(bview, cursor, sel_start_cursor,
693 sel_end_cursor, layout);
694 RedoParagraphs(bview, sel_start_cursor, endpar);
696 // we have to reset the selection, because the
697 // geometry could have changed
698 SetCursor(bview, sel_start_cursor.par(),
699 sel_start_cursor.pos(), false);
701 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
703 UpdateCounters(bview, cursor.row());
704 ClearSelection(bview);
706 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
710 // increment depth over selection and
711 // make a total rebreak of those paragraphs
712 void LyXText::IncDepth(BufferView * bview)
714 // If there is no selection, just use the current paragraph
716 sel_start_cursor = cursor; // dummy selection
717 sel_end_cursor = cursor;
720 // We end at the next paragraph with depth 0
721 LyXParagraph * endpar =
723 sel_end_cursor.par()->LastPhysicalPar()->next();
725 sel_end_cursor.par()->next();
727 LyXParagraph * undoendpar = endpar;
729 if (endpar && endpar->GetDepth()) {
730 while (endpar && endpar->GetDepth()) {
732 endpar = endpar->LastPhysicalPar()->next();
734 endpar = endpar->next();
740 endpar = endpar->next(); // because of parindents etc.
743 SetUndo(bview->buffer(), Undo::EDIT,
746 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
748 sel_start_cursor.par()->previous(),
752 LyXCursor tmpcursor = cursor; // store the current cursor
754 // ok we have a selection. This is always between sel_start_cursor
755 // and sel_end cursor
756 cursor = sel_start_cursor;
758 bool anything_changed = false;
761 // NOTE: you can't change the depth of a bibliography entry
764 cursor.par()->footnoteflag ==
765 sel_start_cursor.par()->footnoteflag &&
767 textclasslist.Style(bview->buffer()->params.textclass,
768 cursor.par()->GetLayout()
769 ).labeltype != LABEL_BIBLIO) {
770 LyXParagraph * prev =
772 cursor.par()->FirstPhysicalPar()->previous();
774 cursor.par()->previous();
777 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
778 || (prev->GetDepth() == cursor.par()->GetDepth()
779 && textclasslist.Style(bview->buffer()->params.textclass,
780 prev->GetLayout()).isEnvironment()))) {
782 cursor.par()->FirstPhysicalPar()->params.depth(cursor.par()->FirstPhysicalPar()->params.depth() + 1);
784 cursor.par()->params.depth(cursor.par()->params.depth() + 1);
786 anything_changed = true;
789 if (cursor.par() == sel_end_cursor.par())
791 cursor.par(cursor.par()->next());
794 // if nothing changed set all depth to 0
795 if (!anything_changed) {
796 cursor = sel_start_cursor;
797 while (cursor.par() != sel_end_cursor.par()) {
799 cursor.par()->FirstPhysicalPar()->params.depth(0);
801 cursor.par()->params.depth(0);
803 cursor.par(cursor.par()->next());
806 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
807 cursor.par()->FirstPhysicalPar()->params.depth(0);
809 cursor.par()->params.depth(0);
813 RedoParagraphs(bview, sel_start_cursor, endpar);
815 // we have to reset the selection, because the
816 // geometry could have changed
817 SetCursor(bview, sel_start_cursor.par(),
818 sel_start_cursor.pos());
820 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
821 UpdateCounters(bview, cursor.row());
822 ClearSelection(bview);
824 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
828 // decrement depth over selection and
829 // make a total rebreak of those paragraphs
830 void LyXText::DecDepth(BufferView * bview)
832 // if there is no selection just set the layout
833 // of the current paragraph
835 sel_start_cursor = cursor; // dummy selection
836 sel_end_cursor = cursor;
839 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
841 LyXParagraph * endpar = sel_end_cursor.par()->next();
843 LyXParagraph * undoendpar = endpar;
845 if (endpar && endpar->GetDepth()) {
846 while (endpar && endpar->GetDepth()) {
848 endpar = endpar->LastPhysicalPar()->next();
850 endpar = endpar->next();
856 endpar = endpar->next(); // because of parindents etc.
859 SetUndo(bview->buffer(), Undo::EDIT,
862 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
864 sel_start_cursor.par()->previous(),
868 LyXCursor tmpcursor = cursor; // store the current cursor
870 // ok we have a selection. This is always between sel_start_cursor
871 // and sel_end cursor
872 cursor = sel_start_cursor;
876 if (cursor.par()->footnoteflag ==
877 sel_start_cursor.par()->footnoteflag) {
878 if (cursor.par()->FirstPhysicalPar()->params.depth())
879 cursor.par()->FirstPhysicalPar()->params.depth(cursor.par()->FirstPhysicalPar()->params.depth() - 1);
882 if (cursor.par()->params.depth())
883 cursor.par()->params.depth(cursor.par()->params.depth() - 1);
885 if (cursor.par() == sel_end_cursor.par())
887 cursor.par(cursor.par()->next());
890 RedoParagraphs(bview, sel_start_cursor, endpar);
892 // we have to reset the selection, because the
893 // geometry could have changed
894 SetCursor(bview, sel_start_cursor.par(),
895 sel_start_cursor.pos());
897 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
898 UpdateCounters(bview, cursor.row());
899 ClearSelection(bview);
901 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
905 // set font over selection and make a total rebreak of those paragraphs
906 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
908 // if there is no selection just set the current_font
910 // Determine basis font
912 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
914 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
916 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
917 // Update current font
918 real_current_font.update(font,
919 bview->buffer()->params.language,
922 // Reduce to implicit settings
923 current_font = real_current_font;
924 current_font.reduce(layoutfont);
925 // And resolve it completely
926 real_current_font.realize(layoutfont);
930 LyXCursor tmpcursor = cursor; // store the current cursor
932 // ok we have a selection. This is always between sel_start_cursor
933 // and sel_end cursor
935 SetUndo(bview->buffer(), Undo::EDIT,
937 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous_,
938 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next_
940 sel_start_cursor.par()->previous(),
941 sel_end_cursor.par()->next()
944 cursor = sel_start_cursor;
945 while (cursor.par() != sel_end_cursor.par() ||
948 cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag &&
950 cursor.pos() < sel_end_cursor.pos()))
953 if (cursor.pos() < cursor.par()->Last()
954 && cursor.par()->footnoteflag
955 == sel_start_cursor.par()->footnoteflag
957 if (cursor.pos() < cursor.par()->size()
960 // an open footnote should behave
962 LyXFont newfont = GetFont(bview->buffer(),
963 cursor.par(), cursor.pos());
965 bview->buffer()->params.language,
967 SetCharFont(bview->buffer(),
968 cursor.par(), cursor.pos(), newfont);
969 cursor.pos(cursor.pos() + 1);
972 cursor.par(cursor.par()->next());
976 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->next());
978 // we have to reset the selection, because the
979 // geometry could have changed
980 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
982 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
983 ClearSelection(bview);
985 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
986 tmpcursor.boundary());
990 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
992 Row * tmprow = cur.row();
993 int y = cur.y() - tmprow->baseline();
995 SetHeightOfRow(bview, tmprow);
997 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
999 LyXParagraph * first_phys_par = tmprow->par();
1001 // find the first row of the paragraph
1002 if (first_phys_par != tmprow->par())
1003 while (tmprow->previous()
1004 && tmprow->previous()->par() != first_phys_par) {
1005 tmprow = tmprow->previous();
1006 y -= tmprow->height();
1007 SetHeightOfRow(bview, tmprow);
1009 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
1010 tmprow = tmprow->previous();
1011 y -= tmprow->height();
1012 SetHeightOfRow(bview, tmprow);
1015 // we can set the refreshing parameters now
1016 status = LyXText::NEED_MORE_REFRESH;
1018 refresh_row = tmprow;
1019 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
1023 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
1025 Row * tmprow = cur.row();
1027 int y = cur.y() - tmprow->baseline();
1028 SetHeightOfRow(bview, tmprow);
1030 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
1032 LyXParagraph * first_phys_par = tmprow->par();
1034 // find the first row of the paragraph
1035 if (first_phys_par != tmprow->par())
1036 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
1037 tmprow = tmprow->previous();
1038 y -= tmprow->height();
1040 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
1041 tmprow = tmprow->previous();
1042 y -= tmprow->height();
1045 // we can set the refreshing parameters now
1046 if (status == LyXText::UNCHANGED || y < refresh_y) {
1048 refresh_row = tmprow;
1050 status = LyXText::NEED_MORE_REFRESH;
1051 SetCursor(bview, cur.par(), cur.pos());
1055 /* deletes and inserts again all paragaphs between the cursor
1056 * and the specified par
1057 * This function is needed after SetLayout and SetFont etc. */
1058 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
1059 LyXParagraph const * endpar) const
1062 LyXParagraph * tmppar = 0, * first_phys_par = 0;
1064 Row * tmprow = cur.row();
1066 int y = cur.y() - tmprow->baseline();
1068 if (!tmprow->previous()){
1069 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
1072 first_phys_par = tmprow->par()->FirstPhysicalPar();
1074 first_phys_par = tmprow->par();
1076 // find the first row of the paragraph
1077 if (first_phys_par != tmprow->par())
1078 while (tmprow->previous() &&
1079 (tmprow->previous()->par() != first_phys_par)) {
1080 tmprow = tmprow->previous();
1081 y -= tmprow->height();
1083 while (tmprow->previous()
1084 && tmprow->previous()->par() == first_phys_par) {
1085 tmprow = tmprow->previous();
1086 y -= tmprow->height();
1090 // we can set the refreshing parameters now
1091 status = LyXText::NEED_MORE_REFRESH;
1093 refresh_row = tmprow->previous(); /* the real refresh row will
1094 be deleted, so I store
1095 the previous here */
1098 tmppar = tmprow->next()->par();
1101 while (tmppar != endpar) {
1102 RemoveRow(tmprow->next());
1104 tmppar = tmprow->next()->par();
1109 // remove the first one
1110 tmprow2 = tmprow; /* this is because tmprow->previous()
1112 tmprow = tmprow->previous();
1115 tmppar = first_phys_par;
1119 InsertParagraph(bview, tmppar, tmprow);
1122 while (tmprow->next() && tmprow->next()->par() == tmppar)
1123 tmprow = tmprow->next();
1124 tmppar = tmppar->next();
1126 } while (tmppar != endpar);
1128 // this is because of layout changes
1130 refresh_y -= refresh_row->height();
1131 SetHeightOfRow(bview, refresh_row);
1133 refresh_row = firstrow;
1135 SetHeightOfRow(bview, refresh_row);
1138 if (tmprow && tmprow->next())
1139 SetHeightOfRow(bview, tmprow->next());
1143 bool LyXText::FullRebreak(BufferView * bview)
1149 if (need_break_row) {
1150 BreakAgain(bview, need_break_row);
1158 /* important for the screen */
1161 /* the cursor set functions have a special mechanism. When they
1162 * realize, that you left an empty paragraph, they will delete it.
1163 * They also delete the corresponding row */
1165 // need the selection cursor:
1166 void LyXText::SetSelection(BufferView * bview)
1168 const bool lsel = selection;
1171 last_sel_cursor = sel_cursor;
1172 sel_start_cursor = sel_cursor;
1173 sel_end_cursor = sel_cursor;
1178 // first the toggling area
1179 if (cursor.y() < last_sel_cursor.y()
1180 || (cursor.y() == last_sel_cursor.y()
1181 && cursor.x() < last_sel_cursor.x())) {
1182 toggle_end_cursor = last_sel_cursor;
1183 toggle_cursor = cursor;
1185 toggle_end_cursor = cursor;
1186 toggle_cursor = last_sel_cursor;
1189 last_sel_cursor = cursor;
1191 // and now the whole selection
1193 if (sel_cursor.par() == cursor.par())
1194 if (sel_cursor.pos() < cursor.pos()) {
1195 sel_end_cursor = cursor;
1196 sel_start_cursor = sel_cursor;
1198 sel_end_cursor = sel_cursor;
1199 sel_start_cursor = cursor;
1201 else if (sel_cursor.y() < cursor.y() ||
1202 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1203 sel_end_cursor = cursor;
1204 sel_start_cursor = sel_cursor;
1207 sel_end_cursor = sel_cursor;
1208 sel_start_cursor = cursor;
1211 // a selection with no contents is not a selection
1212 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1213 sel_start_cursor.pos() == sel_end_cursor.pos())
1216 if (inset_owner && (selection || lsel))
1217 inset_owner->SetUpdateStatus(bview, InsetText::SELECTION);
1221 string const LyXText::selectionAsString(Buffer const * buffer) const
1223 if (!selection) return string();
1226 // Special handling if the whole selection is within one paragraph
1227 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1228 result += sel_start_cursor.par()->String(buffer,
1229 sel_start_cursor.pos(),
1230 sel_end_cursor.pos());
1234 // The selection spans more than one paragraph
1236 // First paragraph in selection
1238 result += sel_start_cursor.par()->String(buffer,
1239 sel_start_cursor.pos(),
1240 sel_start_cursor.par()->Last())
1243 result += sel_start_cursor.par()->String(buffer,
1244 sel_start_cursor.pos(),
1245 sel_start_cursor.par()->size())
1249 // The paragraphs in between (if any)
1250 LyXCursor tmpcur(sel_start_cursor);
1251 tmpcur.par(tmpcur.par()->next());
1252 while (tmpcur.par() != sel_end_cursor.par()) {
1254 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1256 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->size()) + "\n\n";
1258 tmpcur.par(tmpcur.par()->next()); // Or NextAfterFootnote??
1261 // Last paragraph in selection
1262 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1268 void LyXText::ClearSelection(BufferView * /*bview*/) const
1275 void LyXText::CursorHome(BufferView * bview) const
1277 SetCursor(bview, cursor.par(), cursor.row()->pos());
1281 void LyXText::CursorEnd(BufferView * bview) const
1283 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1284 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1287 if (cursor.par()->Last() &&
1289 if (cursor.par()->size() &&
1291 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1292 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1293 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1295 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1300 void LyXText::CursorTop(BufferView * bview) const
1302 while (cursor.par()->previous())
1303 cursor.par(cursor.par()->previous());
1304 SetCursor(bview, cursor.par(), 0);
1308 void LyXText::CursorBottom(BufferView * bview) const
1310 while (cursor.par()->next())
1311 cursor.par(cursor.par()->next());
1313 SetCursor(bview, cursor.par(), cursor.par()->Last());
1315 SetCursor(bview, cursor.par(), cursor.par()->size());
1320 /* returns a pointer to the row near the specified y-coordinate
1321 * (relative to the whole text). y is set to the real beginning
1323 Row * LyXText::GetRowNearY(int & y) const
1325 Row * tmprow = firstrow;
1328 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1329 tmpy += tmprow->height();
1330 tmprow = tmprow->next();
1333 y = tmpy; // return the real y
1338 void LyXText::ToggleFree(BufferView * bview,
1339 LyXFont const & font, bool toggleall)
1341 // If the mask is completely neutral, tell user
1342 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1343 // Could only happen with user style
1344 bview->owner()->getMiniBuffer()
1345 ->Set(_("No font change defined. Use Character under"
1346 " the Layout menu to define font change."));
1350 // Try implicit word selection
1351 // If there is a change in the language the implicit word selection
1353 LyXCursor resetCursor = cursor;
1354 bool implicitSelection = (font.language() == ignore_language
1355 && font.number() == LyXFont::IGNORE)
1356 ? SelectWordWhenUnderCursor(bview) : false;
1359 SetFont(bview, font, toggleall);
1361 /* Implicit selections are cleared afterwards and cursor is set to the
1362 original position. */
1363 if (implicitSelection) {
1364 ClearSelection(bview);
1365 cursor = resetCursor;
1366 SetCursor(bview, cursor.par(), cursor.pos());
1367 sel_cursor = cursor;
1370 inset_owner->SetUpdateStatus(bview, InsetText::CURSOR_PAR);
1374 LyXParagraph::size_type
1375 LyXText::BeginningOfMainBody(Buffer const * buf,
1376 LyXParagraph const * par) const
1378 if (textclasslist.Style(buf->params.textclass,
1379 par->GetLayout()).labeltype != LABEL_MANUAL)
1382 return par->BeginningOfMainBody();
1387 /* if there is a selection, reset every environment you can find
1388 * in the selection, otherwise just the environment you are in */
1389 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1391 LyXParagraph * tmppar, * firsttmppar;
1393 ClearSelection(bview);
1395 /* is is only allowed, if the cursor is IN an open footnote.
1396 * Otherwise it is too dangerous */
1397 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1400 SetUndo(bview->buffer(), Undo::FINISH,
1401 cursor.par()->PreviousBeforeFootnote()->previous_,
1402 cursor.par()->NextAfterFootnote()->next_);
1404 /* ok, move to the beginning of the footnote. */
1405 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1406 cursor.par(cursor.par()->previous());
1408 SetCursor(bview, cursor.par(), cursor.par()->Last());
1409 /* this is just faster than using CursorLeft(); */
1411 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1412 tmppar = firsttmppar;
1413 /* tmppar is now the paragraph right before the footnote */
1415 bool first_footnote_par_is_not_empty = tmppar->next_->size();
1417 while (tmppar->next_
1418 && tmppar->next_->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1419 tmppar = tmppar->next_; /* I use next instead of Next(),
1420 * because there cannot be any
1421 * footnotes in a footnote
1423 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1425 /* remember the captions and empty paragraphs */
1426 if ((textclasslist.Style(bview->buffer()->params.textclass,
1427 tmppar->GetLayout())
1428 .labeltype == LABEL_SENSITIVE)
1430 tmppar->SetLayout(bview->buffer()->params, 0);
1433 // now we will paste the ex-footnote, if the layouts allow it
1434 // first restore the layout of the paragraph right behind
1437 tmppar->next_->MakeSameLayout(cursor.par());
1440 if (!tmppar->GetLayout()
1442 && (!tmppar->next()->Last()
1443 || tmppar->next()->HasSameLayout(tmppar)))) {
1444 if (tmppar->next()->Last()
1445 && tmppar->next()->IsLineSeparator(0))
1446 tmppar->next()->Erase(0);
1447 tmppar->PasteParagraph(bview->buffer()->params);
1450 tmppar = tmppar->next(); /* make sure tmppar cannot be touched
1451 * by the pasting of the beginning */
1453 /* then the beginning */
1454 /* if there is no space between the text and the footnote, so we insert
1456 * (only if the previous par and the footnotepar are not empty!) */
1457 if (!firsttmppar->next_->GetLayout()
1458 || firsttmppar->HasSameLayout(firsttmppar->next_)) {
1459 if (firsttmppar->size()
1460 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1461 && first_footnote_par_is_not_empty) {
1462 firsttmppar->next_->InsertChar(0, ' ');
1464 firsttmppar->PasteParagraph(bview->buffer()->params);
1467 /* now redo the paragaphs */
1468 RedoParagraphs(bview, cursor, tmppar);
1470 SetCursor(bview, cursor.par(), cursor.pos());
1472 /* sometimes it can happen, that there is a counter change */
1473 Row * row = cursor.row();
1474 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1476 UpdateCounters(bview, row);
1479 ClearSelection(bview);
1484 /* the DTP switches for paragraphs. LyX will store them in the
1485 * first physicla paragraph. When a paragraph is broken, the top settings
1486 * rest, the bottom settings are given to the new one. So I can make shure,
1487 * they do not duplicate themself and you cannnot make dirty things with
1490 void LyXText::SetParagraph(BufferView * bview,
1491 bool line_top, bool line_bottom,
1492 bool pagebreak_top, bool pagebreak_bottom,
1493 VSpace const & space_top,
1494 VSpace const & space_bottom,
1496 string labelwidthstring,
1499 LyXCursor tmpcursor = cursor;
1501 sel_start_cursor = cursor;
1502 sel_end_cursor = cursor;
1505 // make sure that the depth behind the selection are restored, too
1507 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
1509 LyXParagraph * endpar = sel_end_cursor.par()->next();
1511 LyXParagraph * undoendpar = endpar;
1513 if (endpar && endpar->GetDepth()) {
1514 while (endpar && endpar->GetDepth()) {
1516 endpar = endpar->LastPhysicalPar()->next();
1518 endpar = endpar->next();
1520 undoendpar = endpar;
1524 endpar = endpar->next(); // because of parindents etc.
1527 SetUndo(bview->buffer(), Undo::EDIT,
1530 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
1532 sel_start_cursor.par()->previous(),
1537 LyXParagraph * tmppar = sel_end_cursor.par();
1539 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->previous()) {
1540 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1542 while (tmppar != sel_start_cursor.par()->previous()) {
1543 SetCursor(bview, tmppar, 0);
1545 status = LyXText::NEED_MORE_REFRESH;
1546 refresh_row = cursor.row();
1547 refresh_y = cursor.y() - cursor.row()->baseline();
1549 if (cursor.par()->footnoteflag ==
1550 sel_start_cursor.par()->footnoteflag) {
1552 cursor.par()->params.lineTop(line_top);
1553 cursor.par()->params.lineBottom(line_bottom);
1554 cursor.par()->params.pagebreakTop(pagebreak_top);
1555 cursor.par()->params.pagebreakBottom(pagebreak_bottom);
1556 cursor.par()->params.spaceTop(space_top);
1557 cursor.par()->params.spaceBottom(space_bottom);
1558 // does the layout allow the new alignment?
1559 if (align == LYX_ALIGN_LAYOUT)
1560 align = textclasslist
1561 .Style(bview->buffer()->params.textclass,
1562 cursor.par()->GetLayout()).align;
1563 if (align & textclasslist
1564 .Style(bview->buffer()->params.textclass,
1565 cursor.par()->GetLayout()).alignpossible) {
1566 if (align == textclasslist
1567 .Style(bview->buffer()->params.textclass,
1568 cursor.par()->GetLayout()).align)
1569 cursor.par()->params.align(LYX_ALIGN_LAYOUT);
1571 cursor.par()->params.align(align);
1573 cursor.par()->SetLabelWidthString(labelwidthstring);
1574 cursor.par()->params.noindent(noindent);
1578 tmppar = cursor.par()->FirstPhysicalPar()->previous();
1580 tmppar = cursor.par()->previous();
1584 RedoParagraphs(bview, sel_start_cursor, endpar);
1586 ClearSelection(bview);
1587 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1588 sel_cursor = cursor;
1589 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1590 SetSelection(bview);
1591 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1593 bview->updateInset(inset_owner, true);
1598 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1599 string const & width,
1600 string const & widthp,
1601 int alignment, bool hfill,
1602 bool start_minipage)
1604 LyXCursor tmpcursor = cursor;
1605 LyXParagraph * tmppar;
1607 sel_start_cursor = cursor;
1608 sel_end_cursor = cursor;
1611 // make sure that the depth behind the selection are restored, too
1613 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
1615 LyXParagraph * endpar = sel_end_cursor.par()->next();
1617 LyXParagraph * undoendpar = endpar;
1619 if (endpar && endpar->GetDepth()) {
1620 while (endpar && endpar->GetDepth()) {
1622 endpar = endpar->LastPhysicalPar()->next();
1624 endpar = endpar->next();
1626 undoendpar = endpar;
1630 endpar = endpar->next(); // because of parindents etc.
1633 SetUndo(bview->buffer(), Undo::EDIT,
1636 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
1638 sel_start_cursor.par()->previous(),
1642 tmppar = sel_end_cursor.par();
1644 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->previous()) {
1645 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1647 while(tmppar != sel_start_cursor.par()->previous()) {
1648 SetCursor(bview, tmppar, 0);
1650 status = LyXText::NEED_MORE_REFRESH;
1651 refresh_row = cursor.row();
1652 refresh_y = cursor.y() - cursor.row()->baseline();
1654 if (cursor.par()->footnoteflag ==
1655 sel_start_cursor.par()->footnoteflag) {
1658 if (type == LyXParagraph::PEXTRA_NONE) {
1659 if (cursor.par()->params.pextraType() != LyXParagraph::PEXTRA_NONE) {
1660 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1661 cursor.par()->params.pextraType(LyXParagraph::PEXTRA_NONE);
1664 cursor.par()->SetPExtraType(bview->buffer()->params,
1665 type, width, widthp);
1666 cursor.par()->params.pextraHfill(hfill);
1667 cursor.par()->params.pextraStartMinipage(start_minipage);
1668 cursor.par()->params.pextraAlignment(alignment);
1673 tmppar = cursor.par()->FirstPhysicalPar()->previous();
1675 tmppar = cursor.par()->previous();
1678 RedoParagraphs(bview, sel_start_cursor, endpar);
1679 ClearSelection(bview);
1680 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1681 sel_cursor = cursor;
1682 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1683 SetSelection(bview);
1684 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1689 char loweralphaCounter(int n)
1691 if (n < 1 || n > 26)
1701 char alphaCounter(int n)
1703 if (n < 1 || n > 26)
1711 char hebrewCounter(int n)
1713 static const char hebrew[22] = {
1714 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1715 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1716 '÷', 'ø', 'ù', 'ú'
1718 if (n < 1 || n > 22)
1726 string const romanCounter(int n)
1728 static char const * roman[20] = {
1729 "i", "ii", "iii", "iv", "v",
1730 "vi", "vii", "viii", "ix", "x",
1731 "xi", "xii", "xiii", "xiv", "xv",
1732 "xvi", "xvii", "xviii", "xix", "xx"
1734 if (n < 1 || n > 20)
1743 // set the counter of a paragraph. This includes the labels
1744 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1747 // this is only relevant for the beginning of paragraph
1748 par = par->FirstPhysicalPar();
1750 LyXLayout const & layout =
1751 textclasslist.Style(buf->params.textclass,
1754 LyXTextClass const & textclass =
1755 textclasslist.TextClass(buf->params.textclass);
1757 /* copy the prev-counters to this one, unless this is the start of a
1758 footnote or of a bibliography or the very first paragraph */
1761 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1762 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1763 && par->footnotekind == LyXParagraph::FOOTNOTE)
1765 && !(textclasslist.Style(buf->params.textclass,
1766 par->previous()->GetLayout()
1767 ).labeltype != LABEL_BIBLIO
1768 && layout.labeltype == LABEL_BIBLIO)) {
1769 for (int i = 0; i < 10; ++i) {
1770 par->setCounter(i, par->previous()->GetFirstCounter(i));
1773 par->params.appendix(par->previous()->FirstPhysicalPar()->params.appendix());
1775 par->params.appendix(par->previous()->params.appendix());
1777 if (!par->params.appendix() && par->params.startOfAppendix()) {
1778 par->params.appendix(true);
1779 for (int i = 0; i < 10; ++i) {
1780 par->setCounter(i, 0);
1784 par->enumdepth = par->previous()->FirstPhysicalPar()->enumdepth;
1785 par->itemdepth = par->previous()->FirstPhysicalPar()->itemdepth;
1787 par->enumdepth = par->previous()->enumdepth;
1788 par->itemdepth = par->previous()->itemdepth;
1791 for (int i = 0; i < 10; ++i) {
1792 par->setCounter(i, 0);
1794 par->params.appendix(par->params.startOfAppendix());
1800 // if this is an open marginnote and this is the first
1801 // entry in the marginnote and the enclosing
1802 // environment is an enum/item then correct for the
1803 // LaTeX behaviour (ARRae)
1804 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1805 && par->footnotekind == LyXParagraph::MARGIN
1807 && par->previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1808 && (par->PreviousBeforeFootnote()
1809 && textclasslist.Style(buf->params.textclass,
1810 par->PreviousBeforeFootnote()->GetLayout()
1811 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1812 // Any itemize or enumerate environment in a marginnote
1813 // that is embedded in an itemize or enumerate
1814 // paragraph is seen by LaTeX as being at a deeper
1815 // level within that enclosing itemization/enumeration
1816 // even if there is a "standard" layout at the start of
1822 /* Maybe we have to increment the enumeration depth.
1823 * BUT, enumeration in a footnote is considered in isolation from its
1824 * surrounding paragraph so don't increment if this is the
1825 * first line of the footnote
1826 * AND, bibliographies can't have their depth changed ie. they
1827 * are always of depth 0
1830 && par->previous()->GetDepth() < par->GetDepth()
1831 && textclasslist.Style(buf->params.textclass,
1832 par->previous()->GetLayout()
1833 ).labeltype == LABEL_COUNTER_ENUMI
1834 && par->enumdepth < 3
1836 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1837 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1838 && par->footnotekind == LyXParagraph::FOOTNOTE)
1840 && layout.labeltype != LABEL_BIBLIO) {
1844 /* Maybe we have to decrement the enumeration depth, see note above */
1846 && par->previous()->GetDepth() > par->GetDepth()
1848 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1849 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1850 && par->footnotekind == LyXParagraph::FOOTNOTE)
1852 && layout.labeltype != LABEL_BIBLIO) {
1853 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1854 par->setCounter(6 + par->enumdepth,
1855 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1856 /* reset the counters.
1857 * A depth change is like a breaking layout
1859 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1860 par->setCounter(i, 0);
1863 if (!par->params.labelString().empty()) {
1864 par->params.labelString(string());
1867 if (layout.margintype == MARGIN_MANUAL) {
1868 if (par->params.labelWidthString().empty()) {
1869 par->SetLabelWidthString(layout.labelstring());
1872 par->SetLabelWidthString(string());
1875 /* is it a layout that has an automatic label ? */
1876 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1878 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1879 if (i >= 0 && i<= buf->params.secnumdepth) {
1880 par->incCounter(i); // increment the counter
1882 // Is there a label? Useful for Chapter layout
1883 if (!par->params.appendix()) {
1884 if (!layout.labelstring().empty())
1885 par->params.labelString(layout.labelstring());
1887 par->params.labelString(string());
1889 if (!layout.labelstring_appendix().empty())
1890 par->params.labelString(layout.labelstring_appendix());
1892 par->params.labelString(string());
1895 std::ostringstream s;
1897 if (!par->params.appendix()) {
1898 switch (2 * LABEL_COUNTER_CHAPTER -
1899 textclass.maxcounter() + i) {
1900 case LABEL_COUNTER_CHAPTER:
1901 s << par->getCounter(i);
1903 case LABEL_COUNTER_SECTION:
1904 s << par->getCounter(i - 1) << '.'
1905 << par->getCounter(i);
1907 case LABEL_COUNTER_SUBSECTION:
1908 s << par->getCounter(i - 2) << '.'
1909 << par->getCounter(i - 1) << '.'
1910 << par->getCounter(i);
1912 case LABEL_COUNTER_SUBSUBSECTION:
1913 s << par->getCounter(i - 3) << '.'
1914 << par->getCounter(i - 2) << '.'
1915 << par->getCounter(i - 1) << '.'
1916 << par->getCounter(i);
1919 case LABEL_COUNTER_PARAGRAPH:
1920 s << par->getCounter(i - 4) << '.'
1921 << par->getCounter(i - 3) << '.'
1922 << par->getCounter(i - 2) << '.'
1923 << par->getCounter(i - 1) << '.'
1924 << par->getCounter(i);
1926 case LABEL_COUNTER_SUBPARAGRAPH:
1927 s << par->getCounter(i - 5) << '.'
1928 << par->getCounter(i - 4) << '.'
1929 << par->getCounter(i - 3) << '.'
1930 << par->getCounter(i - 2) << '.'
1931 << par->getCounter(i - 1) << '.'
1932 << par->getCounter(i);
1936 // Can this ever be reached? And in the
1937 // case it is, how can this be correct?
1939 s << par->getCounter(i) << '.';
1942 } else { // appendix
1943 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1944 case LABEL_COUNTER_CHAPTER:
1945 if (par->isRightToLeftPar(buf->params))
1946 s << hebrewCounter(par->getCounter(i));
1948 s << alphaCounter(par->getCounter(i));
1950 case LABEL_COUNTER_SECTION:
1951 if (par->isRightToLeftPar(buf->params))
1952 s << hebrewCounter(par->getCounter(i - 1));
1954 s << alphaCounter(par->getCounter(i - 1));
1957 << par->getCounter(i);
1960 case LABEL_COUNTER_SUBSECTION:
1961 if (par->isRightToLeftPar(buf->params))
1962 s << hebrewCounter(par->getCounter(i - 2));
1964 s << alphaCounter(par->getCounter(i - 2));
1967 << par->getCounter(i-1) << '.'
1968 << par->getCounter(i);
1971 case LABEL_COUNTER_SUBSUBSECTION:
1972 if (par->isRightToLeftPar(buf->params))
1973 s << hebrewCounter(par->getCounter(i-3));
1975 s << alphaCounter(par->getCounter(i-3));
1978 << par->getCounter(i-2) << '.'
1979 << par->getCounter(i-1) << '.'
1980 << par->getCounter(i);
1983 case LABEL_COUNTER_PARAGRAPH:
1984 if (par->isRightToLeftPar(buf->params))
1985 s << hebrewCounter(par->getCounter(i-4));
1987 s << alphaCounter(par->getCounter(i-4));
1990 << par->getCounter(i-3) << '.'
1991 << par->getCounter(i-2) << '.'
1992 << par->getCounter(i-1) << '.'
1993 << par->getCounter(i);
1996 case LABEL_COUNTER_SUBPARAGRAPH:
1997 if (par->isRightToLeftPar(buf->params))
1998 s << hebrewCounter(par->getCounter(i-5));
2000 s << alphaCounter(par->getCounter(i-5));
2003 << par->getCounter(i-4) << '.'
2004 << par->getCounter(i-3) << '.'
2005 << par->getCounter(i-2) << '.'
2006 << par->getCounter(i-1) << '.'
2007 << par->getCounter(i);
2011 // Can this ever be reached? And in the
2012 // case it is, how can this be correct?
2014 s << par->getCounter(i) << '.';
2020 par->params.labelString(par->params.labelString() +s.str().c_str());
2021 // We really want to remove the c_str as soon as
2024 for (i++; i < 10; ++i) {
2025 // reset the following counters
2026 par->setCounter(i, 0);
2028 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
2029 for (i++; i < 10; ++i) {
2030 // reset the following counters
2031 par->setCounter(i, 0);
2033 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
2034 par->incCounter(i + par->enumdepth);
2035 int number = par->getCounter(i + par->enumdepth);
2037 std::ostringstream s;
2039 switch (par->enumdepth) {
2041 if (par->isRightToLeftPar(buf->params))
2043 << hebrewCounter(number)
2047 << loweralphaCounter(number)
2051 if (par->isRightToLeftPar(buf->params))
2052 s << '.' << romanCounter(number);
2054 s << romanCounter(number) << '.';
2057 if (par->isRightToLeftPar(buf->params))
2059 << alphaCounter(number);
2061 s << alphaCounter(number)
2065 if (par->isRightToLeftPar(buf->params))
2072 par->params.labelString(s.str().c_str());
2073 // we really want to get rid of that c_str()
2075 for (i += par->enumdepth + 1; i < 10; ++i)
2076 par->setCounter(i, 0); /* reset the following counters */
2079 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2080 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2082 int number = par->getCounter(i);
2084 InsetCommandParams p( "bibitem" );
2085 par->bibkey = new InsetBibKey(p);
2087 par->bibkey->setCounter(number);
2088 par->params.labelString(layout.labelstring());
2090 // In biblio should't be following counters but...
2092 string s = layout.labelstring();
2094 // the caption hack:
2095 if (layout.labeltype == LABEL_SENSITIVE) {
2096 bool isOK (par->InInset() && par->InInset()->owner() &&
2097 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2099 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2100 && (par->footnotekind == LyXParagraph::FIG
2101 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2102 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2103 ? ":øåéà " : "Figure:";
2104 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2105 && (par->footnotekind == LyXParagraph::TAB
2106 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2107 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2108 ? ":äìáè" : "Table:";
2109 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2110 && par->footnotekind == LyXParagraph::ALGORITHM) {
2111 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2112 ? ":Ãúéøåâìà " : "Algorithm:";
2116 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2118 = floatList.getType(tmp->type());
2119 // We should get the correct number here too.
2120 s = fl.name() + " #:";
2122 /* par->SetLayout(0);
2123 s = layout->labelstring; */
2124 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2125 ? " :úåòîùî øñç" : "Senseless: ";
2128 par->params.labelString(s);
2130 /* reset the enumeration counter. They are always resetted
2131 * when there is any other layout between */
2132 for (int i = 6 + par->enumdepth; i < 10; ++i)
2133 par->setCounter(i, 0);
2138 /* Updates all counters BEHIND the row. Changed paragraphs
2139 * with a dynamic left margin will be rebroken. */
2140 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2147 } else if (row->par()->next_
2148 && row->par()->next_->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
2149 par = row->par()->LastPhysicalPar()->next();
2151 par = row->par()->next_;
2158 par = row->par()->next();
2163 while (row->par() != par)
2166 SetCounter(bview->buffer(), par);
2168 /* now check for the headline layouts. remember that they
2169 * have a dynamic left margin */
2174 ( textclasslist.Style(bview->buffer()->params.textclass,
2175 par->layout).margintype == MARGIN_DYNAMIC
2176 || textclasslist.Style(bview->buffer()->params.textclass,
2177 par->layout).labeltype == LABEL_SENSITIVE)
2180 /* Rebreak the paragraph */
2181 RemoveParagraph(row);
2182 AppendParagraph(bview, row);
2185 /* think about the damned open footnotes! */
2186 while (par->next() &&
2187 (par->next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2188 || par->next()->IsDummy())){
2190 if (par->IsDummy()) {
2191 while (row->par() != par)
2193 RemoveParagraph(row);
2194 AppendParagraph(bview, row);
2200 par = par->LastPhysicalPar()->next();
2209 /* insets an inset. */
2210 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2212 if (!cursor.par()->InsertInsetAllowed(inset))
2214 SetUndo(bview->buffer(), Undo::INSERT,
2216 cursor.par()->ParFromPos(cursor.pos())->previous_,
2217 cursor.par()->ParFromPos(cursor.pos())->next_
2219 cursor.par()->previous(),
2220 cursor.par()->next()
2223 cursor.par()->InsertInset(cursor.pos(), inset);
2224 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2225 * The character will not be inserted a
2228 // If we enter a highly editable inset the cursor should be to before
2229 // the inset. This couldn't happen before as Undo was not handled inside
2230 // inset now after the Undo LyX tries to call inset->Edit(...) again
2231 // and cannot do this as the cursor is behind the inset and GetInset
2232 // does not return the inset!
2233 if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
2234 CursorLeft(bview, true);
2240 void LyXText::copyEnvironmentType()
2242 copylayouttype = cursor.par()->GetLayout();
2246 void LyXText::pasteEnvironmentType(BufferView * bview)
2248 SetLayout(bview, copylayouttype);
2252 void LyXText::CutSelection(BufferView * bview, bool doclear)
2254 // Stuff what we got on the clipboard. Even if there is no selection.
2256 // There is a problem with having the stuffing here in that the
2257 // larger the selection the slower LyX will get. This can be
2258 // solved by running the line below only when the selection has
2259 // finished. The solution used currently just works, to make it
2260 // faster we need to be more clever and probably also have more
2261 // calls to stuffClipboard. (Lgb)
2262 bview->stuffClipboard(selectionAsString(bview->buffer()));
2264 // This doesn't make sense, if there is no selection
2268 // OK, we have a selection. This is always between sel_start_cursor
2269 // and sel_end_cursor
2271 // Check whether there are half footnotes in the selection
2272 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2273 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2274 LyXParagraph * tmppar = sel_start_cursor.par();
2275 while (tmppar != sel_end_cursor.par()){
2276 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2277 WriteAlert(_("Impossible operation"),
2278 _("Don't know what to do with half floats."),
2282 tmppar = tmppar->next();
2287 // make sure that the depth behind the selection are restored, too
2289 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
2291 LyXParagraph * endpar = sel_end_cursor.par()->next();
2293 LyXParagraph * undoendpar = endpar;
2295 if (endpar && endpar->GetDepth()) {
2296 while (endpar && endpar->GetDepth()) {
2298 endpar = endpar->LastPhysicalPar()->next();
2300 endpar = endpar->next();
2302 undoendpar = endpar;
2304 } else if (endpar) {
2305 endpar = endpar->next(); // because of parindents etc.
2308 SetUndo(bview->buffer(), Undo::DELETE,
2311 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
2313 sel_start_cursor.par()->previous(),
2319 // there are two cases: cut only within one paragraph or
2320 // more than one paragraph
2322 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2323 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2325 if (sel_start_cursor.par() == sel_end_cursor.par())
2328 // only within one paragraph
2329 endpar = sel_start_cursor.par();
2330 int pos = sel_end_cursor.pos();
2331 cap.cutSelection(sel_start_cursor.par(), &endpar,
2332 sel_start_cursor.pos(), pos,
2333 bview->buffer()->params.textclass, doclear);
2334 sel_end_cursor.pos(pos);
2336 endpar = sel_end_cursor.par();
2338 int pos = sel_end_cursor.pos();
2339 cap.cutSelection(sel_start_cursor.par(), &endpar,
2340 sel_start_cursor.pos(), pos,
2341 bview->buffer()->params.textclass, doclear);
2343 sel_end_cursor.par(endpar);
2344 sel_end_cursor.pos(pos);
2345 cursor.pos(sel_end_cursor.pos());
2347 endpar = endpar->next();
2349 // sometimes necessary
2351 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2353 RedoParagraphs(bview, sel_start_cursor, endpar);
2355 ClearSelection(bview);
2356 cursor = sel_start_cursor;
2357 SetCursor(bview, cursor.par(), cursor.pos());
2358 sel_cursor = cursor;
2359 UpdateCounters(bview, cursor.row());
2363 void LyXText::CopySelection(BufferView * bview)
2365 // Stuff what we got on the clipboard. Even if there is no selection.
2367 // There is a problem with having the stuffing here in that the
2368 // larger the selection the slower LyX will get. This can be
2369 // solved by running the line below only when the selection has
2370 // finished. The solution used currently just works, to make it
2371 // faster we need to be more clever and probably also have more
2372 // calls to stuffClipboard. (Lgb)
2373 bview->stuffClipboard(selectionAsString(bview->buffer()));
2375 // this doesnt make sense, if there is no selection
2379 // ok we have a selection. This is always between sel_start_cursor
2380 // and sel_end cursor
2383 /* check wether there are half footnotes in the selection */
2384 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2385 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2386 LyXParagraph * tmppar = sel_start_cursor.par();
2387 while (tmppar != sel_end_cursor.par()) {
2388 if (tmppar->footnoteflag !=
2389 sel_end_cursor.par()->footnoteflag) {
2390 WriteAlert(_("Impossible operation"),
2391 _("Don't know what to do"
2392 " with half floats."),
2396 tmppar = tmppar->next();
2401 // copy behind a space if there is one
2403 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2405 while (sel_start_cursor.par()->size() > sel_start_cursor.pos()
2407 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2408 && (sel_start_cursor.par() != sel_end_cursor.par()
2409 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2410 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2414 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2415 sel_start_cursor.pos(), sel_end_cursor.pos(),
2416 bview->buffer()->params.textclass);
2420 void LyXText::PasteSelection(BufferView * bview)
2424 // this does not make sense, if there is nothing to paste
2425 if (!cap.checkPastePossible(cursor.par()))
2428 SetUndo(bview->buffer(), Undo::INSERT,
2430 cursor.par()->ParFromPos(cursor.pos())->previous_,
2431 cursor.par()->ParFromPos(cursor.pos())->next_
2433 cursor.par()->previous(),
2434 cursor.par()->next()
2438 LyXParagraph * endpar;
2439 LyXParagraph * actpar = cursor.par();
2441 int pos = cursor.pos();
2442 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2444 RedoParagraphs(bview, cursor, endpar);
2446 SetCursor(bview, cursor.par(), cursor.pos());
2447 ClearSelection(bview);
2449 sel_cursor = cursor;
2450 SetCursor(bview, actpar, pos);
2451 SetSelection(bview);
2452 UpdateCounters(bview, cursor.row());
2456 // returns a pointer to the very first LyXParagraph
2457 LyXParagraph * LyXText::FirstParagraph() const
2459 return OwnerParagraph();
2463 // sets the selection over the number of characters of string, no check!!
2464 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2466 sel_cursor = cursor;
2467 for (int i = 0; str[i]; ++i)
2469 SetSelection(bview);
2473 // simple replacing. The font of the first selected character is used
2474 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2477 SetCursorParUndo(bview->buffer());
2480 if (!selection) { // create a dummy selection
2481 sel_end_cursor = cursor;
2482 sel_start_cursor = cursor;
2485 // Get font setting before we cut
2486 LyXParagraph::size_type pos = sel_end_cursor.pos();
2487 LyXFont const font = sel_start_cursor.par()
2488 ->GetFontSettings(bview->buffer()->params,
2489 sel_start_cursor.pos());
2491 // Insert the new string
2492 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2493 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2497 // Cut the selection
2498 CutSelection(bview);
2504 // needed to insert the selection
2505 void LyXText::InsertStringA(BufferView * bview, string const & str)
2507 LyXParagraph * par = cursor.par();
2508 LyXParagraph::size_type pos = cursor.pos();
2509 LyXParagraph::size_type a = 0;
2510 LyXParagraph * endpar = cursor.par()->next();
2512 SetCursorParUndo(bview->buffer());
2515 textclasslist.Style(bview->buffer()->params.textclass,
2516 cursor.par()->GetLayout()).isEnvironment();
2517 // only to be sure, should not be neccessary
2518 ClearSelection(bview);
2520 // insert the string, don't insert doublespace
2521 string::size_type i = 0;
2522 while (i < str.length()) {
2523 if (str[i] != '\n') {
2525 && i + 1 < str.length() && str[i + 1] != ' '
2526 && pos && par->GetChar(pos - 1)!= ' ') {
2527 par->InsertChar(pos, ' ', current_font);
2529 } else if (str[i] == ' ') {
2530 InsetSpecialChar * new_inset =
2531 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2532 if (par->InsertInsetAllowed(new_inset)) {
2533 par->InsertInset(pos, new_inset,
2539 } else if (str[i] == '\t') {
2540 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2541 InsetSpecialChar * new_inset =
2542 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2543 if (par->InsertInsetAllowed(new_inset)) {
2544 par->InsertInset(pos, new_inset,
2551 } else if (str[i] != 13 &&
2552 // Ignore unprintables
2553 (str[i] & 127) >= ' ') {
2554 par->InsertChar(pos, str[i], current_font);
2558 if (!par->size()) { // par is empty
2559 InsetSpecialChar * new_inset =
2560 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2561 if (par->InsertInsetAllowed(new_inset)) {
2562 par->InsertInset(pos,
2570 par->BreakParagraph(bview->buffer()->params, pos, flag);
2577 RedoParagraphs(bview, cursor, endpar);
2578 SetCursor(bview, cursor.par(), cursor.pos());
2579 sel_cursor = cursor;
2580 SetCursor(bview, par, pos);
2581 SetSelection(bview);
2585 /* turns double-CR to single CR, others where converted into one blank and 13s
2586 * that are ignored .Double spaces are also converted into one. Spaces at
2587 * the beginning of a paragraph are forbidden. tabs are converted into one
2588 * space. then InsertStringA is called */
2589 void LyXText::InsertStringB(BufferView * bview, string const & s)
2592 string::size_type i = 1;
2593 while (i < str.length()) {
2596 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2598 if (str[i] == '\n' && i + 1 < str.length()) {
2599 if (str[i + 1] != '\n') {
2600 if (str[i - 1] != ' ')
2605 while (i + 1 < str.length()
2606 && (str[i + 1] == ' '
2607 || str[i + 1] == '\t'
2608 || str[i + 1] == '\n'
2609 || str[i + 1] == 13)) {
2616 InsertStringA(bview, str);
2620 bool LyXText::GotoNextInset(BufferView * bview,
2621 std::vector<Inset::Code> const & codes,
2622 string const & contents) const
2624 LyXCursor res = cursor;
2628 if (res.pos() < res.par()->Last() - 1) {
2630 if (res.pos() < res.par()->size() - 1) {
2632 res.pos(res.pos() + 1);
2634 res.par(res.par()->next());
2638 } while (res.par() &&
2639 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2640 && (inset = res.par()->GetInset(res.pos())) != 0
2641 && find(codes.begin(), codes.end(), inset->LyxCode())
2643 && (contents.empty() ||
2644 static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
2648 SetCursor(bview, res.par(), res.pos());
2655 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2656 LyXParagraph::size_type pos)
2658 LyXCursor tmpcursor;
2661 LyXParagraph::size_type z;
2662 Row * row = GetRow(par, pos, y);
2664 // is there a break one row above
2665 if (row->previous() && row->previous()->par() == row->par()) {
2666 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2667 if (z >= row->pos()) {
2668 // set the dimensions of the row above
2669 y -= row->previous()->height();
2671 refresh_row = row->previous();
2672 status = LyXText::NEED_MORE_REFRESH;
2674 BreakAgain(bview, row->previous());
2676 // set the cursor again. Otherwise
2677 // dangling pointers are possible
2678 SetCursor(bview, cursor.par(), cursor.pos(),
2679 false, cursor.boundary());
2680 sel_cursor = cursor;
2685 int const tmpheight = row->height();
2686 LyXParagraph::size_type const tmplast = RowLast(row);
2690 BreakAgain(bview, row);
2691 if (row->height() == tmpheight && RowLast(row) == tmplast)
2692 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2694 status = LyXText::NEED_MORE_REFRESH;
2696 // check the special right address boxes
2697 if (textclasslist.Style(bview->buffer()->params.textclass,
2698 par->GetLayout()).margintype
2699 == MARGIN_RIGHT_ADDRESS_BOX) {
2706 RedoDrawingOfParagraph(bview, tmpcursor);
2709 // set the cursor again. Otherwise dangling pointers are possible
2710 // also set the selection
2714 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2715 false, sel_cursor.boundary());
2716 sel_cursor = cursor;
2717 SetCursorIntern(bview, sel_start_cursor.par(),
2718 sel_start_cursor.pos(),
2719 false, sel_start_cursor.boundary());
2720 sel_start_cursor = cursor;
2721 SetCursorIntern(bview, sel_end_cursor.par(),
2722 sel_end_cursor.pos(),
2723 false, sel_end_cursor.boundary());
2724 sel_end_cursor = cursor;
2725 SetCursorIntern(bview, last_sel_cursor.par(),
2726 last_sel_cursor.pos(),
2727 false, last_sel_cursor.boundary());
2728 last_sel_cursor = cursor;
2731 SetCursorIntern(bview, cursor.par(), cursor.pos(),
2732 false, cursor.boundary());
2736 // returns false if inset wasn't found
2737 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2739 // first check the current paragraph
2740 int pos = cursor.par()->GetPositionOfInset(inset);
2742 CheckParagraph(bview, cursor.par(), pos);
2746 // check every paragraph
2748 LyXParagraph * par = FirstParagraph();
2751 // make sure the paragraph is open
2752 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2754 pos = par->GetPositionOfInset(inset);
2756 CheckParagraph(bview, par, pos);
2769 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2770 LyXParagraph::size_type pos,
2771 bool setfont, bool boundary) const
2773 LyXCursor old_cursor = cursor;
2774 SetCursorIntern(bview, par, pos, setfont, boundary);
2775 DeleteEmptyParagraphMechanism(bview, old_cursor);
2779 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2780 LyXParagraph::size_type pos, bool boundary) const
2783 // correct the cursor position if impossible
2784 if (pos > par->Last()){
2785 LyXParagraph * tmppar = par->ParFromPos(pos);
2786 pos = par->PositionInParFromPos(pos);
2789 if (par->IsDummy() && par->previous_ &&
2790 par->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2791 while (par->previous_ &&
2792 ((par->previous_->IsDummy() &&
2793 (par->previous_->previous_->footnoteflag ==
2794 LyXParagraph::CLOSED_FOOTNOTE)) ||
2795 (par->previous_->footnoteflag ==
2796 LyXParagraph::CLOSED_FOOTNOTE))) {
2797 par = par->previous_;
2798 if (par->IsDummy() &&
2799 (par->previous_->footnoteflag ==
2800 LyXParagraph::CLOSED_FOOTNOTE))
2801 pos += par->size() + 1;
2803 if (par->previous_) {
2804 par = par->previous_;
2806 pos += par->size() + 1;
2811 cur.boundary(boundary);
2813 /* get the cursor y position in text */
2815 Row * row = GetRow(par, pos, y);
2816 /* y is now the beginning of the cursor row */
2817 y += row->baseline();
2818 /* y is now the cursor baseline */
2821 /* now get the cursors x position */
2823 float fill_separator, fill_hfill, fill_label_hfill;
2824 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2826 LyXParagraph::size_type cursor_vpos = 0;
2827 LyXParagraph::size_type last = RowLastPrintable(row);
2829 if (pos > last + 1) // This shouldn't happen.
2831 else if (pos < row->pos())
2834 if (last < row->pos())
2835 cursor_vpos = row->pos();
2836 else if (pos > last && !boundary)
2837 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2838 ? row->pos() : last + 1;
2839 else if (pos > row->pos() &&
2840 (pos > last || boundary))
2841 /// Place cursor after char at (logical) position pos - 1
2842 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2843 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2845 /// Place cursor before char at (logical) position pos
2846 cursor_vpos = (bidi_level(pos) % 2 == 0)
2847 ? log2vis(pos) : log2vis(pos) + 1;
2849 LyXParagraph::size_type main_body =
2850 BeginningOfMainBody(bview->buffer(), row->par());
2851 if ((main_body > 0) &&
2852 ((main_body-1 > last) ||
2853 !row->par()->IsLineSeparator(main_body-1)))
2856 for (LyXParagraph::size_type vpos = row->pos();
2857 vpos < cursor_vpos; ++vpos) {
2858 pos = vis2log(vpos);
2859 if (main_body > 0 && pos == main_body - 1) {
2860 x += fill_label_hfill +
2861 lyxfont::width(textclasslist.Style(
2862 bview->buffer()->params.textclass,
2863 row->par()->GetLayout())
2865 GetFont(bview->buffer(), row->par(), -2));
2866 if (row->par()->IsLineSeparator(main_body-1))
2867 x -= SingleWidth(bview, row->par(),main_body-1);
2869 if (HfillExpansion(bview->buffer(), row, pos)) {
2870 x += SingleWidth(bview, row->par(), pos);
2871 if (pos >= main_body)
2874 x += fill_label_hfill;
2875 } else if (row->par()->IsSeparator(pos)) {
2876 x += SingleWidth(bview, row->par(), pos);
2877 if (pos >= main_body)
2878 x += fill_separator;
2880 x += SingleWidth(bview, row->par(), pos);
2889 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2890 LyXParagraph::size_type pos,
2891 bool setfont, bool boundary) const
2893 SetCursor(bview, cursor, par, pos, boundary);
2895 SetCurrentFont(bview);
2899 void LyXText::SetCurrentFont(BufferView * bview) const
2901 LyXParagraph::size_type pos = cursor.pos();
2902 if (cursor.boundary() && pos > 0)
2907 if (pos == cursor.par()->Last())
2909 if (pos == cursor.par()->size())
2912 else if (cursor.par()->IsSeparator(pos)) {
2913 if (pos > cursor.row()->pos() &&
2914 bidi_level(pos) % 2 ==
2915 bidi_level(pos - 1) % 2)
2918 else if (pos + 1 < cursor.par()->Last())
2920 else if (pos + 1 < cursor.par()->size())
2927 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2928 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2931 if (cursor.pos() == cursor.par()->Last() &&
2933 if (cursor.pos() == cursor.par()->size() &&
2935 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2936 !cursor.boundary()) {
2937 Language const * lang =
2938 cursor.par()->getParLanguage(bview->buffer()->params);
2939 current_font.setLanguage(lang);
2940 current_font.setNumber(LyXFont::OFF);
2941 real_current_font.setLanguage(lang);
2942 real_current_font.setNumber(LyXFont::OFF);
2947 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2949 LyXCursor old_cursor = cursor;
2951 /* get the row first */
2953 Row * row = GetRowNearY(y);
2954 cursor.par(row->par());
2957 int column = GetColumnNearX(bview, row, x, bound);
2958 cursor.pos(row->pos() + column);
2960 cursor.y(y + row->baseline());
2962 cursor.boundary(bound);
2963 SetCurrentFont(bview);
2964 DeleteEmptyParagraphMechanism(bview, old_cursor);
2968 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2971 /* get the row first */
2973 Row * row = GetRowNearY(y);
2975 int column = GetColumnNearX(bview, row, x, bound);
2977 cur.par(row->par());
2978 cur.pos(row->pos() + column);
2980 cur.y(y + row->baseline());
2982 cur.boundary(bound);
2986 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2988 if (cursor.pos() > 0) {
2989 bool boundary = cursor.boundary();
2990 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2991 if (!internal && !boundary &&
2992 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2993 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2994 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2995 LyXParagraph * par = cursor.par()->previous();
2997 SetCursor(bview, par, par->Last());
2999 SetCursor(bview, par, par->size());
3005 void LyXText::CursorRight(BufferView * bview, bool internal) const
3007 if (!internal && cursor.boundary() &&
3008 !cursor.par()->IsNewline(cursor.pos()))
3009 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3011 else if (cursor.pos() < cursor.par()->Last()) {
3013 else if (cursor.pos() < cursor.par()->size()) {
3015 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3017 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3018 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3019 } else if (cursor.par()->next())
3020 SetCursor(bview, cursor.par()->next(), 0);
3024 void LyXText::CursorUp(BufferView * bview) const
3026 SetCursorFromCoordinates(bview, cursor.x_fix(),
3027 cursor.y() - cursor.row()->baseline() - 1);
3031 void LyXText::CursorDown(BufferView * bview) const
3033 SetCursorFromCoordinates(bview, cursor.x_fix(),
3034 cursor.y() - cursor.row()->baseline()
3035 + cursor.row()->height() + 1);
3039 void LyXText::CursorUpParagraph(BufferView * bview) const
3041 if (cursor.pos() > 0) {
3042 SetCursor(bview, cursor.par(), 0);
3044 else if (cursor.par()->previous()) {
3045 SetCursor(bview, cursor.par()->previous(), 0);
3050 void LyXText::CursorDownParagraph(BufferView * bview) const
3052 if (cursor.par()->next()) {
3053 SetCursor(bview, cursor.par()->next(), 0);
3056 SetCursor(bview, cursor.par(), cursor.par()->Last());
3058 SetCursor(bview, cursor.par(), cursor.par()->size());
3064 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3065 LyXCursor const & old_cursor) const
3067 // Would be wrong to delete anything if we have a selection.
3068 if (selection) return;
3070 // We allow all kinds of "mumbo-jumbo" when freespacing.
3071 if (textclasslist.Style(bview->buffer()->params.textclass,
3072 old_cursor.par()->GetLayout()).free_spacing)
3075 bool deleted = false;
3077 /* Ok I'll put some comments here about what is missing.
3078 I have fixed BackSpace (and thus Delete) to not delete
3079 double-spaces automagically. I have also changed Cut,
3080 Copy and Paste to hopefully do some sensible things.
3081 There are still some small problems that can lead to
3082 double spaces stored in the document file or space at
3083 the beginning of paragraphs. This happens if you have
3084 the cursor betwenn to spaces and then save. Or if you
3085 cut and paste and the selection have a space at the
3086 beginning and then save right after the paste. I am
3087 sure none of these are very hard to fix, but I will
3088 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3089 that I can get some feedback. (Lgb)
3092 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3093 // delete the LineSeparator.
3096 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3097 // delete the LineSeparator.
3100 // If the pos around the old_cursor were spaces, delete one of them.
3101 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3102 // Only if the cursor has really moved
3104 if (old_cursor.pos() > 0
3106 && old_cursor.pos() < old_cursor.par()->Last()
3108 && old_cursor.pos() < old_cursor.par()->size()
3110 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3111 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3112 old_cursor.par()->Erase(old_cursor.pos() - 1);
3113 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3115 if (old_cursor.par() == cursor.par() &&
3116 cursor.pos() > old_cursor.pos()) {
3117 SetCursorIntern(bview, cursor.par(),
3120 SetCursorIntern(bview, cursor.par(),
3126 // Do not delete empty paragraphs with keepempty set.
3127 if ((textclasslist.Style(bview->buffer()->params.textclass,
3128 old_cursor.par()->GetLayout())).keepempty)
3131 LyXCursor tmpcursor;
3134 if (old_cursor.par() != cursor.par()) {
3135 if ((old_cursor.par()->Last() == 0
3136 || (old_cursor.par()->Last() == 1
3137 && old_cursor.par()->IsLineSeparator(0)))
3138 && old_cursor.par()->FirstPhysicalPar()
3139 == old_cursor.par()->LastPhysicalPar()
3141 if (old_cursor.par() != cursor.par()) {
3142 if ((old_cursor.par()->size() == 0
3143 || (old_cursor.par()->size() == 1
3144 && old_cursor.par()->IsLineSeparator(0)))
3147 // ok, we will delete anything
3149 // make sure that you do not delete any environments
3152 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3153 !(old_cursor.row()->previous()
3154 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3155 && !(old_cursor.row()->next()
3156 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3157 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3158 && ((old_cursor.row()->previous()
3159 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3160 || (old_cursor.row()->next()
3161 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3164 status = LyXText::NEED_MORE_REFRESH;
3167 if (old_cursor.row()->previous()) {
3168 refresh_row = old_cursor.row()->previous();
3169 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3171 cursor = old_cursor; // that undo can restore the right cursor position
3173 LyXParagraph * endpar = old_cursor.par()->next_;
3174 if (endpar && endpar->GetDepth()) {
3175 while (endpar && endpar->GetDepth()) {
3176 endpar = endpar->LastPhysicalPar()->next();
3179 SetUndo(bview->buffer(), Undo::DELETE,
3180 old_cursor.par()->previous_,
3185 RemoveRow(old_cursor.row());
3186 if (OwnerParagraph() == old_cursor.par()) {
3187 OwnerParagraph(OwnerParagraph()->next_);
3190 LyXParagraph * endpar = old_cursor.par()->next();
3191 if (endpar && endpar->GetDepth()) {
3192 while (endpar && endpar->GetDepth()) {
3193 endpar = endpar->next();
3196 SetUndo(bview->buffer(), Undo::DELETE,
3197 old_cursor.par()->previous(),
3202 RemoveRow(old_cursor.row());
3203 if (OwnerParagraph() == old_cursor.par()) {
3204 OwnerParagraph(OwnerParagraph()->next());
3208 delete old_cursor.par();
3210 /* Breakagain the next par. Needed
3211 * because of the parindent that
3212 * can occur or dissappear. The
3213 * next row can change its height,
3214 * if there is another layout before */
3215 if (refresh_row->next()) {
3216 BreakAgain(bview, refresh_row->next());
3217 UpdateCounters(bview, refresh_row);
3219 SetHeightOfRow(bview, refresh_row);
3221 refresh_row = old_cursor.row()->next();
3222 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3225 cursor = old_cursor; // that undo can restore the right cursor position
3227 LyXParagraph * endpar = old_cursor.par()->next_;
3228 if (endpar && endpar->GetDepth()) {
3229 while (endpar && endpar->GetDepth()) {
3230 endpar = endpar->LastPhysicalPar()->next();
3233 SetUndo(bview->buffer(), Undo::DELETE,
3234 old_cursor.par()->previous_,
3239 RemoveRow(old_cursor.row());
3241 if (OwnerParagraph() == old_cursor.par()) {
3242 OwnerParagraph(OwnerParagraph()->next_);
3245 LyXParagraph * endpar = old_cursor.par()->next();
3246 if (endpar && endpar->GetDepth()) {
3247 while (endpar && endpar->GetDepth()) {
3248 endpar = endpar->next();
3251 SetUndo(bview->buffer(), Undo::DELETE,
3252 old_cursor.par()->previous(),
3257 RemoveRow(old_cursor.row());
3259 if (OwnerParagraph() == old_cursor.par()) {
3260 OwnerParagraph(OwnerParagraph()->next());
3263 delete old_cursor.par();
3265 /* Breakagain the next par. Needed
3266 because of the parindent that can
3267 occur or dissappear.
3268 The next row can change its height,
3269 if there is another layout before
3272 BreakAgain(bview, refresh_row);
3273 UpdateCounters(bview, refresh_row->previous());
3279 SetCursorIntern(bview, cursor.par(), cursor.pos());
3281 if (sel_cursor.par() == old_cursor.par()
3282 && sel_cursor.pos() == sel_cursor.pos()) {
3283 // correct selection
3284 sel_cursor = cursor;
3291 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3292 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3294 SetCursorIntern(bview, cursor.par(), cursor.pos());
3295 sel_cursor = cursor;
3303 LyXParagraph * LyXText::GetParFromID(int id)
3305 LyXParagraph * result = FirstParagraph();
3306 while (result && result->id() != id)
3307 result = result->next_;
3311 LyXParagraph * LyXText::GetParFromID(int id)
3313 LyXParagraph * result = FirstParagraph();
3314 while (result && result->id() != id)
3315 result = result->next();
3322 bool LyXText::TextUndo(BufferView * bview)
3326 // returns false if no undo possible
3327 Undo * undo = bview->buffer()->undostack.pop();
3331 bview->buffer()->redostack
3332 .push(CreateUndo(bview->buffer(), undo->kind,
3333 GetParFromID(undo->number_of_before_par),
3334 GetParFromID(undo->number_of_behind_par)));
3336 return TextHandleUndo(bview, undo);
3340 bool LyXText::TextRedo(BufferView * bview)
3344 // returns false if no redo possible
3345 Undo * undo = bview->buffer()->redostack.pop();
3349 bview->buffer()->undostack
3350 .push(CreateUndo(bview->buffer(), undo->kind,
3351 GetParFromID(undo->number_of_before_par),
3352 GetParFromID(undo->number_of_behind_par)));
3354 return TextHandleUndo(bview, undo);
3358 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3362 // returns false if no undo possible
3363 bool result = false;
3365 LyXParagraph * before =
3366 GetParFromID(undo->number_of_before_par);
3367 LyXParagraph * behind =
3368 GetParFromID(undo->number_of_behind_par);
3369 LyXParagraph * tmppar;
3370 LyXParagraph * tmppar2;
3371 LyXParagraph * endpar;
3372 LyXParagraph * tmppar5;
3374 // if there's no before take the beginning
3375 // of the document for redoing
3377 SetCursorIntern(bview, FirstParagraph(), 0);
3379 // replace the paragraphs with the undo informations
3381 LyXParagraph * tmppar3 = undo->par;
3382 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3383 LyXParagraph * tmppar4 = tmppar3;
3386 while (tmppar4->next_)
3387 tmppar4 = tmppar4->next_;
3388 } // get last undo par
3390 // now remove the old text if there is any
3391 if (before != behind || (!behind && !before)) {
3393 tmppar5 = before->next();
3395 tmppar5 = OwnerParagraph();
3397 while (tmppar5 && tmppar5 != behind) {
3399 tmppar5 = tmppar5->next();
3400 // a memory optimization for edit: Only layout information
3401 // is stored in the undo. So restore the text informations.
3402 if (undo->kind == Undo::EDIT) {
3403 tmppar2->setContentsFromPar(tmppar);
3404 tmppar->clearContents();
3405 tmppar2 = tmppar2->next();
3412 while (tmppar4->next())
3413 tmppar4 = tmppar4->next();
3414 } // get last undo par
3416 // now remove the old text if there is any
3417 if (before != behind || (!behind && !before)) {
3419 tmppar5 = before->next();
3421 tmppar5 = OwnerParagraph();
3423 while (tmppar5 && tmppar5 != behind) {
3425 tmppar5 = tmppar5->next();
3426 // a memory optimization for edit: Only layout information
3427 // is stored in the undo. So restore the text informations.
3428 if (undo->kind == Undo::EDIT) {
3429 tmppar2->setContentsFromPar(tmppar);
3430 tmppar->clearContents();
3431 tmppar2 = tmppar2->next();
3437 // put the new stuff in the list if there is one
3440 before->next(tmppar3);
3442 OwnerParagraph(tmppar3);
3443 tmppar3->previous(before);
3446 OwnerParagraph(behind);
3449 tmppar4->next(behind);
3451 behind->previous(tmppar4);
3455 // Set the cursor for redoing
3458 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3460 SetCursorIntern(bview, before, 0);
3463 // check wether before points to a closed float and open it if necessary
3464 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3465 && before->next_ && before->next_->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3467 while (tmppar4->previous_ &&
3468 tmppar4->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3469 tmppar4 = tmppar4->previous_;
3470 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3471 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3472 tmppar4 = tmppar4->next_;
3479 // open a cosed footnote at the end if necessary
3480 if (behind && behind->previous_ &&
3481 behind->previous_->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3482 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3483 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3484 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3485 behind = behind->next_;
3490 // calculate the endpar for redoing the paragraphs.
3493 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3494 endpar = behind->LastPhysicalPar()->next();
3496 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->next();
3498 endpar = behind->next();
3503 tmppar = GetParFromID(undo->number_of_cursor_par);
3504 RedoParagraphs(bview, cursor, endpar);
3506 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3507 UpdateCounters(bview, cursor.row());
3517 void LyXText::FinishUndo()
3521 // makes sure the next operation will be stored
3522 undo_finished = true;
3526 void LyXText::FreezeUndo()
3530 // this is dangerous and for internal use only
3535 void LyXText::UnFreezeUndo()
3539 // this is dangerous and for internal use only
3540 undo_frozen = false;
3544 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3545 LyXParagraph const * before,
3546 LyXParagraph const * behind) const
3551 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3552 buf->redostack.clear();
3556 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3557 LyXParagraph const * before, LyXParagraph const * behind)
3561 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3565 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3566 LyXParagraph const * before,
3567 LyXParagraph const * behind) const
3572 int before_number = -1;
3573 int behind_number = -1;
3575 before_number = before->id();
3577 behind_number = behind->id();
3578 // Undo::EDIT and Undo::FINISH are
3579 // always finished. (no overlapping there)
3580 // overlapping only with insert and delete inside one paragraph:
3581 // Nobody wants all removed character
3582 // appear one by one when undoing.
3583 // EDIT is special since only layout information, not the
3584 // contents of a paragaph are stored.
3585 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3586 // check wether storing is needed
3587 if (!buf->undostack.empty() &&
3588 buf->undostack.top()->kind == kind &&
3589 buf->undostack.top()->number_of_before_par == before_number &&
3590 buf->undostack.top()->number_of_behind_par == behind_number ){
3595 // create a new Undo
3596 LyXParagraph * undopar;
3597 LyXParagraph * tmppar;
3598 LyXParagraph * tmppar2;
3600 LyXParagraph * start = 0;
3601 LyXParagraph * end = 0;
3605 start = before->next_;
3607 start = FirstParagraph();
3609 end = behind->previous_;
3611 end = FirstParagraph();
3615 if (start && end && (start != end->next_) &&
3616 ((before != behind) || (!before && !behind))) {
3618 tmppar2 = tmppar->Clone();
3619 tmppar2->id(tmppar->id());
3621 // a memory optimization: Just store the layout information
3623 if (kind == Undo::EDIT){
3624 //tmppar2->text.clear();
3625 tmppar2->clearContents();
3630 while (tmppar != end && tmppar->next_) {
3631 tmppar = tmppar->next_;
3632 tmppar2->next(tmppar->Clone());
3633 tmppar2->next_->id(tmppar->id());
3634 // a memory optimization: Just store the layout
3635 // information when only edit
3636 if (kind == Undo::EDIT){
3637 //tmppar2->next->text.clear();
3638 tmppar2->clearContents();
3640 tmppar2->next_->previous(tmppar2);
3641 tmppar2 = tmppar2->next_;
3645 undopar = 0; // nothing to replace (undo of delete maybe)
3647 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3648 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3651 start = const_cast<LyXParagraph*>(before->next());
3653 start = FirstParagraph();
3655 end = const_cast<LyXParagraph*>(behind->previous());
3657 end = FirstParagraph();
3661 if (start && end && (start != end->next()) &&
3662 ((before != behind) || (!before && !behind))) {
3664 tmppar2 = tmppar->Clone();
3665 tmppar2->id(tmppar->id());
3667 // a memory optimization: Just store the layout information
3669 if (kind == Undo::EDIT){
3670 //tmppar2->text.clear();
3671 tmppar2->clearContents();
3676 while (tmppar != end && tmppar->next()) {
3677 tmppar = tmppar->next();
3678 tmppar2->next(tmppar->Clone());
3679 tmppar2->next()->id(tmppar->id());
3680 // a memory optimization: Just store the layout
3681 // information when only edit
3682 if (kind == Undo::EDIT){
3683 //tmppar2->next->text.clear();
3684 tmppar2->clearContents();
3686 tmppar2->next()->previous(tmppar2);
3687 tmppar2 = tmppar2->next();
3691 undopar = 0; // nothing to replace (undo of delete maybe)
3693 int cursor_par = cursor.par()->id();
3694 int cursor_pos = cursor.pos();
3697 Undo * undo = new Undo(kind,
3698 before_number, behind_number,
3699 cursor_par, cursor_pos,
3702 undo_finished = false;
3707 void LyXText::SetCursorParUndo(Buffer * buf)
3711 SetUndo(buf, Undo::FINISH,
3713 cursor.par()->ParFromPos(cursor.pos())->previous_,
3714 cursor.par()->ParFromPos(cursor.pos())->next_
3716 cursor.par()->previous(),
3717 cursor.par()->next()
3723 void LyXText::toggleAppendix(BufferView * bview)
3726 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3728 LyXParagraph * par = cursor.par();
3730 bool start = !par->params.startOfAppendix();
3732 // ensure that we have only one start_of_appendix in this document
3733 LyXParagraph * tmp = FirstParagraph();
3735 for (; tmp; tmp = tmp->next_)
3736 tmp->params.startOfAppendix(false);
3738 for (; tmp; tmp = tmp->next())
3739 tmp->params.startOfAppendix(false);
3741 par->params.startOfAppendix(start);
3743 // we can set the refreshing parameters now
3744 status = LyXText::NEED_MORE_REFRESH;
3746 refresh_row = 0; // not needed for full update
3747 UpdateCounters(bview, 0);
3748 SetCursor(bview, cursor.par(), cursor.pos());
3752 LyXParagraph * LyXText::OwnerParagraph() const
3755 return inset_owner->par;
3757 return bv_owner->buffer()->paragraph;
3761 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3764 inset_owner->par = p;
3766 bv_owner->buffer()->paragraph = p;