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"
47 //#define USE_OLD_CUT_AND_PASTE 1
53 LyXText::LyXText(BufferView * bv)
61 LyXText::LyXText(InsetText * inset)
78 status = LyXText::UNCHANGED;
79 // set cursor at the very top position
80 selection = true; /* these setting is necessary
81 because of the delete-empty-
82 paragraph mechanism in
85 LyXParagraph * par = OwnerParagraph();
86 current_font = GetFont(bv_owner->buffer(), par, 0);
88 InsertParagraph(bv_owner, par, lastrow);
91 SetCursor(bv_owner, firstrow->par(), 0);
93 current_font = LyXFont(LyXFont::ALL_SANE);
99 // no rebreak necessary
102 undo_finished = true;
105 // Default layouttype for copy environment type
109 // Dump all rowinformation:
110 Row * tmprow = firstrow;
111 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
113 lyxerr << tmprow->baseline() << '\t'
114 << tmprow->par << '\t'
115 << tmprow->pos() << '\t'
116 << tmprow->height << '\t'
117 << tmprow->ascent_of_text << '\t'
118 << tmprow->fill << '\n';
119 tmprow = tmprow->next();
126 void LyXText::init(BufferView * bview)
131 LyXParagraph * par = OwnerParagraph();
132 current_font = GetFont(bview->buffer(), par, 0);
134 InsertParagraph(bview, par, lastrow);
137 SetCursorIntern(bview, firstrow->par(), 0);
140 // Dump all rowinformation:
141 Row * tmprow = firstrow;
142 lyxerr << "Width = " << width << endl;
143 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
145 lyxerr << tmprow->baseline() << '\t'
146 << tmprow->par() << '\t'
147 << tmprow->pos() << '\t'
148 << tmprow->height() << '\t'
149 << tmprow->ascent_of_text() << '\t'
150 << tmprow->fill() << '\n';
151 tmprow = tmprow->next();
159 // Delete all rows, this does not touch the paragraphs!
160 Row * tmprow = firstrow;
162 tmprow = firstrow->next();
169 // Gets the fully instantiated font at a given position in a paragraph
170 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
171 // The difference is that this one is used for displaying, and thus we
172 // are allowed to make cosmetic improvements. For instance make footnotes
174 // If position is -1, we get the layout font of the paragraph.
175 // If position is -2, we get the font of the manual label of the paragraph.
176 LyXFont LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
177 LyXParagraph::size_type pos) const
179 LyXLayout const & layout =
180 textclasslist.Style(buf->params.textclass, par->GetLayout());
182 char par_depth = par->GetDepth();
183 // We specialize the 95% common case:
186 par->footnoteflag == LyXParagraph::NO_FOOTNOTE &&
191 if (layout.labeltype == LABEL_MANUAL
192 && pos < BeginningOfMainBody(buf, par)) {
194 return par->GetFontSettings(buf->params, pos).
195 realize(layout.reslabelfont);
197 return par->GetFontSettings(buf->params, pos).
198 realize(layout.resfont);
201 // process layoutfont for pos == -1 and labelfont for pos < -1
203 return layout.resfont;
205 return layout.reslabelfont;
209 // The uncommon case need not be optimized as much
211 LyXFont layoutfont, tmpfont;
215 if (pos < BeginningOfMainBody(buf, par)) {
217 layoutfont = layout.labelfont;
220 layoutfont = layout.font;
222 tmpfont = par->GetFontSettings(buf->params, pos);
223 tmpfont.realize(layoutfont);
226 // process layoutfont for pos == -1 and labelfont for pos < -1
228 tmpfont = layout.font;
230 tmpfont = layout.labelfont;
233 // Resolve against environment font information
234 while (par && par_depth && !tmpfont.resolved()) {
235 par = par->DepthHook(par_depth - 1);
237 tmpfont.realize(textclasslist.
238 Style(buf->params.textclass,
239 par->GetLayout()).font);
240 par_depth = par->GetDepth();
244 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
247 // Cosmetic improvement: If this is an open footnote, make the font
249 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
250 && par->footnotekind == LyXParagraph::FOOTNOTE) {
258 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
259 LyXParagraph::size_type pos,
263 // Let the insets convert their font
264 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
265 if (par->GetInset(pos))
266 font = par->GetInset(pos)->ConvertFont(font);
269 LyXLayout const & layout =
270 textclasslist.Style(buf->params.textclass,
273 // Get concrete layout font to reduce against
276 if (pos < BeginningOfMainBody(buf, par))
277 layoutfont = layout.labelfont;
279 layoutfont = layout.font;
281 // Realize against environment font information
282 if (par->GetDepth()){
283 LyXParagraph * tp = par;
284 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
285 tp = tp->DepthHook(tp->GetDepth()-1);
287 layoutfont.realize(textclasslist.
288 Style(buf->params.textclass,
289 tp->GetLayout()).font);
293 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
296 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
297 && par->footnotekind == LyXParagraph::FOOTNOTE) {
298 layoutfont.decSize();
301 // Now, reduce font against full layout font
302 font.reduce(layoutfont);
304 par->SetFont(pos, font);
308 /* inserts a new row behind the specified row, increments
309 * the touched counters */
310 void LyXText::InsertRow(Row * row, LyXParagraph * par,
311 LyXParagraph::size_type pos) const
313 Row * tmprow = new Row;
316 tmprow->next(firstrow);
319 tmprow->previous(row);
320 tmprow->next(row->next());
325 tmprow->next()->previous(tmprow);
327 if (tmprow->previous())
328 tmprow->previous()->next(tmprow);
336 ++number_of_rows; // one more row
340 // removes the row and reset the touched counters
341 void LyXText::RemoveRow(Row * row) const
343 /* this must not happen before the currentrow for clear reasons.
344 so the trick is just to set the current row onto the previous
347 GetRow(row->par(), row->pos(), unused_y);
350 row->next()->previous(row->previous());
351 if (!row->previous()) {
352 firstrow = row->next();
354 row->previous()->next(row->next());
357 lastrow = row->previous();
359 height -= row->height(); // the text becomes smaller
362 --number_of_rows; // one row less
366 // remove all following rows of the paragraph of the specified row.
367 void LyXText::RemoveParagraph(Row * row) const
369 LyXParagraph * tmppar = row->par();
373 while (row && row->par() == tmppar) {
374 tmprow = row->next();
381 // insert the specified paragraph behind the specified row
382 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
385 InsertRow(row, par, 0); /* insert a new row, starting
388 SetCounter(bview->buffer(), par); // set the counters
390 // and now append the whole paragraph behind the new row
393 AppendParagraph(bview, firstrow);
395 row->next()->height(0);
396 AppendParagraph(bview, row->next());
402 void LyXText::ToggleFootnote(BufferView * bview)
404 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
406 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
408 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
410 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
411 CloseFootnote(bview);
417 void LyXText::OpenStuff(BufferView * bview)
419 if (cursor.pos() == 0 && cursor.par()->bibkey){
420 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
421 } else if (cursor.pos() < cursor.par()->Last()
422 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
423 && cursor.par()->GetInset(cursor.pos())->Editable()) {
424 bview->owner()->getMiniBuffer()
425 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
426 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
427 SetCursorParUndo(bview->buffer());
428 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
432 ToggleFootnote(bview);
439 void LyXText::CloseFootnote(BufferView * bview)
441 LyXParagraph * tmppar;
442 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
444 // if the cursor is not in an open footnote, or
445 // there is no open footnote in this paragraph, just return.
446 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
449 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
450 bview->owner()->getMiniBuffer()
451 ->Set(_("Nothing to do"));
455 // ok, move the cursor right before the footnote
456 // just a little faster than using CursorRight()
458 cursor.par()->ParFromPos(cursor.pos()) != par;) {
459 cursor.pos(cursor.pos() + 1);
462 // now the cursor is at the beginning of the physical par
463 SetCursor(bview, cursor.par(),
465 cursor.par()->ParFromPos(cursor.pos())->size());
467 /* we are in a footnote, so let us move at the beginning */
468 /* this is just faster than using just CursorLeft() */
470 tmppar = cursor.par();
471 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
472 // just a little bit faster than movin the cursor
473 tmppar = tmppar->Previous();
475 SetCursor(bview, tmppar, tmppar->Last());
478 // the cursor must be exactly before the footnote
479 par = cursor.par()->ParFromPos(cursor.pos());
481 status = LyXText::NEED_MORE_REFRESH;
482 refresh_row = cursor.row();
483 refresh_y = cursor.y() - cursor.row()->baseline();
485 tmppar = cursor.par();
486 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
487 Row * row = cursor.row();
489 tmppar->CloseFootnote(cursor.pos());
491 while (tmppar != endpar) {
492 RemoveRow(row->next());
494 tmppar = row->next()->par();
499 AppendParagraph(bview, cursor.row());
501 SetCursor(bview, cursor.par(), cursor.pos());
505 if (cursor.row()->next())
506 SetHeightOfRow(bview, cursor.row()->next());
511 /* used in setlayout */
512 // Asger is not sure we want to do this...
513 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
517 LyXLayout const & layout =
518 textclasslist.Style(buf->params.textclass, par->GetLayout());
520 LyXFont layoutfont, tmpfont;
521 for (LyXParagraph::size_type pos = 0;
522 pos < par->Last(); ++pos) {
523 if (pos < BeginningOfMainBody(buf, par))
524 layoutfont = layout.labelfont;
526 layoutfont = layout.font;
528 tmpfont = par->GetFontSettings(buf->params, pos);
529 tmpfont.reduce(layoutfont);
530 par->SetFont(pos, tmpfont);
535 LyXParagraph * LyXText::SetLayout(BufferView * bview,
536 LyXCursor & cur, LyXCursor & sstart_cur,
537 LyXCursor & send_cur,
538 LyXTextClass::size_type layout)
540 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
541 LyXParagraph * undoendpar = endpar;
543 if (endpar && endpar->GetDepth()) {
544 while (endpar && endpar->GetDepth()) {
545 endpar = endpar->LastPhysicalPar()->Next();
549 endpar = endpar->Next(); // because of parindents etc.
552 SetUndo(bview->buffer(), Undo::EDIT,
553 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
556 /* ok we have a selection. This is always between sstart_cur
557 * and sel_end cursor */
560 LyXLayout const & lyxlayout =
561 textclasslist.Style(bview->buffer()->params.textclass, layout);
563 while (cur.par() != send_cur.par()) {
565 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
567 cur.par()->SetLayout(bview->buffer()->params, layout);
568 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
569 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
570 fppar->added_space_top = lyxlayout.fill_top ?
571 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
572 fppar->added_space_bottom = lyxlayout.fill_bottom ?
573 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
574 if (lyxlayout.margintype == MARGIN_MANUAL)
575 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
576 if (lyxlayout.labeltype != LABEL_BIBLIO
578 delete fppar->bibkey;
584 cur.par(cur.par()->Next());
587 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
589 cur.par()->SetLayout(bview->buffer()->params, layout);
590 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
591 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
592 fppar->added_space_top = lyxlayout.fill_top ?
593 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
594 fppar->added_space_bottom = lyxlayout.fill_bottom ?
595 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
596 if (lyxlayout.margintype == MARGIN_MANUAL)
597 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
598 if (lyxlayout.labeltype != LABEL_BIBLIO
600 delete fppar->bibkey;
609 // set layout over selection and make a total rebreak of those paragraphs
610 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
613 tmpcursor = cursor; /* store the current cursor */
615 #ifdef USE_OLD_SET_LAYOUT
616 // if there is no selection just set the layout
617 // of the current paragraph */
619 sel_start_cursor = cursor; // dummy selection
620 sel_end_cursor = cursor;
623 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
624 LyXParagraph * undoendpar = endpar;
626 if (endpar && endpar->GetDepth()) {
627 while (endpar && endpar->GetDepth()) {
628 endpar = endpar->LastPhysicalPar()->Next();
633 endpar = endpar->Next(); // because of parindents etc.
637 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
640 /* ok we have a selection. This is always between sel_start_cursor
641 * and sel_end cursor */
642 cursor = sel_start_cursor;
644 LyXLayout const & lyxlayout =
645 textclasslist.Style(bview->buffer()->params.textclass, layout);
647 while (cursor.par() != sel_end_cursor.par()) {
648 if (cursor.par()->footnoteflag ==
649 sel_start_cursor.par()->footnoteflag) {
650 cursor.par()->SetLayout(layout);
651 MakeFontEntriesLayoutSpecific(cursor.par());
652 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
653 fppar->added_space_top = lyxlayout.fill_top ?
654 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
655 fppar->added_space_bottom = lyxlayout.fill_bottom ?
656 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
657 if (lyxlayout.margintype == MARGIN_MANUAL)
658 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
659 if (lyxlayout.labeltype != LABEL_BIBLIO
661 delete fppar->bibkey;
665 cursor.par() = cursor.par()->Next();
667 if (cursor.par()->footnoteflag ==
668 sel_start_cursor.par()->footnoteflag) {
669 cursor.par()->SetLayout(layout);
670 MakeFontEntriesLayoutSpecific(cursor.par());
671 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
672 fppar->added_space_top = lyxlayout.fill_top ?
673 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
674 fppar->added_space_bottom = lyxlayout.fill_bottom ?
675 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
676 if (lyxlayout.margintype == MARGIN_MANUAL)
677 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
678 if (lyxlayout.labeltype != LABEL_BIBLIO
680 delete fppar->bibkey;
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);
695 RedoParagraphs(bview, sel_start_cursor, endpar);
697 // we have to reset the selection, because the
698 // geometry could have changed */
699 SetCursor(bview, sel_start_cursor.par(),
700 sel_start_cursor.pos(), false);
702 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
704 UpdateCounters(bview, cursor.row());
707 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
711 // increment depth over selection and
712 // make a total rebreak of those paragraphs
713 void LyXText::IncDepth(BufferView * bview)
715 // If there is no selection, just use the current paragraph
717 sel_start_cursor = cursor; // dummy selection
718 sel_end_cursor = cursor;
721 // We end at the next paragraph with depth 0
722 LyXParagraph * endpar =
723 sel_end_cursor.par()->LastPhysicalPar()->Next();
724 LyXParagraph * undoendpar = endpar;
726 if (endpar && endpar->GetDepth()) {
727 while (endpar && endpar->GetDepth()) {
728 endpar = endpar->LastPhysicalPar()->Next();
733 endpar = endpar->Next(); // because of parindents etc.
736 SetUndo(bview->buffer(), Undo::EDIT,
738 .par()->ParFromPos(sel_start_cursor.pos())->previous,
741 LyXCursor tmpcursor = cursor; // store the current cursor
743 // ok we have a selection. This is always between sel_start_cursor
744 // and sel_end cursor
745 cursor = sel_start_cursor;
747 bool anything_changed = false;
750 // NOTE: you can't change the depth of a bibliography entry
751 if (cursor.par()->footnoteflag ==
752 sel_start_cursor.par()->footnoteflag
753 && textclasslist.Style(bview->buffer()->params.textclass,
754 cursor.par()->GetLayout()
755 ).labeltype != LABEL_BIBLIO) {
756 LyXParagraph * prev =
757 cursor.par()->FirstPhysicalPar()->Previous();
759 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
760 || (prev->GetDepth() == cursor.par()->GetDepth()
761 && textclasslist.Style(bview->buffer()->params.textclass,
762 prev->GetLayout()).isEnvironment()))) {
763 cursor.par()->FirstPhysicalPar()->depth++;
764 anything_changed = true;
767 if (cursor.par() == sel_end_cursor.par())
769 cursor.par(cursor.par()->Next());
772 // if nothing changed set all depth to 0
773 if (!anything_changed) {
774 cursor = sel_start_cursor;
775 while (cursor.par() != sel_end_cursor.par()) {
776 cursor.par()->FirstPhysicalPar()->depth = 0;
777 cursor.par(cursor.par()->Next());
779 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
780 cursor.par()->FirstPhysicalPar()->depth = 0;
783 RedoParagraphs(bview, sel_start_cursor, endpar);
785 // we have to reset the selection, because the
786 // geometry could have changed
787 SetCursor(bview, sel_start_cursor.par(),
788 sel_start_cursor.pos());
790 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
791 UpdateCounters(bview, cursor.row());
794 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
798 // decrement depth over selection and
799 // make a total rebreak of those paragraphs
800 void LyXText::DecDepth(BufferView * bview)
802 // if there is no selection just set the layout
803 // of the current paragraph
805 sel_start_cursor = cursor; // dummy selection
806 sel_end_cursor = cursor;
809 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
810 LyXParagraph * undoendpar = endpar;
812 if (endpar && endpar->GetDepth()) {
813 while (endpar && endpar->GetDepth()) {
814 endpar = endpar->LastPhysicalPar()->Next();
819 endpar = endpar->Next(); // because of parindents etc.
822 SetUndo(bview->buffer(), Undo::EDIT,
824 .par()->ParFromPos(sel_start_cursor.pos())->previous,
827 LyXCursor tmpcursor = cursor; // store the current cursor
829 // ok we have a selection. This is always between sel_start_cursor
830 // and sel_end cursor
831 cursor = sel_start_cursor;
834 if (cursor.par()->footnoteflag ==
835 sel_start_cursor.par()->footnoteflag) {
836 if (cursor.par()->FirstPhysicalPar()->depth)
837 cursor.par()->FirstPhysicalPar()->depth--;
839 if (cursor.par() == sel_end_cursor.par())
841 cursor.par(cursor.par()->Next());
844 RedoParagraphs(bview, sel_start_cursor, endpar);
846 // we have to reset the selection, because the
847 // geometry could have changed
848 SetCursor(bview, sel_start_cursor.par(),
849 sel_start_cursor.pos());
851 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
852 UpdateCounters(bview, cursor.row());
855 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
859 // set font over selection and make a total rebreak of those paragraphs
860 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
862 // if there is no selection just set the current_font
864 // Determine basis font
866 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
868 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
870 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
871 // Update current font
872 real_current_font.update(font,
873 bview->buffer()->params.language_info,
876 // Reduce to implicit settings
877 current_font = real_current_font;
878 current_font.reduce(layoutfont);
879 // And resolve it completely
880 real_current_font.realize(layoutfont);
884 LyXCursor tmpcursor = cursor; // store the current cursor
886 // ok we have a selection. This is always between sel_start_cursor
887 // and sel_end cursor
889 SetUndo(bview->buffer(), Undo::EDIT,
890 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
891 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next);
892 cursor = sel_start_cursor;
893 while (cursor.par() != sel_end_cursor.par() ||
894 (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag
895 && cursor.pos() < sel_end_cursor.pos()))
897 if (cursor.pos() < cursor.par()->Last()
898 && cursor.par()->footnoteflag
899 == sel_start_cursor.par()->footnoteflag) {
900 // an open footnote should behave
902 LyXFont newfont = GetFont(bview->buffer(),
903 cursor.par(), cursor.pos());
905 bview->buffer()->params.language_info,
907 SetCharFont(bview->buffer(),
908 cursor.par(), cursor.pos(), newfont);
909 cursor.pos(cursor.pos() + 1);
912 cursor.par(cursor.par()->Next());
916 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
918 // we have to reset the selection, because the
919 // geometry could have changed
920 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
922 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
925 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
926 tmpcursor.boundary());
930 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
932 Row * tmprow = cur.row();
933 long y = cur.y() - tmprow->baseline();
935 SetHeightOfRow(bview, tmprow);
936 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
937 // find the first row of the paragraph
938 if (first_phys_par != tmprow->par())
939 while (tmprow->previous()
940 && tmprow->previous()->par() != first_phys_par) {
941 tmprow = tmprow->previous();
942 y -= tmprow->height();
943 SetHeightOfRow(bview, tmprow);
945 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
946 tmprow = tmprow->previous();
947 y -= tmprow->height();
948 SetHeightOfRow(bview, tmprow);
951 // we can set the refreshing parameters now
952 status = LyXText::NEED_MORE_REFRESH;
954 refresh_row = tmprow;
955 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
959 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
961 Row * tmprow = cur.row();
963 long y = cur.y() - tmprow->baseline();
964 SetHeightOfRow(bview, tmprow);
965 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
966 // find the first row of the paragraph
967 if (first_phys_par != tmprow->par())
968 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
969 tmprow = tmprow->previous();
970 y -= tmprow->height();
972 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
973 tmprow = tmprow->previous();
974 y -= tmprow->height();
977 // we can set the refreshing parameters now
978 if (status == LyXText::UNCHANGED || y < refresh_y) {
980 refresh_row = tmprow;
982 status = LyXText::NEED_MORE_REFRESH;
983 SetCursor(bview, cur.par(), cur.pos());
987 /* deletes and inserts again all paragaphs between the cursor
988 * and the specified par
989 * This function is needed after SetLayout and SetFont etc. */
990 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
991 LyXParagraph const * endpar) const
994 LyXParagraph * tmppar = 0, * first_phys_par = 0;
996 Row * tmprow = cur.row();
998 long y = cur.y() - tmprow->baseline();
1000 if (!tmprow->previous()){
1001 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
1003 first_phys_par = tmprow->par()->FirstPhysicalPar();
1004 // find the first row of the paragraph
1005 if (first_phys_par != tmprow->par())
1006 while (tmprow->previous() &&
1007 (tmprow->previous()->par() != first_phys_par)) {
1008 tmprow = tmprow->previous();
1009 y -= tmprow->height();
1011 while (tmprow->previous()
1012 && tmprow->previous()->par() == first_phys_par) {
1013 tmprow = tmprow->previous();
1014 y -= tmprow->height();
1018 // we can set the refreshing parameters now
1019 status = LyXText::NEED_MORE_REFRESH;
1021 refresh_row = tmprow->previous(); /* the real refresh row will
1022 be deleted, so I store
1023 the previous here */
1026 tmppar = tmprow->next()->par();
1029 while (tmppar != endpar) {
1030 RemoveRow(tmprow->next());
1032 tmppar = tmprow->next()->par();
1037 // remove the first one
1038 tmprow2 = tmprow; /* this is because tmprow->previous()
1040 tmprow = tmprow->previous();
1043 tmppar = first_phys_par;
1047 InsertParagraph(bview, tmppar, tmprow);
1050 while (tmprow->next() && tmprow->next()->par() == tmppar)
1051 tmprow = tmprow->next();
1052 tmppar = tmppar->Next();
1054 } while (tmppar != endpar);
1056 // this is because of layout changes
1058 refresh_y -= refresh_row->height();
1059 SetHeightOfRow(bview, refresh_row);
1061 refresh_row = firstrow;
1063 SetHeightOfRow(bview, refresh_row);
1066 if (tmprow && tmprow->next())
1067 SetHeightOfRow(bview, tmprow->next());
1071 bool LyXText::FullRebreak(BufferView * bview)
1077 if (need_break_row) {
1078 BreakAgain(bview, need_break_row);
1086 /* important for the screen */
1089 /* the cursor set functions have a special mechanism. When they
1090 * realize, that you left an empty paragraph, they will delete it.
1091 * They also delete the corresponding row */
1093 // need the selection cursor:
1094 void LyXText::SetSelection()
1097 last_sel_cursor = sel_cursor;
1098 sel_start_cursor = sel_cursor;
1099 sel_end_cursor = sel_cursor;
1104 // first the toggling area
1105 if (cursor.y() < last_sel_cursor.y()
1106 || (cursor.y() == last_sel_cursor.y()
1107 && cursor.x() < last_sel_cursor.x())) {
1108 toggle_end_cursor = last_sel_cursor;
1109 toggle_cursor = cursor;
1111 toggle_end_cursor = cursor;
1112 toggle_cursor = last_sel_cursor;
1115 last_sel_cursor = cursor;
1117 // and now the whole selection
1119 if (sel_cursor.par() == cursor.par())
1120 if (sel_cursor.pos() < cursor.pos()) {
1121 sel_end_cursor = cursor;
1122 sel_start_cursor = sel_cursor;
1124 sel_end_cursor = sel_cursor;
1125 sel_start_cursor = cursor;
1127 else if (sel_cursor.y() < cursor.y() ||
1128 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1129 sel_end_cursor = cursor;
1130 sel_start_cursor = sel_cursor;
1133 sel_end_cursor = sel_cursor;
1134 sel_start_cursor = cursor;
1137 // a selection with no contents is not a selection
1138 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1139 sel_start_cursor.pos() == sel_end_cursor.pos())
1144 string LyXText::selectionAsString(Buffer const * buffer) const
1146 if (!selection) return string();
1149 // Special handling if the whole selection is within one paragraph
1150 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1151 result += sel_start_cursor.par()->String(buffer,
1152 sel_start_cursor.pos(),
1153 sel_end_cursor.pos());
1157 // The selection spans more than one paragraph
1159 // First paragraph in selection
1160 result += sel_start_cursor.par()->String(buffer,
1161 sel_start_cursor.pos(),
1162 sel_start_cursor.par()->Last())
1165 // The paragraphs in between (if any)
1166 LyXCursor tmpcur(sel_start_cursor);
1167 tmpcur.par(tmpcur.par()->Next());
1168 while (tmpcur.par() != sel_end_cursor.par()) {
1169 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1170 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1173 // Last paragraph in selection
1174 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1180 void LyXText::ClearSelection() const
1187 void LyXText::CursorHome(BufferView * bview) const
1189 SetCursor(bview, cursor.par(), cursor.row()->pos());
1193 void LyXText::CursorEnd(BufferView * bview) const
1195 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1196 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1198 if (cursor.par()->Last() &&
1199 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1200 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1201 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1203 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1206 if (cursor.par()->table) {
1207 int cell = NumberOfCell(cursor.par(), cursor.pos());
1208 if (cursor.par()->table->RowHasContRow(cell) &&
1209 cursor.par()->table->CellHasContRow(cell)<0) {
1210 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1211 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1213 if (cursor.par()->Last() &&
1214 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1215 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1216 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1218 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1226 void LyXText::CursorTop(BufferView * bview) const
1228 while (cursor.par()->Previous())
1229 cursor.par(cursor.par()->Previous());
1230 SetCursor(bview, cursor.par(), 0);
1234 void LyXText::CursorBottom(BufferView * bview) const
1236 while (cursor.par()->Next())
1237 cursor.par(cursor.par()->Next());
1238 SetCursor(bview, cursor.par(), cursor.par()->Last());
1242 /* returns a pointer to the row near the specified y-coordinate
1243 * (relative to the whole text). y is set to the real beginning
1245 Row * LyXText::GetRowNearY(long & y) const
1247 Row * tmprow = firstrow;
1250 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1251 tmpy += tmprow->height();
1252 tmprow = tmprow->next();
1255 y = tmpy; // return the real y
1260 void LyXText::ToggleFree(BufferView * bview,
1261 LyXFont const & font, bool toggleall)
1263 // If the mask is completely neutral, tell user
1264 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1265 // Could only happen with user style
1266 bview->owner()->getMiniBuffer()
1267 ->Set(_("No font change defined. Use Character under"
1268 " the Layout menu to define font change."));
1272 // Try implicit word selection
1273 // If there is a change in the language the implicit word selection
1275 LyXCursor resetCursor = cursor;
1276 bool implicitSelection = (font.language() == ignore_language)
1277 ? SelectWordWhenUnderCursor(bview) : false;
1280 SetFont(bview, font, toggleall);
1282 /* Implicit selections are cleared afterwards and cursor is set to the
1283 original position. */
1284 if (implicitSelection) {
1286 cursor = resetCursor;
1287 SetCursor(bview, cursor.par(), cursor.pos());
1288 sel_cursor = cursor;
1293 LyXParagraph::size_type
1294 LyXText::BeginningOfMainBody(Buffer const * buf,
1295 LyXParagraph const * par) const
1297 if (textclasslist.Style(buf->params.textclass,
1298 par->GetLayout()).labeltype != LABEL_MANUAL)
1301 return par->BeginningOfMainBody();
1306 /* if there is a selection, reset every environment you can find
1307 * in the selection, otherwise just the environment you are in */
1308 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1310 LyXParagraph * tmppar, * firsttmppar;
1314 /* is is only allowed, if the cursor is IN an open footnote.
1315 * Otherwise it is too dangerous */
1316 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1319 SetUndo(bview->buffer(), Undo::FINISH,
1320 cursor.par()->PreviousBeforeFootnote()->previous,
1321 cursor.par()->NextAfterFootnote()->next);
1323 /* ok, move to the beginning of the footnote. */
1324 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1325 cursor.par(cursor.par()->Previous());
1327 SetCursor(bview, cursor.par(), cursor.par()->Last());
1328 /* this is just faster than using CursorLeft(); */
1330 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1331 tmppar = firsttmppar;
1332 /* tmppar is now the paragraph right before the footnote */
1334 bool first_footnote_par_is_not_empty = tmppar->next->size();
1337 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1338 tmppar = tmppar->next; /* I use next instead of Next(),
1339 * because there cannot be any
1340 * footnotes in a footnote
1342 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1344 /* remember the captions and empty paragraphs */
1345 if ((textclasslist.Style(bview->buffer()->params.textclass,
1346 tmppar->GetLayout())
1347 .labeltype == LABEL_SENSITIVE)
1349 tmppar->SetLayout(bview->buffer()->params, 0);
1352 // now we will paste the ex-footnote, if the layouts allow it
1353 // first restore the layout of the paragraph right behind
1356 tmppar->next->MakeSameLayout(cursor.par());
1359 if ((!tmppar->GetLayout() && !tmppar->table)
1361 && (!tmppar->Next()->Last()
1362 || tmppar->Next()->HasSameLayout(tmppar)))) {
1363 if (tmppar->Next()->Last()
1364 && tmppar->Next()->IsLineSeparator(0))
1365 tmppar->Next()->Erase(0);
1366 tmppar->PasteParagraph(bview->buffer()->params);
1369 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1370 * by the pasting of the beginning */
1372 /* then the beginning */
1373 /* if there is no space between the text and the footnote, so we insert
1375 * (only if the previous par and the footnotepar are not empty!) */
1376 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1377 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1378 if (firsttmppar->size()
1379 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1380 && first_footnote_par_is_not_empty) {
1381 firsttmppar->next->InsertChar(0, ' ');
1383 firsttmppar->PasteParagraph(bview->buffer()->params);
1386 /* now redo the paragaphs */
1387 RedoParagraphs(bview, cursor, tmppar);
1389 SetCursor(bview, cursor.par(), cursor.pos());
1391 /* sometimes it can happen, that there is a counter change */
1392 Row * row = cursor.row();
1393 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1395 UpdateCounters(bview, row);
1403 /* the DTP switches for paragraphs. LyX will store them in the
1404 * first physicla paragraph. When a paragraph is broken, the top settings
1405 * rest, the bottom settings are given to the new one. So I can make shure,
1406 * they do not duplicate themself and you cannnot make dirty things with
1409 void LyXText::SetParagraph(BufferView * bview,
1410 bool line_top, bool line_bottom,
1411 bool pagebreak_top, bool pagebreak_bottom,
1412 VSpace const & space_top,
1413 VSpace const & space_bottom,
1415 string labelwidthstring,
1418 LyXCursor tmpcursor = cursor;
1420 sel_start_cursor = cursor;
1421 sel_end_cursor = cursor;
1424 // make sure that the depth behind the selection are restored, too
1425 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1426 LyXParagraph * undoendpar = endpar;
1428 if (endpar && endpar->GetDepth()) {
1429 while (endpar && endpar->GetDepth()) {
1430 endpar = endpar->LastPhysicalPar()->Next();
1431 undoendpar = endpar;
1435 endpar = endpar->Next(); // because of parindents etc.
1438 SetUndo(bview->buffer(), Undo::EDIT,
1440 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1444 LyXParagraph * tmppar = sel_end_cursor.par();
1445 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1446 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1447 status = LyXText::NEED_MORE_REFRESH;
1448 refresh_row = cursor.row();
1449 refresh_y = cursor.y() - cursor.row()->baseline();
1450 if (cursor.par()->footnoteflag ==
1451 sel_start_cursor.par()->footnoteflag) {
1452 cursor.par()->line_top = line_top;
1453 cursor.par()->line_bottom = line_bottom;
1454 cursor.par()->pagebreak_top = pagebreak_top;
1455 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1456 cursor.par()->added_space_top = space_top;
1457 cursor.par()->added_space_bottom = space_bottom;
1458 // does the layout allow the new alignment?
1459 if (align == LYX_ALIGN_LAYOUT)
1460 align = textclasslist
1461 .Style(bview->buffer()->params.textclass,
1462 cursor.par()->GetLayout()).align;
1463 if (align & textclasslist
1464 .Style(bview->buffer()->params.textclass,
1465 cursor.par()->GetLayout()).alignpossible) {
1466 if (align == textclasslist
1467 .Style(bview->buffer()->params.textclass,
1468 cursor.par()->GetLayout()).align)
1469 cursor.par()->align = LYX_ALIGN_LAYOUT;
1471 cursor.par()->align = align;
1473 cursor.par()->SetLabelWidthString(labelwidthstring);
1474 cursor.par()->noindent = noindent;
1477 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1480 RedoParagraphs(bview, sel_start_cursor, endpar);
1483 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1484 sel_cursor = cursor;
1485 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1487 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1491 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1493 char const * widthp,
1494 int alignment, bool hfill,
1495 bool start_minipage)
1497 LyXCursor tmpcursor = cursor;
1498 LyXParagraph * tmppar;
1500 sel_start_cursor = cursor;
1501 sel_end_cursor = cursor;
1504 // make sure that the depth behind the selection are restored, too
1505 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1506 LyXParagraph * undoendpar = endpar;
1508 if (endpar && endpar->GetDepth()) {
1509 while (endpar && endpar->GetDepth()) {
1510 endpar = endpar->LastPhysicalPar()->Next();
1511 undoendpar = endpar;
1515 endpar = endpar->Next(); // because of parindents etc.
1518 SetUndo(bview->buffer(), Undo::EDIT,
1520 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1523 tmppar = sel_end_cursor.par();
1524 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1525 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1526 status = LyXText::NEED_MORE_REFRESH;
1527 refresh_row = cursor.row();
1528 refresh_y = cursor.y() - cursor.row()->baseline();
1529 if (cursor.par()->footnoteflag ==
1530 sel_start_cursor.par()->footnoteflag) {
1531 if (type == LyXParagraph::PEXTRA_NONE) {
1532 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1533 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1534 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1537 cursor.par()->SetPExtraType(bview->buffer()->params,
1538 type, width, widthp);
1539 cursor.par()->pextra_hfill = hfill;
1540 cursor.par()->pextra_start_minipage = start_minipage;
1541 cursor.par()->pextra_alignment = alignment;
1544 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1546 RedoParagraphs(bview, sel_start_cursor, endpar);
1548 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1549 sel_cursor = cursor;
1550 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1552 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1556 char loweralphaCounter(int n)
1558 if (n < 1 || n > 26)
1565 char alphaCounter(int n)
1567 if (n < 1 || n > 26)
1574 char hebrewCounter(int n)
1576 static const char hebrew[22] = {
1577 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1578 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1579 '÷', 'ø', 'ù', 'ú'
1581 if (n < 1 || n > 22)
1589 char const * romanCounter(int n)
1591 static char const * roman[20] = {
1592 "i", "ii", "iii", "iv", "v",
1593 "vi", "vii", "viii", "ix", "x",
1594 "xi", "xii", "xiii", "xiv", "xv",
1595 "xvi", "xvii", "xviii", "xix", "xx"
1597 if (n < 1 || n > 20)
1604 // set the counter of a paragraph. This includes the labels
1605 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1607 // this is only relevant for the beginning of paragraph
1608 par = par->FirstPhysicalPar();
1610 LyXLayout const & layout =
1611 textclasslist.Style(buf->params.textclass,
1614 LyXTextClass const & textclass =
1615 textclasslist.TextClass(buf->params.textclass);
1617 /* copy the prev-counters to this one, unless this is the start of a
1618 footnote or of a bibliography or the very first paragraph */
1620 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1621 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1622 && par->footnotekind == LyXParagraph::FOOTNOTE)
1623 && !(textclasslist.Style(buf->params.textclass,
1624 par->Previous()->GetLayout()
1625 ).labeltype != LABEL_BIBLIO
1626 && layout.labeltype == LABEL_BIBLIO)) {
1627 for (int i = 0; i < 10; ++i) {
1628 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1630 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1631 if (!par->appendix && par->start_of_appendix){
1632 par->appendix = true;
1633 for (int i = 0; i < 10; ++i) {
1634 par->setCounter(i, 0);
1637 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1638 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1640 for (int i = 0; i < 10; ++i) {
1641 par->setCounter(i, 0);
1643 par->appendix = par->start_of_appendix;
1649 // if this is an open marginnote and this is the first
1650 // entry in the marginnote and the enclosing
1651 // environment is an enum/item then correct for the
1652 // LaTeX behaviour (ARRae)
1653 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1654 && par->footnotekind == LyXParagraph::MARGIN
1656 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1657 && (par->PreviousBeforeFootnote()
1658 && textclasslist.Style(buf->params.textclass,
1659 par->PreviousBeforeFootnote()->GetLayout()
1660 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1661 // Any itemize or enumerate environment in a marginnote
1662 // that is embedded in an itemize or enumerate
1663 // paragraph is seen by LaTeX as being at a deeper
1664 // level within that enclosing itemization/enumeration
1665 // even if there is a "standard" layout at the start of
1671 /* Maybe we have to increment the enumeration depth.
1672 * BUT, enumeration in a footnote is considered in isolation from its
1673 * surrounding paragraph so don't increment if this is the
1674 * first line of the footnote
1675 * AND, bibliographies can't have their depth changed ie. they
1676 * are always of depth 0
1679 && par->Previous()->GetDepth() < par->GetDepth()
1680 && textclasslist.Style(buf->params.textclass,
1681 par->Previous()->GetLayout()
1682 ).labeltype == LABEL_COUNTER_ENUMI
1683 && par->enumdepth < 3
1685 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1686 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1687 && par->footnotekind == LyXParagraph::FOOTNOTE)
1689 && layout.labeltype != LABEL_BIBLIO) {
1693 /* Maybe we have to decrement the enumeration depth, see note above */
1695 && par->Previous()->GetDepth() > par->GetDepth()
1697 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1698 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1699 && par->footnotekind == LyXParagraph::FOOTNOTE)
1701 && layout.labeltype != LABEL_BIBLIO) {
1702 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1703 par->setCounter(6 + par->enumdepth,
1704 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1705 /* reset the counters.
1706 * A depth change is like a breaking layout
1708 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1709 par->setCounter(i, 0);
1712 if (!par->labelstring.empty()) {
1713 par->labelstring.erase();
1716 if (layout.margintype == MARGIN_MANUAL) {
1717 if (par->labelwidthstring.empty()) {
1718 par->SetLabelWidthString(layout.labelstring());
1721 par->SetLabelWidthString(string());
1724 /* is it a layout that has an automatic label ? */
1725 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1727 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1728 if (i >= 0 && i<= buf->params.secnumdepth) {
1729 par->incCounter(i); // increment the counter
1731 // Is there a label? Useful for Chapter layout
1732 if (!par->appendix){
1733 if (!layout.labelstring().empty())
1734 par->labelstring = layout.labelstring();
1736 par->labelstring.erase();
1738 if (!layout.labelstring_appendix().empty())
1739 par->labelstring = layout.labelstring_appendix();
1741 par->labelstring.erase();
1745 std::ostringstream s;
1749 if (!par->appendix) {
1750 switch (2 * LABEL_COUNTER_CHAPTER -
1751 textclass.maxcounter() + i) {
1752 case LABEL_COUNTER_CHAPTER:
1753 s << par->getCounter(i);
1755 case LABEL_COUNTER_SECTION:
1756 s << par->getCounter(i - 1) << '.'
1757 << par->getCounter(i);
1759 case LABEL_COUNTER_SUBSECTION:
1760 s << par->getCounter(i - 2) << '.'
1761 << par->getCounter(i - 1) << '.'
1762 << par->getCounter(i);
1764 case LABEL_COUNTER_SUBSUBSECTION:
1765 s << par->getCounter(i - 3) << '.'
1766 << par->getCounter(i - 2) << '.'
1767 << par->getCounter(i - 1) << '.'
1768 << par->getCounter(i);
1771 case LABEL_COUNTER_PARAGRAPH:
1772 s << par->getCounter(i - 4) << '.'
1773 << par->getCounter(i - 3) << '.'
1774 << par->getCounter(i - 2) << '.'
1775 << par->getCounter(i - 1) << '.'
1776 << par->getCounter(i);
1778 case LABEL_COUNTER_SUBPARAGRAPH:
1779 s << par->getCounter(i - 5) << '.'
1780 << par->getCounter(i - 4) << '.'
1781 << par->getCounter(i - 3) << '.'
1782 << par->getCounter(i - 2) << '.'
1783 << par->getCounter(i - 1) << '.'
1784 << par->getCounter(i);
1788 // Can this ever be reached? And in the
1789 // case it is, how can this be correct?
1791 s << par->getCounter(i) << '.';
1794 } else { // appendix
1795 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1796 case LABEL_COUNTER_CHAPTER:
1797 if (par->isRightToLeftPar(buf->params))
1798 s << hebrewCounter(par->getCounter(i));
1800 s << alphaCounter(par->getCounter(i));
1802 case LABEL_COUNTER_SECTION:
1803 if (par->isRightToLeftPar(buf->params))
1804 s << hebrewCounter(par->getCounter(i - 1));
1806 s << alphaCounter(par->getCounter(i - 1));
1809 << par->getCounter(i);
1812 case LABEL_COUNTER_SUBSECTION:
1813 if (par->isRightToLeftPar(buf->params))
1814 s << hebrewCounter(par->getCounter(i - 2));
1816 s << alphaCounter(par->getCounter(i - 2));
1819 << par->getCounter(i-1) << '.'
1820 << par->getCounter(i);
1823 case LABEL_COUNTER_SUBSUBSECTION:
1824 if (par->isRightToLeftPar(buf->params))
1825 s << hebrewCounter(par->getCounter(i-3));
1827 s << alphaCounter(par->getCounter(i-3));
1830 << par->getCounter(i-2) << '.'
1831 << par->getCounter(i-1) << '.'
1832 << par->getCounter(i);
1835 case LABEL_COUNTER_PARAGRAPH:
1836 if (par->isRightToLeftPar(buf->params))
1837 s << hebrewCounter(par->getCounter(i-4));
1839 s << alphaCounter(par->getCounter(i-4));
1842 << par->getCounter(i-3) << '.'
1843 << par->getCounter(i-2) << '.'
1844 << par->getCounter(i-1) << '.'
1845 << par->getCounter(i);
1848 case LABEL_COUNTER_SUBPARAGRAPH:
1849 if (par->isRightToLeftPar(buf->params))
1850 s << hebrewCounter(par->getCounter(i-5));
1852 s << alphaCounter(par->getCounter(i-5));
1855 << par->getCounter(i-4) << '.'
1856 << par->getCounter(i-3) << '.'
1857 << par->getCounter(i-2) << '.'
1858 << par->getCounter(i-1) << '.'
1859 << par->getCounter(i);
1863 // Can this ever be reached? And in the
1864 // case it is, how can this be correct?
1866 s << par->getCounter(i) << '.';
1872 par->labelstring += s.str().c_str();
1873 // We really want to remove the c_str as soon as
1877 char * tmps = s.str();
1878 par->labelstring += tmps;
1882 for (i++; i < 10; ++i) {
1883 // reset the following counters
1884 par->setCounter(i, 0);
1886 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1887 for (i++; i < 10; ++i) {
1888 // reset the following counters
1889 par->setCounter(i, 0);
1891 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1892 par->incCounter(i + par->enumdepth);
1893 int number = par->getCounter(i + par->enumdepth);
1896 std::ostringstream s;
1900 switch (par->enumdepth) {
1902 if (par->isRightToLeftPar(buf->params))
1904 << hebrewCounter(number)
1908 << loweralphaCounter(number)
1912 if (par->isRightToLeftPar(buf->params))
1913 s << '.' << romanCounter(number);
1915 s << romanCounter(number) << '.';
1918 if (par->isRightToLeftPar(buf->params))
1920 << alphaCounter(number);
1922 s << alphaCounter(number)
1926 if (par->isRightToLeftPar(buf->params))
1933 par->labelstring = s.str().c_str();
1934 // we really want to get rid of that c_str()
1937 char * tmps = s.str();
1938 par->labelstring = tmps;
1942 for (i += par->enumdepth + 1; i < 10; ++i)
1943 par->setCounter(i, 0); /* reset the following counters */
1946 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1947 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1949 int number = par->getCounter(i);
1951 par->bibkey = new InsetBibKey();
1952 par->bibkey->setCounter(number);
1953 par->labelstring = layout.labelstring();
1955 // In biblio should't be following counters but...
1957 string s = layout.labelstring();
1959 // the caption hack:
1960 if (layout.labeltype == LABEL_SENSITIVE) {
1961 bool isOK (par->InInset() && par->InInset()->owner() &&
1962 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
1964 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1965 && (par->footnotekind == LyXParagraph::FIG
1966 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
1967 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1968 ? ":øåéà " : "Figure:";
1969 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1970 && (par->footnotekind == LyXParagraph::TAB
1971 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
1972 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1973 ? ":äìáè" : "Table:";
1974 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1975 && par->footnotekind == LyXParagraph::ALGORITHM) {
1976 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1977 ? ":Ãúéøåâìà " : "Algorithm:";
1981 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
1983 = floatList.getType(tmp->type());
1984 // We should get the correct number here too.
1985 s = fl.name + " #:";
1987 /* par->SetLayout(0);
1988 s = layout->labelstring; */
1989 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1990 ? " :úåòîùî øñç" : "Senseless: ";
1993 par->labelstring = s;
1995 /* reset the enumeration counter. They are always resetted
1996 * when there is any other layout between */
1997 for (int i = 6 + par->enumdepth; i < 10; ++i)
1998 par->setCounter(i, 0);
2003 /* Updates all counters BEHIND the row. Changed paragraphs
2004 * with a dynamic left margin will be rebroken. */
2005 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2012 if (row->par()->next
2014 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
2017 par = row->par()->LastPhysicalPar()->Next();
2019 par = row->par()->next;
2024 while (row->par() != par)
2027 SetCounter(bview->buffer(), par);
2029 /* now check for the headline layouts. remember that they
2030 * have a dynamic left margin */
2032 && ( textclasslist.Style(bview->buffer()->params.textclass,
2033 par->layout).margintype == MARGIN_DYNAMIC
2034 || textclasslist.Style(bview->buffer()->params.textclass,
2035 par->layout).labeltype == LABEL_SENSITIVE)
2038 /* Rebreak the paragraph */
2039 RemoveParagraph(row);
2040 AppendParagraph(bview, row);
2043 /* think about the damned open footnotes! */
2044 while (par->Next() &&
2045 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2046 || par->Next()->IsDummy())){
2048 if (par->IsDummy()) {
2049 while (row->par() != par)
2051 RemoveParagraph(row);
2052 AppendParagraph(bview, row);
2058 par = par->LastPhysicalPar()->Next();
2064 /* insets an inset. */
2065 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2067 if (!cursor.par()->InsertInsetAllowed(inset))
2069 SetUndo(bview->buffer(), Undo::INSERT,
2070 cursor.par()->ParFromPos(cursor.pos())->previous,
2071 cursor.par()->ParFromPos(cursor.pos())->next);
2072 cursor.par()->InsertInset(cursor.pos(), inset);
2073 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2074 * The character will not be inserted a
2079 void LyXText::copyEnvironmentType()
2081 copylayouttype = cursor.par()->GetLayout();
2085 void LyXText::pasteEnvironmentType(BufferView * bview)
2087 SetLayout(bview, copylayouttype);
2091 void LyXText::CutSelection(BufferView * bview, bool doclear)
2093 // Stuff what we got on the clipboard. Even if there is no selection.
2095 // There is a problem with having the stuffing here in that the
2096 // larger the selection the slower LyX will get. This can be
2097 // solved by running the line below only when the selection has
2098 // finished. The solution used currently just works, to make it
2099 // faster we need to be more clever and probably also have more
2100 // calls to stuffClipboard. (Lgb)
2101 bview->stuffClipboard(selectionAsString(bview->buffer()));
2103 // This doesn't make sense, if there is no selection
2107 // OK, we have a selection. This is always between sel_start_cursor
2108 // and sel_end cursor
2109 LyXParagraph * tmppar;
2112 // Check whether there are half footnotes in the selection
2113 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2114 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2115 tmppar = sel_start_cursor.par();
2116 while (tmppar != sel_end_cursor.par()){
2117 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2118 WriteAlert(_("Impossible operation"),
2119 _("Don't know what to do with half floats."),
2123 tmppar = tmppar->Next();
2128 /* table stuff -- begin */
2129 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2130 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2131 WriteAlert(_("Impossible operation"),
2132 _("Don't know what to do with half tables."),
2136 sel_start_cursor.par()->table->Reinit();
2138 /* table stuff -- end */
2140 // make sure that the depth behind the selection are restored, too
2141 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2142 LyXParagraph * undoendpar = endpar;
2144 if (endpar && endpar->GetDepth()) {
2145 while (endpar && endpar->GetDepth()) {
2146 endpar = endpar->LastPhysicalPar()->Next();
2147 undoendpar = endpar;
2149 } else if (endpar) {
2150 endpar = endpar->Next(); // because of parindents etc.
2153 SetUndo(bview->buffer(), Undo::DELETE, sel_start_cursor
2154 .par()->ParFromPos(sel_start_cursor.pos())->previous, undoendpar);
2158 // there are two cases: cut only within one paragraph or
2159 // more than one paragraph
2160 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2161 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2162 // only within one paragraph
2163 endpar = sel_start_cursor.par();
2164 int pos = sel_end_cursor.pos();
2165 cap.cutSelection(sel_start_cursor.par(), &endpar,
2166 sel_start_cursor.pos(), pos,
2167 bview->buffer()->params.textclass, doclear);
2168 sel_end_cursor.pos(pos);
2170 endpar = sel_end_cursor.par();
2172 int pos = sel_end_cursor.pos();
2173 cap.cutSelection(sel_start_cursor.par(), &endpar,
2174 sel_start_cursor.pos(), pos,
2175 bview->buffer()->params.textclass, doclear);
2177 sel_end_cursor.par(endpar);
2178 sel_end_cursor.pos(pos);
2179 cursor.pos(sel_end_cursor.pos());
2181 endpar = endpar->Next();
2183 // sometimes necessary
2185 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2187 RedoParagraphs(bview, sel_start_cursor, endpar);
2190 cursor = sel_start_cursor;
2191 SetCursor(bview, cursor.par(), cursor.pos());
2192 sel_cursor = cursor;
2193 UpdateCounters(bview, cursor.row());
2197 void LyXText::CopySelection(BufferView * bview)
2199 // Stuff what we got on the clipboard. Even if there is no selection.
2201 // There is a problem with having the stuffing here in that the
2202 // larger the selection the slower LyX will get. This can be
2203 // solved by running the line below only when the selection has
2204 // finished. The solution used currently just works, to make it
2205 // faster we need to be more clever and probably also have more
2206 // calls to stuffClipboard. (Lgb)
2207 bview->stuffClipboard(selectionAsString(bview->buffer()));
2209 // this doesnt make sense, if there is no selection
2213 // ok we have a selection. This is always between sel_start_cursor
2214 // and sel_end cursor
2215 LyXParagraph * tmppar;
2218 /* check wether there are half footnotes in the selection */
2219 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2220 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2221 tmppar = sel_start_cursor.par();
2222 while (tmppar != sel_end_cursor.par()) {
2223 if (tmppar->footnoteflag !=
2224 sel_end_cursor.par()->footnoteflag) {
2225 WriteAlert(_("Impossible operation"),
2226 _("Don't know what to do"
2227 " with half floats."),
2231 tmppar = tmppar->Next();
2236 /* table stuff -- begin */
2237 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2238 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2239 WriteAlert(_("Impossible operation"),
2240 _("Don't know what to do with half tables."),
2245 /* table stuff -- end */
2248 // copy behind a space if there is one
2249 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2250 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2251 && (sel_start_cursor.par() != sel_end_cursor.par()
2252 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2253 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2257 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2258 sel_start_cursor.pos(), sel_end_cursor.pos(),
2259 bview->buffer()->params.textclass);
2263 void LyXText::PasteSelection(BufferView * bview)
2267 // this does not make sense, if there is nothing to paste
2268 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2271 SetUndo(bview->buffer(), Undo::INSERT,
2272 cursor.par()->ParFromPos(cursor.pos())->previous,
2273 cursor.par()->ParFromPos(cursor.pos())->next);
2275 LyXParagraph * endpar;
2276 LyXParagraph * actpar = cursor.par();
2278 int pos = cursor.pos();
2279 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2281 RedoParagraphs(bview, cursor, endpar);
2283 SetCursor(bview, cursor.par(), cursor.pos());
2286 sel_cursor = cursor;
2287 SetCursor(bview, actpar, pos);
2289 UpdateCounters(bview, cursor.row());
2293 // returns a pointer to the very first LyXParagraph
2294 LyXParagraph * LyXText::FirstParagraph() const
2296 return OwnerParagraph();
2300 // returns true if the specified string is at the specified position
2301 bool LyXText::IsStringInText(LyXParagraph * par,
2302 LyXParagraph::size_type pos,
2303 char const * str) const
2307 while (pos + i < par->Last() && str[i] &&
2308 str[i] == par->GetChar(pos + i)) {
2318 // sets the selection over the number of characters of string, no check!!
2319 void LyXText::SetSelectionOverString(BufferView * bview, char const * string)
2321 sel_cursor = cursor;
2322 for (int i = 0; string[i]; ++i)
2328 // simple replacing. The font of the first selected character is used
2329 void LyXText::ReplaceSelectionWithString(BufferView * bview, char const * str)
2331 SetCursorParUndo(bview->buffer());
2334 if (!selection) { // create a dummy selection
2335 sel_end_cursor = cursor;
2336 sel_start_cursor = cursor;
2339 // Get font setting before we cut
2340 LyXParagraph::size_type pos = sel_end_cursor.pos();
2341 LyXFont font = sel_start_cursor.par()->GetFontSettings(bview->buffer()->params,
2342 sel_start_cursor.pos());
2344 // Insert the new string
2345 for (int i = 0; str[i]; ++i) {
2346 sel_end_cursor.par()->InsertChar(pos, str[i], font);
2350 // Cut the selection
2351 CutSelection(bview);
2357 // if the string can be found: return true and set the cursor to
2359 bool LyXText::SearchForward(BufferView * bview, char const * str) const
2361 LyXParagraph * par = cursor.par();
2362 LyXParagraph::size_type pos = cursor.pos();
2363 while (par && !IsStringInText(par, pos, str)) {
2364 if (pos < par->Last() - 1)
2372 SetCursor(bview, par, pos);
2380 bool LyXText::SearchBackward(BufferView * bview, char const * string) const
2382 LyXParagraph * par = cursor.par();
2383 int pos = cursor.pos();
2389 // We skip empty paragraphs (Asger)
2391 par = par->Previous();
2393 pos = par->Last() - 1;
2394 } while (par && pos < 0);
2396 } while (par && !IsStringInText(par, pos, string));
2399 SetCursor(bview, par, pos);
2406 // needed to insert the selection
2407 void LyXText::InsertStringA(BufferView * bview, string const & str)
2409 LyXParagraph * par = cursor.par();
2410 LyXParagraph::size_type pos = cursor.pos();
2411 LyXParagraph::size_type a = 0;
2413 LyXParagraph * endpar = cursor.par()->Next();
2415 SetCursorParUndo(bview->buffer());
2418 textclasslist.Style(bview->buffer()->params.textclass,
2419 cursor.par()->GetLayout()).isEnvironment();
2420 // only to be sure, should not be neccessary
2423 // insert the string, don't insert doublespace
2424 string::size_type i = 0;
2425 while (i < str.length()) {
2426 if (str[i] != '\n') {
2428 && i + 1 < str.length() && str[i + 1] != ' '
2429 && pos && par->GetChar(pos - 1)!= ' ') {
2430 par->InsertChar(pos, ' ', current_font);
2433 } else if (par->table) {
2434 if (str[i] == '\t') {
2435 while((pos < par->size()) &&
2436 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2438 if (pos < par->size())
2440 else // no more fields to fill skip the rest
2442 } else if ((str[i] != 13) &&
2443 ((str[i] & 127) >= ' ')) {
2444 par->InsertChar(pos, str[i],
2449 } else if (str[i] == ' ') {
2450 InsetSpecialChar * new_inset =
2451 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2452 if (par->InsertInsetAllowed(new_inset)) {
2453 par->InsertInset(pos, new_inset,
2459 } else if (str[i] == '\t') {
2460 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2461 InsetSpecialChar * new_inset =
2462 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2463 if (par->InsertInsetAllowed(new_inset)) {
2464 par->InsertInset(pos, new_inset,
2471 } else if (str[i] != 13 &&
2472 // Ignore unprintables
2473 (str[i] & 127) >= ' ') {
2474 par->InsertChar(pos, str[i], current_font);
2480 if ((i + 1) >= str.length()) {
2481 if (pos < par->size())
2485 while((pos < par->size()) &&
2486 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2489 cell = NumberOfCell(par, pos);
2490 while((pos < par->size()) &&
2491 !(par->table->IsFirstCell(cell))) {
2493 while((pos < par->size()) &&
2494 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2497 cell = NumberOfCell(par, pos);
2499 if (pos >= par->size())
2500 // no more fields to fill skip the rest
2504 if (!par->size()) { // par is empty
2505 InsetSpecialChar * new_inset =
2506 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2507 if (par->InsertInsetAllowed(new_inset)) {
2508 par->InsertInset(pos,
2516 par->BreakParagraph(bview->buffer()->params, pos, flag);
2526 RedoParagraphs(bview, cursor, endpar);
2527 SetCursor(bview, cursor.par(), cursor.pos());
2528 sel_cursor = cursor;
2529 SetCursor(bview, par, pos);
2534 /* turns double-CR to single CR, others where converted into one blank and 13s
2535 * that are ignored .Double spaces are also converted into one. Spaces at
2536 * the beginning of a paragraph are forbidden. tabs are converted into one
2537 * space. then InsertStringA is called */
2538 void LyXText::InsertStringB(BufferView * bview, string const & s)
2541 LyXParagraph * par = cursor.par();
2542 string::size_type i = 1;
2543 while (i < str.length()) {
2544 if (str[i] == '\t' && !par->table)
2546 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2548 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2549 if (str[i + 1] != '\n') {
2550 if (str[i - 1] != ' ')
2555 while (i + 1 < str.length()
2556 && (str[i + 1] == ' '
2557 || str[i + 1] == '\t'
2558 || str[i + 1] == '\n'
2559 || str[i + 1] == 13)) {
2566 InsertStringA(bview, str);
2570 bool LyXText::GotoNextError(BufferView * bview) const
2572 LyXCursor res = cursor;
2574 if (res.pos() < res.par()->Last() - 1) {
2575 res.pos(res.pos() + 1);
2577 res.par(res.par()->Next());
2581 } while (res.par() &&
2582 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2583 && res.par()->GetInset(res.pos())->AutoDelete()));
2586 SetCursor(bview, res.par(), res.pos());
2593 bool LyXText::GotoNextNote(BufferView * bview) const
2595 LyXCursor res = cursor;
2597 if (res.pos() < res.par()->Last() - 1) {
2598 res.pos(res.pos() + 1);
2600 res.par(res.par()->Next());
2604 } while (res.par() &&
2605 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2606 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
2609 SetCursor(bview, res.par(), res.pos());
2616 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2617 LyXParagraph::size_type pos)
2619 LyXCursor tmpcursor;
2622 /* table stuff -- begin*/
2625 CheckParagraphInTable(bview, par, pos);
2629 /* table stuff -- end*/
2632 LyXParagraph::size_type z;
2633 Row * row = GetRow(par, pos, y);
2635 // is there a break one row above
2636 if (row->previous() && row->previous()->par() == row->par()) {
2637 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2638 if ( z >= row->pos()) {
2639 // set the dimensions of the row above
2640 y -= row->previous()->height();
2642 refresh_row = row->previous();
2643 status = LyXText::NEED_MORE_REFRESH;
2645 BreakAgain(bview, row->previous());
2647 // set the cursor again. Otherwise
2648 // dangling pointers are possible
2649 SetCursor(bview, cursor.par(), cursor.pos());
2650 sel_cursor = cursor;
2655 int tmpheight = row->height();
2656 LyXParagraph::size_type tmplast = RowLast(row);
2660 BreakAgain(bview, row);
2661 if (row->height() == tmpheight && RowLast(row) == tmplast)
2662 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2664 status = LyXText::NEED_MORE_REFRESH;
2666 // check the special right address boxes
2667 if (textclasslist.Style(bview->buffer()->params.textclass,
2668 par->GetLayout()).margintype
2669 == MARGIN_RIGHT_ADDRESS_BOX) {
2676 RedoDrawingOfParagraph(bview, tmpcursor);
2682 // set the cursor again. Otherwise dangling pointers are possible
2683 // also set the selection
2687 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos());
2688 sel_cursor = cursor;
2689 SetCursorIntern(bview, sel_start_cursor.par(),
2690 sel_start_cursor.pos());
2691 sel_start_cursor = cursor;
2692 SetCursorIntern(bview, sel_end_cursor.par(),
2693 sel_end_cursor.pos());
2694 sel_end_cursor = cursor;
2695 SetCursorIntern(bview, last_sel_cursor.par(),
2696 last_sel_cursor.pos());
2697 last_sel_cursor = cursor;
2700 SetCursorIntern(bview, cursor.par(), cursor.pos());
2704 // returns false if inset wasn't found
2705 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2707 // first check the current paragraph
2708 int pos = cursor.par()->GetPositionOfInset(inset);
2710 CheckParagraph(bview, cursor.par(), pos);
2714 // check every paragraph
2716 LyXParagraph * par = FirstParagraph();
2719 // make sure the paragraph is open
2720 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2722 pos = par->GetPositionOfInset(inset);
2724 CheckParagraph(bview, par, pos);
2737 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2738 LyXParagraph::size_type pos,
2739 bool setfont, bool boundary) const
2741 LyXCursor old_cursor = cursor;
2742 SetCursorIntern(bview, par, pos, setfont, boundary);
2743 DeleteEmptyParagraphMechanism(bview, old_cursor);
2747 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2748 LyXParagraph::size_type pos, bool boundary) const
2750 // correct the cursor position if impossible
2751 if (pos > par->Last()){
2752 LyXParagraph * tmppar = par->ParFromPos(pos);
2753 pos = par->PositionInParFromPos(pos);
2757 if (par->IsDummy() && par->previous &&
2758 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2759 while (par->previous &&
2760 ((par->previous->IsDummy() &&
2761 (par->previous->previous->footnoteflag ==
2762 LyXParagraph::CLOSED_FOOTNOTE)) ||
2763 (par->previous->footnoteflag ==
2764 LyXParagraph::CLOSED_FOOTNOTE))) {
2765 par = par->previous ;
2766 if (par->IsDummy() &&
2767 (par->previous->footnoteflag ==
2768 LyXParagraph::CLOSED_FOOTNOTE))
2769 pos += par->size() + 1;
2771 if (par->previous) {
2772 par = par->previous;
2774 pos += par->size() + 1;
2779 cur.boundary(boundary);
2781 /* get the cursor y position in text */
2783 Row * row = GetRow(par, pos, y);
2784 /* y is now the beginning of the cursor row */
2785 y += row->baseline();
2786 /* y is now the cursor baseline */
2789 /* now get the cursors x position */
2791 float fill_separator, fill_hfill, fill_label_hfill;
2792 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2794 LyXParagraph::size_type cursor_vpos = 0;
2795 LyXParagraph::size_type last = RowLastPrintable(row);
2797 if (pos > last + 1) // This shouldn't happen.
2799 else if (pos < row->pos())
2802 if (last < row->pos())
2803 cursor_vpos = row->pos();
2804 else if (pos > last && !boundary)
2805 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2806 ? row->pos() : last + 1;
2807 else if (pos > row->pos() &&
2808 (pos > last || boundary ||
2809 (row->par()->table && row->par()->IsNewline(pos))))
2810 /// Place cursor after char at (logical) position pos - 1
2811 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2812 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2814 /// Place cursor before char at (logical) position pos
2815 cursor_vpos = (bidi_level(pos) % 2 == 0)
2816 ? log2vis(pos) : log2vis(pos) + 1;
2819 /* table stuff -- begin*/
2820 if (row->par()->table) {
2821 int cell = NumberOfCell(row->par(), row->pos());
2823 x += row->par()->table->GetBeginningOfTextInCell(cell);
2824 for (LyXParagraph::size_type vpos = row->pos();
2825 vpos < cursor_vpos; ++vpos) {
2826 pos = vis2log(vpos);
2827 if (row->par()->IsNewline(pos)) {
2828 x = x_old + row->par()->table->WidthOfColumn(cell);
2831 x += row->par()->table->GetBeginningOfTextInCell(cell);
2833 x += SingleWidth(bview, row->par(), pos);
2837 /* table stuff -- end*/
2839 LyXParagraph::size_type main_body =
2840 BeginningOfMainBody(bview->buffer(), row->par());
2841 if ((main_body > 0) &&
2842 ((main_body-1 > last) ||
2843 !row->par()->IsLineSeparator(main_body-1)))
2846 for (LyXParagraph::size_type vpos = row->pos();
2847 vpos < cursor_vpos; ++vpos) {
2848 pos = vis2log(vpos);
2849 if (main_body > 0 && pos == main_body-1) {
2850 x += fill_label_hfill +
2851 lyxfont::width(textclasslist.Style(
2852 bview->buffer()->params.textclass,
2853 row->par()->GetLayout())
2855 GetFont(bview->buffer(), row->par(), -2));
2856 if (row->par()->IsLineSeparator(main_body-1))
2857 x -= SingleWidth(bview, row->par(),main_body-1);
2859 if (HfillExpansion(bview->buffer(), row, pos)) {
2860 x += SingleWidth(bview, row->par(), pos);
2861 if (pos >= main_body)
2864 x += fill_label_hfill;
2865 } else if (row->par()->IsSeparator(pos)) {
2866 x += SingleWidth(bview, row->par(), pos);
2867 if (pos >= main_body)
2868 x += fill_separator;
2870 x += SingleWidth(bview, row->par(), pos);
2882 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2883 LyXParagraph::size_type pos,
2884 bool setfont, bool boundary) const
2886 SetCursor(bview, cursor, par, pos, boundary);
2888 SetCurrentFont(bview);
2891 void LyXText::SetCurrentFont(BufferView * bview) const
2893 LyXParagraph::size_type pos = cursor.pos();
2894 if (cursor.boundary() && pos > 0)
2898 if (pos == cursor.par()->Last() ||
2899 (cursor.par()->table && cursor.par()->IsNewline(pos)))
2901 else if (cursor.par()->IsSeparator(pos)) {
2902 if (pos > cursor.row()->pos() &&
2903 bidi_level(pos) % 2 ==
2904 bidi_level(pos - 1) % 2)
2906 else if (pos + 1 < cursor.par()->Last())
2912 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2913 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2915 if (cursor.pos() == cursor.par()->Last() &&
2916 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2917 !cursor.boundary()) {
2918 Language const * lang =
2919 cursor.par()->getParLanguage(bview->buffer()->params);
2920 current_font.setLanguage(lang);
2921 real_current_font.setLanguage(lang);
2926 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, long y) const
2928 LyXCursor old_cursor = cursor;
2930 /* get the row first */
2932 Row * row = GetRowNearY(y);
2933 cursor.par(row->par());
2936 int column = GetColumnNearX(bview, row, x, bound);
2937 cursor.pos(row->pos() + column);
2939 cursor.y(y + row->baseline());
2941 cursor.boundary(bound);
2942 SetCurrentFont(bview);
2943 DeleteEmptyParagraphMechanism(bview, old_cursor);
2947 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2948 int x, long y) const
2950 /* get the row first */
2952 Row * row = GetRowNearY(y);
2954 int column = GetColumnNearX(bview, row, x, bound);
2956 cur.par(row->par());
2957 cur.pos(row->pos() + column);
2959 cur.y(y + row->baseline());
2961 cur.boundary(bound);
2965 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2967 CursorLeftIntern(bview, internal);
2969 if (cursor.par()->table) {
2970 int cell = NumberOfCell(cursor.par(), cursor.pos());
2971 if (cursor.par()->table->IsContRow(cell)
2972 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
2980 void LyXText::CursorLeftIntern(BufferView * bview, bool internal) const
2982 if (cursor.pos() > 0) {
2983 bool boundary = cursor.boundary();
2984 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2985 if (!internal && !boundary &&
2986 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2987 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2988 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2989 LyXParagraph * par = cursor.par()->Previous();
2990 SetCursor(bview, par, par->Last());
2995 void LyXText::CursorRight(BufferView * bview, bool internal) const
2997 CursorRightIntern(bview, internal);
2999 if (cursor.par()->table) {
3000 int cell = NumberOfCell(cursor.par(), cursor.pos());
3001 if (cursor.par()->table->IsContRow(cell) &&
3002 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3010 void LyXText::CursorRightIntern(BufferView * bview, bool internal) const
3012 if (!internal && cursor.boundary() &&
3013 (!cursor.par()->table || !cursor.par()->IsNewline(cursor.pos())))
3014 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3015 else if (cursor.pos() < cursor.par()->Last()) {
3016 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3018 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3019 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3020 } else if (cursor.par()->Next())
3021 SetCursor(bview, cursor.par()->Next(), 0);
3025 void LyXText::CursorUp(BufferView * bview) const
3027 SetCursorFromCoordinates(bview, cursor.x_fix(),
3028 cursor.y() - cursor.row()->baseline() - 1);
3030 if (cursor.par()->table) {
3031 int cell = NumberOfCell(cursor.par(), cursor.pos());
3032 if (cursor.par()->table->IsContRow(cell) &&
3033 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3041 void LyXText::CursorDown(BufferView * bview) const
3044 if (cursor.par()->table &&
3045 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3046 !cursor.par()->next)
3050 SetCursorFromCoordinates(bview, cursor.x_fix(),
3051 cursor.y() - cursor.row()->baseline()
3052 + cursor.row()->height() + 1);
3054 if (cursor.par()->table) {
3055 int cell = NumberOfCell(cursor.par(), cursor.pos());
3056 int cell_above = cursor.par()->table->GetCellAbove(cell);
3057 while(cursor.par()->table &&
3058 cursor.par()->table->IsContRow(cell) &&
3059 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3060 SetCursorFromCoordinates(bview, cursor.x_fix(),
3061 cursor.y() - cursor.row()->baseline()
3062 + cursor.row()->height() + 1);
3063 if (cursor.par()->table) {
3064 cell = NumberOfCell(cursor.par(), cursor.pos());
3065 cell_above = cursor.par()->table->GetCellAbove(cell);
3073 void LyXText::CursorUpParagraph(BufferView * bview) const
3075 if (cursor.pos() > 0) {
3076 SetCursor(bview, cursor.par(), 0);
3078 else if (cursor.par()->Previous()) {
3079 SetCursor(bview, cursor.par()->Previous(), 0);
3084 void LyXText::CursorDownParagraph(BufferView * bview) const
3086 if (cursor.par()->Next()) {
3087 SetCursor(bview, cursor.par()->Next(), 0);
3089 SetCursor(bview, cursor.par(), cursor.par()->Last());
3094 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3095 LyXCursor const & old_cursor) const
3097 // Would be wrong to delete anything if we have a selection.
3098 if (selection) return;
3100 // We allow all kinds of "mumbo-jumbo" when freespacing.
3101 if (textclasslist.Style(bview->buffer()->params.textclass,
3102 old_cursor.par()->GetLayout()).free_spacing)
3105 bool deleted = false;
3107 /* Ok I'll put some comments here about what is missing.
3108 I have fixed BackSpace (and thus Delete) to not delete
3109 double-spaces automagically. I have also changed Cut,
3110 Copy and Paste to hopefully do some sensible things.
3111 There are still some small problems that can lead to
3112 double spaces stored in the document file or space at
3113 the beginning of paragraphs. This happens if you have
3114 the cursor betwenn to spaces and then save. Or if you
3115 cut and paste and the selection have a space at the
3116 beginning and then save right after the paste. I am
3117 sure none of these are very hard to fix, but I will
3118 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3119 that I can get some feedback. (Lgb)
3122 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3123 // delete the LineSeparator.
3126 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3127 // delete the LineSeparator.
3130 // If the pos around the old_cursor were spaces, delete one of them.
3131 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3132 // Only if the cursor has really moved
3134 if (old_cursor.pos() > 0
3135 && old_cursor.pos() < old_cursor.par()->Last()
3136 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3137 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3138 old_cursor.par()->Erase(old_cursor.pos() - 1);
3139 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3141 if (old_cursor.par() == cursor.par() &&
3142 cursor.pos() > old_cursor.pos()) {
3143 SetCursorIntern(bview, cursor.par(),
3146 SetCursorIntern(bview, cursor.par(),
3152 // Do not delete empty paragraphs with keepempty set.
3153 if ((textclasslist.Style(bview->buffer()->params.textclass,
3154 old_cursor.par()->GetLayout())).keepempty)
3157 LyXCursor tmpcursor;
3159 if (old_cursor.par() != cursor.par()) {
3160 if ( (old_cursor.par()->Last() == 0
3161 || (old_cursor.par()->Last() == 1
3162 && old_cursor.par()->IsLineSeparator(0)))
3163 && old_cursor.par()->FirstPhysicalPar()
3164 == old_cursor.par()->LastPhysicalPar()) {
3165 // ok, we will delete anything
3167 // make sure that you do not delete any environments
3168 if ((old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3169 !(old_cursor.row()->previous()
3170 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3171 && !(old_cursor.row()->next()
3172 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3173 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3174 && ((old_cursor.row()->previous()
3175 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3176 || (old_cursor.row()->next()
3177 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3179 status = LyXText::NEED_MORE_REFRESH;
3182 if (old_cursor.row()->previous()) {
3183 refresh_row = old_cursor.row()->previous();
3184 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3186 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());
3200 if (OwnerParagraph() == old_cursor.par()) {
3201 OwnerParagraph(OwnerParagraph()->next);
3204 delete old_cursor.par();
3206 /* Breakagain the next par. Needed
3207 * because of the parindent that
3208 * can occur or dissappear. The
3209 * next row can change its height,
3210 * if there is another layout before */
3211 if (refresh_row->next()) {
3212 BreakAgain(bview, refresh_row->next());
3213 UpdateCounters(bview, refresh_row);
3215 SetHeightOfRow(bview, refresh_row);
3217 refresh_row = old_cursor.row()->next();
3218 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3221 cursor = old_cursor; // that undo can restore the right cursor position
3222 LyXParagraph * endpar = old_cursor.par()->next;
3223 if (endpar && endpar->GetDepth()) {
3224 while (endpar && endpar->GetDepth()) {
3225 endpar = endpar->LastPhysicalPar()->Next();
3228 SetUndo(bview->buffer(), Undo::DELETE,
3229 old_cursor.par()->previous,
3234 RemoveRow(old_cursor.row());
3236 if (OwnerParagraph() == old_cursor.par()) {
3237 OwnerParagraph(OwnerParagraph()->next);
3239 delete old_cursor.par();
3241 /* Breakagain the next par. Needed
3242 because of the parindent that can
3243 occur or dissappear.
3244 The next row can change its height,
3245 if there is another layout before
3248 BreakAgain(bview, refresh_row);
3249 UpdateCounters(bview, refresh_row->previous());
3255 SetCursorIntern(bview, cursor.par(), cursor.pos());
3257 if (sel_cursor.par() == old_cursor.par()
3258 && sel_cursor.pos() == sel_cursor.pos()) {
3259 // correct selection
3260 sel_cursor = cursor;
3265 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3266 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3268 SetCursorIntern(bview, cursor.par(), cursor.pos());
3269 sel_cursor = cursor;
3276 LyXParagraph * LyXText::GetParFromID(int id)
3278 LyXParagraph * result = FirstParagraph();
3279 while (result && result->id() != id)
3280 result = result->next;
3286 bool LyXText::TextUndo(BufferView * bview)
3290 // returns false if no undo possible
3291 Undo * undo = bview->buffer()->undostack.pop();
3295 bview->buffer()->redostack
3296 .push(CreateUndo(bview->buffer(), undo->kind,
3297 GetParFromID(undo->number_of_before_par),
3298 GetParFromID(undo->number_of_behind_par)));
3300 return TextHandleUndo(bview, undo);
3304 bool LyXText::TextRedo(BufferView * bview)
3308 // returns false if no redo possible
3309 Undo * undo = bview->buffer()->redostack.pop();
3313 bview->buffer()->undostack
3314 .push(CreateUndo(bview->buffer(), undo->kind,
3315 GetParFromID(undo->number_of_before_par),
3316 GetParFromID(undo->number_of_behind_par)));
3318 return TextHandleUndo(bview, undo);
3322 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3326 // returns false if no undo possible
3327 bool result = false;
3329 LyXParagraph * before =
3330 GetParFromID(undo->number_of_before_par);
3331 LyXParagraph * behind =
3332 GetParFromID(undo->number_of_behind_par);
3333 LyXParagraph * tmppar;
3334 LyXParagraph * tmppar2;
3335 LyXParagraph * endpar;
3336 LyXParagraph * tmppar5;
3338 // if there's no before take the beginning
3339 // of the document for redoing
3341 SetCursorIntern(bview, FirstParagraph(), 0);
3343 // replace the paragraphs with the undo informations
3345 LyXParagraph * tmppar3 = undo->par;
3346 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3347 LyXParagraph * tmppar4 = tmppar3;
3349 while (tmppar4->next)
3350 tmppar4 = tmppar4->next;
3351 } // get last undo par
3353 // now remove the old text if there is any
3354 if (before != behind || (!behind && !before)){
3356 tmppar5 = before->next;
3358 tmppar5 = OwnerParagraph();
3360 while (tmppar5 && tmppar5 != behind){
3362 tmppar5 = tmppar5->next;
3363 // a memory optimization for edit: Only layout information
3364 // is stored in the undo. So restore the text informations.
3365 if (undo->kind == Undo::EDIT) {
3366 tmppar2->setContentsFromPar(tmppar);
3367 tmppar->clearContents();
3368 tmppar2 = tmppar2->next;
3373 // put the new stuff in the list if there is one
3376 before->next = tmppar3;
3378 OwnerParagraph(tmppar3);
3379 tmppar3->previous = before;
3382 OwnerParagraph(behind);
3385 tmppar4->next = behind;
3387 behind->previous = tmppar4;
3391 // Set the cursor for redoing
3393 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3395 // check wether before points to a closed float and open it if necessary
3396 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3397 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3399 while (tmppar4->previous &&
3400 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3401 tmppar4 = tmppar4->previous;
3402 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3403 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3404 tmppar4 = tmppar4->next;
3411 // open a cosed footnote at the end if necessary
3412 if (behind && behind->previous &&
3413 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3414 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3415 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3416 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3417 behind = behind->next;
3422 // calculate the endpar for redoing the paragraphs.
3425 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3427 endpar = behind->LastPhysicalPar()->Next();
3430 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3435 tmppar = GetParFromID(undo->number_of_cursor_par);
3436 RedoParagraphs(bview, cursor, endpar);
3438 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3439 UpdateCounters(bview, cursor.row());
3449 void LyXText::FinishUndo()
3453 // makes sure the next operation will be stored
3454 undo_finished = true;
3458 void LyXText::FreezeUndo()
3462 // this is dangerous and for internal use only
3467 void LyXText::UnFreezeUndo()
3471 // this is dangerous and for internal use only
3472 undo_frozen = false;
3476 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3477 LyXParagraph const * before,
3478 LyXParagraph const * behind) const
3483 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3484 buf->redostack.clear();
3488 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3489 LyXParagraph const * before, LyXParagraph const * behind)
3493 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3497 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3498 LyXParagraph const * before,
3499 LyXParagraph const * behind) const
3504 int before_number = -1;
3505 int behind_number = -1;
3507 before_number = before->id();
3509 behind_number = behind->id();
3510 // Undo::EDIT and Undo::FINISH are
3511 // always finished. (no overlapping there)
3512 // overlapping only with insert and delete inside one paragraph:
3513 // Nobody wants all removed character
3514 // appear one by one when undoing.
3515 // EDIT is special since only layout information, not the
3516 // contents of a paragaph are stored.
3517 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3518 // check wether storing is needed
3519 if (!buf->undostack.empty() &&
3520 buf->undostack.top()->kind == kind &&
3521 buf->undostack.top()->number_of_before_par == before_number &&
3522 buf->undostack.top()->number_of_behind_par == behind_number ){
3527 // create a new Undo
3528 LyXParagraph * undopar;
3529 LyXParagraph * tmppar;
3530 LyXParagraph * tmppar2;
3532 LyXParagraph * start = 0;
3533 LyXParagraph * end = 0;
3536 start = before->next;
3538 start = FirstParagraph();
3540 end = behind->previous;
3542 end = FirstParagraph();
3548 && start != end->next
3549 && (before != behind || (!before && !behind))) {
3551 tmppar2 = tmppar->Clone();
3552 tmppar2->id(tmppar->id());
3554 // a memory optimization: Just store the layout information
3556 if (kind == Undo::EDIT){
3557 //tmppar2->text.clear();
3558 tmppar2->clearContents();
3563 while (tmppar != end && tmppar->next) {
3564 tmppar = tmppar->next;
3565 tmppar2->next = tmppar->Clone();
3566 tmppar2->next->id(tmppar->id());
3567 // a memory optimization: Just store the layout
3568 // information when only edit
3569 if (kind == Undo::EDIT){
3570 //tmppar2->next->text.clear();
3571 tmppar2->clearContents();
3573 tmppar2->next->previous = tmppar2;
3574 tmppar2 = tmppar2->next;
3578 undopar = 0; // nothing to replace (undo of delete maybe)
3580 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3581 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3583 Undo * undo = new Undo(kind,
3584 before_number, behind_number,
3585 cursor_par, cursor_pos,
3588 undo_finished = false;
3593 void LyXText::SetCursorParUndo(Buffer * buf)
3597 SetUndo(buf, Undo::FINISH,
3598 cursor.par()->ParFromPos(cursor.pos())->previous,
3599 cursor.par()->ParFromPos(cursor.pos())->next);
3604 void LyXText::RemoveTableRow(LyXCursor & cur) const
3610 // move to the previous row
3611 int cell_act = NumberOfCell(cur.par(), cur.pos());
3614 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3615 cur.pos(cur.pos() - 1);
3617 !cur.par()->table->IsFirstCell(cell_act)) {
3618 cur.pos(cur.pos() - 1);
3619 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
3620 cur.pos(cur.pos() - 1);
3624 // now we have to pay attention if the actual table is the
3625 // main row of TableContRows and if yes to delete all of them
3630 // delete up to the next row
3631 while (cur.pos() < cur.par()->Last() &&
3633 || !cur.par()->table->IsFirstCell(cell_act))) {
3634 while (cur.pos() < cur.par()->Last() &&
3635 !cur.par()->IsNewline(cur.pos()))
3636 cur.par()->Erase(cur.pos());
3639 if (cur.pos() < cur.par()->Last())
3640 cur.par()->Erase(cur.pos());
3642 if (cur.pos() && cur.pos() == cur.par()->Last()) {
3643 cur.pos(cur.pos() - 1);
3644 cur.par()->Erase(cur.pos()); // no newline at very end!
3646 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
3647 !cur.par()->table->IsContRow(cell_org) &&
3648 cur.par()->table->IsContRow(cell));
3649 cur.par()->table->DeleteRow(cell_org);
3656 bool LyXText::IsEmptyTableCell() const
3658 LyXParagraph::size_type pos = cursor.pos() - 1;
3659 while (pos >= 0 && pos < cursor.par()->Last()
3660 && !cursor.par()->IsNewline(pos))
3662 return cursor.par()->IsNewline(pos + 1);
3667 void LyXText::toggleAppendix(BufferView * bview)
3669 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3670 bool start = !par->start_of_appendix;
3672 // ensure that we have only one start_of_appendix in this document
3673 LyXParagraph * tmp = FirstParagraph();
3674 for (; tmp; tmp = tmp->next)
3675 tmp->start_of_appendix = 0;
3676 par->start_of_appendix = start;
3678 // we can set the refreshing parameters now
3679 status = LyXText::NEED_MORE_REFRESH;
3681 refresh_row = 0; // not needed for full update
3682 UpdateCounters(bview, 0);
3683 SetCursor(bview, cursor.par(), cursor.pos());
3687 LyXParagraph * LyXText::OwnerParagraph() const
3690 return inset_owner->par;
3692 return bv_owner->buffer()->paragraph;
3696 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3699 inset_owner->par = p;
3701 bv_owner->buffer()->paragraph = p;