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"
22 #include "lyxparagraph.h"
23 #include "insets/inseterror.h"
24 #include "insets/insetbib.h"
25 #include "insets/insetspecialchar.h"
26 #include "insets/insettext.h"
27 #include "insets/insetfloat.h"
30 #include "support/textutils.h"
33 #include "bufferparams.h"
34 #include "lyx_gui_misc.h"
36 #include "BufferView.h"
38 #include "CutAndPaste.h"
43 #include "FloatList.h"
53 LyXText::LyXText(BufferView * bv)
61 LyXText::LyXText(InsetText * inset)
71 the_locking_inset = 0;
79 status = LyXText::UNCHANGED;
80 // set cursor at the very top position
81 selection = true; /* these setting is necessary
82 because of the delete-empty-
83 paragraph mechanism in
86 LyXParagraph * par = OwnerParagraph();
87 current_font = GetFont(bv_owner->buffer(), par, 0);
89 InsertParagraph(bv_owner, par, lastrow);
92 SetCursor(bv_owner, firstrow->par(), 0);
94 current_font = LyXFont(LyXFont::ALL_SANE);
100 // no rebreak necessary
103 undo_finished = true;
106 // Default layouttype for copy environment type
110 // Dump all rowinformation:
111 Row * tmprow = firstrow;
112 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
114 lyxerr << tmprow->baseline() << '\t'
115 << tmprow->par << '\t'
116 << tmprow->pos() << '\t'
117 << tmprow->height << '\t'
118 << tmprow->ascent_of_text << '\t'
119 << tmprow->fill << '\n';
120 tmprow = tmprow->next();
127 void LyXText::init(BufferView * bview)
132 LyXParagraph * par = OwnerParagraph();
133 current_font = GetFont(bview->buffer(), par, 0);
135 InsertParagraph(bview, par, lastrow);
138 SetCursorIntern(bview, firstrow->par(), 0);
141 // Dump all rowinformation:
142 Row * tmprow = firstrow;
143 lyxerr << "Width = " << width << endl;
144 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
146 lyxerr << tmprow->baseline() << '\t'
147 << tmprow->par() << '\t'
148 << tmprow->pos() << '\t'
149 << tmprow->height() << '\t'
150 << tmprow->ascent_of_text() << '\t'
151 << tmprow->fill() << '\n';
152 tmprow = tmprow->next();
160 // Delete all rows, this does not touch the paragraphs!
161 Row * tmprow = firstrow;
163 tmprow = firstrow->next();
170 // Gets the fully instantiated font at a given position in a paragraph
171 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
172 // The difference is that this one is used for displaying, and thus we
173 // are allowed to make cosmetic improvements. For instance make footnotes
175 // If position is -1, we get the layout font of the paragraph.
176 // If position is -2, we get the font of the manual label of the paragraph.
177 LyXFont const LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
178 LyXParagraph::size_type pos) const
180 LyXLayout const & layout =
181 textclasslist.Style(buf->params.textclass, par->GetLayout());
183 char par_depth = par->GetDepth();
184 // We specialize the 95% common case:
187 par->footnoteflag == LyXParagraph::NO_FOOTNOTE &&
192 if (layout.labeltype == LABEL_MANUAL
193 && pos < BeginningOfMainBody(buf, par)) {
195 LyXFont f = par->GetFontSettings(buf->params,
197 return f.realize(layout.reslabelfont);
199 LyXFont f = par->GetFontSettings(buf->params, pos);
200 return f.realize(layout.resfont);
205 // process layoutfont for pos == -1 and labelfont for pos < -1
207 return layout.resfont;
209 return layout.reslabelfont;
213 // The uncommon case need not be optimized as much
215 LyXFont layoutfont, tmpfont;
219 if (pos < BeginningOfMainBody(buf, par)) {
221 layoutfont = layout.labelfont;
224 layoutfont = layout.font;
226 tmpfont = par->GetFontSettings(buf->params, pos);
227 tmpfont.realize(layoutfont);
230 // process layoutfont for pos == -1 and labelfont for pos < -1
232 tmpfont = layout.font;
234 tmpfont = layout.labelfont;
237 // Resolve against environment font information
238 while (par && par_depth && !tmpfont.resolved()) {
239 par = par->DepthHook(par_depth - 1);
241 tmpfont.realize(textclasslist.
242 Style(buf->params.textclass,
243 par->GetLayout()).font);
244 par_depth = par->GetDepth();
248 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
251 // Cosmetic improvement: If this is an open footnote, make the font
253 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
254 && par->footnotekind == LyXParagraph::FOOTNOTE) {
262 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
263 LyXParagraph::size_type pos,
267 // Let the insets convert their font
268 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
269 if (par->GetInset(pos))
270 font = par->GetInset(pos)->ConvertFont(font);
273 LyXLayout const & layout =
274 textclasslist.Style(buf->params.textclass,
277 // Get concrete layout font to reduce against
280 if (pos < BeginningOfMainBody(buf, par))
281 layoutfont = layout.labelfont;
283 layoutfont = layout.font;
285 // Realize against environment font information
286 if (par->GetDepth()){
287 LyXParagraph * tp = par;
288 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
289 tp = tp->DepthHook(tp->GetDepth()-1);
291 layoutfont.realize(textclasslist.
292 Style(buf->params.textclass,
293 tp->GetLayout()).font);
297 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
300 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
301 && par->footnotekind == LyXParagraph::FOOTNOTE) {
302 layoutfont.decSize();
305 // Now, reduce font against full layout font
306 font.reduce(layoutfont);
308 par->SetFont(pos, font);
312 /* inserts a new row behind the specified row, increments
313 * the touched counters */
314 void LyXText::InsertRow(Row * row, LyXParagraph * par,
315 LyXParagraph::size_type pos) const
317 Row * tmprow = new Row;
320 tmprow->next(firstrow);
323 tmprow->previous(row);
324 tmprow->next(row->next());
329 tmprow->next()->previous(tmprow);
331 if (tmprow->previous())
332 tmprow->previous()->next(tmprow);
340 ++number_of_rows; // one more row
344 // removes the row and reset the touched counters
345 void LyXText::RemoveRow(Row * row) const
347 /* this must not happen before the currentrow for clear reasons.
348 so the trick is just to set the current row onto the previous
351 GetRow(row->par(), row->pos(), unused_y);
354 row->next()->previous(row->previous());
355 if (!row->previous()) {
356 firstrow = row->next();
358 row->previous()->next(row->next());
361 lastrow = row->previous();
363 height -= row->height(); // the text becomes smaller
366 --number_of_rows; // one row less
370 // remove all following rows of the paragraph of the specified row.
371 void LyXText::RemoveParagraph(Row * row) const
373 LyXParagraph * tmppar = row->par();
377 while (row && row->par() == tmppar) {
378 tmprow = row->next();
385 // insert the specified paragraph behind the specified row
386 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
389 InsertRow(row, par, 0); /* insert a new row, starting
392 SetCounter(bview->buffer(), par); // set the counters
394 // and now append the whole paragraph behind the new row
397 AppendParagraph(bview, firstrow);
399 row->next()->height(0);
400 AppendParagraph(bview, row->next());
406 void LyXText::ToggleFootnote(BufferView * bview)
408 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
410 && par->next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
412 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
414 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
415 CloseFootnote(bview);
422 void LyXText::OpenStuff(BufferView * bview)
424 if (cursor.pos() == 0 && cursor.par()->bibkey){
425 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
426 } else if (cursor.pos() < cursor.par()->Last()
427 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
428 && cursor.par()->GetInset(cursor.pos())->Editable()) {
429 bview->owner()->getMiniBuffer()
430 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
431 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
432 SetCursorParUndo(bview->buffer());
433 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
437 ToggleFootnote(bview);
445 void LyXText::CloseFootnote(BufferView * bview)
447 LyXParagraph * tmppar;
448 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
450 // if the cursor is not in an open footnote, or
451 // there is no open footnote in this paragraph, just return.
452 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
455 par->next_->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
456 bview->owner()->getMiniBuffer()
457 ->Set(_("Nothing to do"));
461 // ok, move the cursor right before the footnote
462 // just a little faster than using CursorRight()
464 cursor.par()->ParFromPos(cursor.pos()) != par;) {
465 cursor.pos(cursor.pos() + 1);
468 // now the cursor is at the beginning of the physical par
469 SetCursor(bview, cursor.par(),
471 cursor.par()->ParFromPos(cursor.pos())->size());
473 /* we are in a footnote, so let us move at the beginning */
474 /* this is just faster than using just CursorLeft() */
476 tmppar = cursor.par();
477 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
478 // just a little bit faster than movin the cursor
479 tmppar = tmppar->previous();
481 SetCursor(bview, tmppar, tmppar->Last());
484 // the cursor must be exactly before the footnote
485 par = cursor.par()->ParFromPos(cursor.pos());
487 status = LyXText::NEED_MORE_REFRESH;
488 refresh_row = cursor.row();
489 refresh_y = cursor.y() - cursor.row()->baseline();
491 tmppar = cursor.par();
492 LyXParagraph * endpar = par->NextAfterFootnote()->next();
493 Row * row = cursor.row();
495 tmppar->CloseFootnote(cursor.pos());
497 while (tmppar != endpar) {
498 RemoveRow(row->next());
500 tmppar = row->next()->par();
505 AppendParagraph(bview, cursor.row());
507 SetCursor(bview, cursor.par(), cursor.pos());
511 if (cursor.row()->next())
512 SetHeightOfRow(bview, cursor.row()->next());
517 /* used in setlayout */
518 // Asger is not sure we want to do this...
519 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
523 LyXLayout const & layout =
524 textclasslist.Style(buf->params.textclass, par->GetLayout());
526 LyXFont layoutfont, tmpfont;
527 for (LyXParagraph::size_type pos = 0;
529 pos < par->Last(); ++pos) {
531 pos < par->size(); ++pos) {
533 if (pos < BeginningOfMainBody(buf, par))
534 layoutfont = layout.labelfont;
536 layoutfont = layout.font;
538 tmpfont = par->GetFontSettings(buf->params, pos);
539 tmpfont.reduce(layoutfont);
540 par->SetFont(pos, tmpfont);
546 LyXParagraph * LyXText::SetLayout(BufferView * bview,
547 LyXCursor & cur, LyXCursor & sstart_cur,
548 LyXCursor & send_cur,
549 LyXTextClass::size_type layout)
551 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->next();
552 LyXParagraph * undoendpar = endpar;
554 if (endpar && endpar->GetDepth()) {
555 while (endpar && endpar->GetDepth()) {
556 endpar = endpar->LastPhysicalPar()->next();
560 endpar = endpar->next(); // because of parindents etc.
563 SetUndo(bview->buffer(), Undo::EDIT,
564 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous_,
567 /* ok we have a selection. This is always between sstart_cur
568 * and sel_end cursor */
571 LyXLayout const & lyxlayout =
572 textclasslist.Style(bview->buffer()->params.textclass, layout);
574 while (cur.par() != send_cur.par()) {
575 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
576 cur.par()->SetLayout(bview->buffer()->params, layout);
577 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
578 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
579 fppar->params.spaceTop(lyxlayout.fill_top ?
580 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
581 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
582 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
583 if (lyxlayout.margintype == MARGIN_MANUAL)
584 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
585 if (lyxlayout.labeltype != LABEL_BIBLIO
587 delete fppar->bibkey;
591 cur.par(cur.par()->next());
593 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
594 cur.par()->SetLayout(bview->buffer()->params, layout);
595 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
596 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
597 fppar->params.spaceTop(lyxlayout.fill_top ?
598 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
599 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
600 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
601 if (lyxlayout.margintype == MARGIN_MANUAL)
602 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
603 if (lyxlayout.labeltype != LABEL_BIBLIO
605 delete fppar->bibkey;
612 LyXParagraph * LyXText::SetLayout(BufferView * bview,
613 LyXCursor & cur, LyXCursor & sstart_cur,
614 LyXCursor & send_cur,
615 LyXTextClass::size_type layout)
617 LyXParagraph * endpar = send_cur.par()->next();
618 LyXParagraph * undoendpar = endpar;
620 if (endpar && endpar->GetDepth()) {
621 while (endpar && endpar->GetDepth()) {
622 endpar = endpar->next();
626 endpar = endpar->next(); // because of parindents etc.
629 SetUndo(bview->buffer(), Undo::EDIT,
630 sstart_cur.par()->previous(),
633 /* ok we have a selection. This is always between sstart_cur
634 * and sel_end cursor */
637 LyXLayout const & lyxlayout =
638 textclasslist.Style(bview->buffer()->params.textclass, layout);
640 while (cur.par() != send_cur.par()) {
641 cur.par()->SetLayout(layout);
642 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
643 LyXParagraph * fppar = cur.par();
644 fppar->params.spaceTop(lyxlayout.fill_top ?
645 VSpace(VSpace::VFILL)
646 : VSpace(VSpace::NONE));
647 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
648 VSpace(VSpace::VFILL)
649 : VSpace(VSpace::NONE));
650 if (lyxlayout.margintype == MARGIN_MANUAL)
651 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
652 if (lyxlayout.labeltype != LABEL_BIBLIO
654 delete fppar->bibkey;
657 cur.par(cur.par()->next());
659 cur.par()->SetLayout(layout);
660 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
661 LyXParagraph * fppar = cur.par();
662 fppar->params.spaceTop(lyxlayout.fill_top ?
663 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
664 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
665 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
666 if (lyxlayout.margintype == MARGIN_MANUAL)
667 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
668 if (lyxlayout.labeltype != LABEL_BIBLIO
670 delete fppar->bibkey;
678 // set layout over selection and make a total rebreak of those paragraphs
679 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
681 LyXCursor tmpcursor = cursor; /* store the current cursor */
683 // if there is no selection just set the layout
684 // of the current paragraph */
686 sel_start_cursor = cursor; // dummy selection
687 sel_end_cursor = cursor;
690 endpar = SetLayout(bview, cursor, sel_start_cursor,
691 sel_end_cursor, layout);
692 RedoParagraphs(bview, sel_start_cursor, endpar);
694 // we have to reset the selection, because the
695 // geometry could have changed
696 SetCursor(bview, sel_start_cursor.par(),
697 sel_start_cursor.pos(), false);
699 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
701 UpdateCounters(bview, cursor.row());
702 ClearSelection(bview);
704 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
708 // increment depth over selection and
709 // make a total rebreak of those paragraphs
710 void LyXText::IncDepth(BufferView * bview)
712 // If there is no selection, just use the current paragraph
714 sel_start_cursor = cursor; // dummy selection
715 sel_end_cursor = cursor;
718 // We end at the next paragraph with depth 0
719 LyXParagraph * endpar =
721 sel_end_cursor.par()->LastPhysicalPar()->next();
723 sel_end_cursor.par()->next();
725 LyXParagraph * undoendpar = endpar;
727 if (endpar && endpar->GetDepth()) {
728 while (endpar && endpar->GetDepth()) {
730 endpar = endpar->LastPhysicalPar()->next();
732 endpar = endpar->next();
738 endpar = endpar->next(); // because of parindents etc.
741 SetUndo(bview->buffer(), Undo::EDIT,
744 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
746 sel_start_cursor.par()->previous(),
750 LyXCursor tmpcursor = cursor; // store the current cursor
752 // ok we have a selection. This is always between sel_start_cursor
753 // and sel_end cursor
754 cursor = sel_start_cursor;
756 bool anything_changed = false;
759 // NOTE: you can't change the depth of a bibliography entry
762 cursor.par()->footnoteflag ==
763 sel_start_cursor.par()->footnoteflag &&
765 textclasslist.Style(bview->buffer()->params.textclass,
766 cursor.par()->GetLayout()
767 ).labeltype != LABEL_BIBLIO) {
768 LyXParagraph * prev =
770 cursor.par()->FirstPhysicalPar()->previous();
772 cursor.par()->previous();
775 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
776 || (prev->GetDepth() == cursor.par()->GetDepth()
777 && textclasslist.Style(bview->buffer()->params.textclass,
778 prev->GetLayout()).isEnvironment()))) {
780 cursor.par()->FirstPhysicalPar()->params.depth(cursor.par()->FirstPhysicalPar()->params.depth() + 1);
782 cursor.par()->params.depth(cursor.par()->params.depth() + 1);
784 anything_changed = true;
787 if (cursor.par() == sel_end_cursor.par())
789 cursor.par(cursor.par()->next());
792 // if nothing changed set all depth to 0
793 if (!anything_changed) {
794 cursor = sel_start_cursor;
795 while (cursor.par() != sel_end_cursor.par()) {
797 cursor.par()->FirstPhysicalPar()->params.depth(0);
799 cursor.par()->params.depth(0);
801 cursor.par(cursor.par()->next());
804 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
805 cursor.par()->FirstPhysicalPar()->params.depth(0);
807 cursor.par()->params.depth(0);
811 RedoParagraphs(bview, sel_start_cursor, endpar);
813 // we have to reset the selection, because the
814 // geometry could have changed
815 SetCursor(bview, sel_start_cursor.par(),
816 sel_start_cursor.pos());
818 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
819 UpdateCounters(bview, cursor.row());
820 ClearSelection(bview);
822 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
826 // decrement depth over selection and
827 // make a total rebreak of those paragraphs
828 void LyXText::DecDepth(BufferView * bview)
830 // if there is no selection just set the layout
831 // of the current paragraph
833 sel_start_cursor = cursor; // dummy selection
834 sel_end_cursor = cursor;
837 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
839 LyXParagraph * endpar = sel_end_cursor.par()->next();
841 LyXParagraph * undoendpar = endpar;
843 if (endpar && endpar->GetDepth()) {
844 while (endpar && endpar->GetDepth()) {
846 endpar = endpar->LastPhysicalPar()->next();
848 endpar = endpar->next();
854 endpar = endpar->next(); // because of parindents etc.
857 SetUndo(bview->buffer(), Undo::EDIT,
860 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
862 sel_start_cursor.par()->previous(),
866 LyXCursor tmpcursor = cursor; // store the current cursor
868 // ok we have a selection. This is always between sel_start_cursor
869 // and sel_end cursor
870 cursor = sel_start_cursor;
874 if (cursor.par()->footnoteflag ==
875 sel_start_cursor.par()->footnoteflag) {
876 if (cursor.par()->FirstPhysicalPar()->params.depth())
877 cursor.par()->FirstPhysicalPar()->params.depth(cursor.par()->FirstPhysicalPar()->params.depth() - 1);
880 if (cursor.par()->params.depth())
881 cursor.par()->params.depth(cursor.par()->params.depth() - 1);
883 if (cursor.par() == sel_end_cursor.par())
885 cursor.par(cursor.par()->next());
888 RedoParagraphs(bview, sel_start_cursor, endpar);
890 // we have to reset the selection, because the
891 // geometry could have changed
892 SetCursor(bview, sel_start_cursor.par(),
893 sel_start_cursor.pos());
895 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
896 UpdateCounters(bview, cursor.row());
897 ClearSelection(bview);
899 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
903 // set font over selection and make a total rebreak of those paragraphs
904 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
906 // if there is no selection just set the current_font
908 // Determine basis font
910 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
912 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
914 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
915 // Update current font
916 real_current_font.update(font,
917 bview->buffer()->params.language,
920 // Reduce to implicit settings
921 current_font = real_current_font;
922 current_font.reduce(layoutfont);
923 // And resolve it completely
924 real_current_font.realize(layoutfont);
928 LyXCursor tmpcursor = cursor; // store the current cursor
930 // ok we have a selection. This is always between sel_start_cursor
931 // and sel_end cursor
933 SetUndo(bview->buffer(), Undo::EDIT,
935 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous_,
936 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next_
938 sel_start_cursor.par()->previous(),
939 sel_end_cursor.par()->next()
942 cursor = sel_start_cursor;
943 while (cursor.par() != sel_end_cursor.par() ||
946 cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag &&
948 cursor.pos() < sel_end_cursor.pos()))
951 if (cursor.pos() < cursor.par()->Last()
952 && cursor.par()->footnoteflag
953 == sel_start_cursor.par()->footnoteflag
955 if (cursor.pos() < cursor.par()->size()
958 // an open footnote should behave
960 LyXFont newfont = GetFont(bview->buffer(),
961 cursor.par(), cursor.pos());
963 bview->buffer()->params.language,
965 SetCharFont(bview->buffer(),
966 cursor.par(), cursor.pos(), newfont);
967 cursor.pos(cursor.pos() + 1);
970 cursor.par(cursor.par()->next());
974 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->next());
976 // we have to reset the selection, because the
977 // geometry could have changed
978 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
980 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
981 ClearSelection(bview);
983 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
984 tmpcursor.boundary());
988 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
990 Row * tmprow = cur.row();
991 int y = cur.y() - tmprow->baseline();
993 SetHeightOfRow(bview, tmprow);
995 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
997 LyXParagraph * first_phys_par = tmprow->par();
999 // find the first row of the paragraph
1000 if (first_phys_par != tmprow->par())
1001 while (tmprow->previous()
1002 && tmprow->previous()->par() != first_phys_par) {
1003 tmprow = tmprow->previous();
1004 y -= tmprow->height();
1005 SetHeightOfRow(bview, tmprow);
1007 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
1008 tmprow = tmprow->previous();
1009 y -= tmprow->height();
1010 SetHeightOfRow(bview, tmprow);
1013 // we can set the refreshing parameters now
1014 status = LyXText::NEED_MORE_REFRESH;
1016 refresh_row = tmprow;
1017 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
1021 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
1023 Row * tmprow = cur.row();
1025 int y = cur.y() - tmprow->baseline();
1026 SetHeightOfRow(bview, tmprow);
1028 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
1030 LyXParagraph * first_phys_par = tmprow->par();
1032 // find the first row of the paragraph
1033 if (first_phys_par != tmprow->par())
1034 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
1035 tmprow = tmprow->previous();
1036 y -= tmprow->height();
1038 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
1039 tmprow = tmprow->previous();
1040 y -= tmprow->height();
1043 // we can set the refreshing parameters now
1044 if (status == LyXText::UNCHANGED || y < refresh_y) {
1046 refresh_row = tmprow;
1048 status = LyXText::NEED_MORE_REFRESH;
1049 SetCursor(bview, cur.par(), cur.pos());
1053 /* deletes and inserts again all paragaphs between the cursor
1054 * and the specified par
1055 * This function is needed after SetLayout and SetFont etc. */
1056 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
1057 LyXParagraph const * endpar) const
1060 LyXParagraph * tmppar = 0, * first_phys_par = 0;
1062 Row * tmprow = cur.row();
1064 int y = cur.y() - tmprow->baseline();
1066 if (!tmprow->previous()){
1067 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
1070 first_phys_par = tmprow->par()->FirstPhysicalPar();
1072 first_phys_par = tmprow->par();
1074 // find the first row of the paragraph
1075 if (first_phys_par != tmprow->par())
1076 while (tmprow->previous() &&
1077 (tmprow->previous()->par() != first_phys_par)) {
1078 tmprow = tmprow->previous();
1079 y -= tmprow->height();
1081 while (tmprow->previous()
1082 && tmprow->previous()->par() == first_phys_par) {
1083 tmprow = tmprow->previous();
1084 y -= tmprow->height();
1088 // we can set the refreshing parameters now
1089 status = LyXText::NEED_MORE_REFRESH;
1091 refresh_row = tmprow->previous(); /* the real refresh row will
1092 be deleted, so I store
1093 the previous here */
1096 tmppar = tmprow->next()->par();
1099 while (tmppar != endpar) {
1100 RemoveRow(tmprow->next());
1102 tmppar = tmprow->next()->par();
1107 // remove the first one
1108 tmprow2 = tmprow; /* this is because tmprow->previous()
1110 tmprow = tmprow->previous();
1113 tmppar = first_phys_par;
1117 InsertParagraph(bview, tmppar, tmprow);
1120 while (tmprow->next() && tmprow->next()->par() == tmppar)
1121 tmprow = tmprow->next();
1122 tmppar = tmppar->next();
1124 } while (tmppar != endpar);
1126 // this is because of layout changes
1128 refresh_y -= refresh_row->height();
1129 SetHeightOfRow(bview, refresh_row);
1131 refresh_row = firstrow;
1133 SetHeightOfRow(bview, refresh_row);
1136 if (tmprow && tmprow->next())
1137 SetHeightOfRow(bview, tmprow->next());
1141 bool LyXText::FullRebreak(BufferView * bview)
1147 if (need_break_row) {
1148 BreakAgain(bview, need_break_row);
1156 /* important for the screen */
1159 /* the cursor set functions have a special mechanism. When they
1160 * realize, that you left an empty paragraph, they will delete it.
1161 * They also delete the corresponding row */
1163 // need the selection cursor:
1164 void LyXText::SetSelection(BufferView * bview)
1166 const bool lsel = selection;
1169 last_sel_cursor = sel_cursor;
1170 sel_start_cursor = sel_cursor;
1171 sel_end_cursor = sel_cursor;
1176 // first the toggling area
1177 if (cursor.y() < last_sel_cursor.y()
1178 || (cursor.y() == last_sel_cursor.y()
1179 && cursor.x() < last_sel_cursor.x())) {
1180 toggle_end_cursor = last_sel_cursor;
1181 toggle_cursor = cursor;
1183 toggle_end_cursor = cursor;
1184 toggle_cursor = last_sel_cursor;
1187 last_sel_cursor = cursor;
1189 // and now the whole selection
1191 if (sel_cursor.par() == cursor.par())
1192 if (sel_cursor.pos() < cursor.pos()) {
1193 sel_end_cursor = cursor;
1194 sel_start_cursor = sel_cursor;
1196 sel_end_cursor = sel_cursor;
1197 sel_start_cursor = cursor;
1199 else if (sel_cursor.y() < cursor.y() ||
1200 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1201 sel_end_cursor = cursor;
1202 sel_start_cursor = sel_cursor;
1205 sel_end_cursor = sel_cursor;
1206 sel_start_cursor = cursor;
1209 // a selection with no contents is not a selection
1210 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1211 sel_start_cursor.pos() == sel_end_cursor.pos())
1214 if (inset_owner && (selection || lsel))
1215 inset_owner->SetUpdateStatus(bview, InsetText::SELECTION);
1219 string const LyXText::selectionAsString(Buffer const * buffer) const
1221 if (!selection) return string();
1224 // Special handling if the whole selection is within one paragraph
1225 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1226 result += sel_start_cursor.par()->String(buffer,
1227 sel_start_cursor.pos(),
1228 sel_end_cursor.pos());
1232 // The selection spans more than one paragraph
1234 // First paragraph in selection
1236 result += sel_start_cursor.par()->String(buffer,
1237 sel_start_cursor.pos(),
1238 sel_start_cursor.par()->Last())
1241 result += sel_start_cursor.par()->String(buffer,
1242 sel_start_cursor.pos(),
1243 sel_start_cursor.par()->size())
1247 // The paragraphs in between (if any)
1248 LyXCursor tmpcur(sel_start_cursor);
1249 tmpcur.par(tmpcur.par()->next());
1250 while (tmpcur.par() != sel_end_cursor.par()) {
1252 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1254 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->size()) + "\n\n";
1256 tmpcur.par(tmpcur.par()->next()); // Or NextAfterFootnote??
1259 // Last paragraph in selection
1260 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1266 void LyXText::ClearSelection(BufferView * /*bview*/) const
1273 void LyXText::CursorHome(BufferView * bview) const
1275 SetCursor(bview, cursor.par(), cursor.row()->pos());
1279 void LyXText::CursorEnd(BufferView * bview) const
1281 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1282 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1285 if (cursor.par()->Last() &&
1287 if (cursor.par()->size() &&
1289 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1290 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1291 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1293 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1298 void LyXText::CursorTop(BufferView * bview) const
1300 while (cursor.par()->previous())
1301 cursor.par(cursor.par()->previous());
1302 SetCursor(bview, cursor.par(), 0);
1306 void LyXText::CursorBottom(BufferView * bview) const
1308 while (cursor.par()->next())
1309 cursor.par(cursor.par()->next());
1311 SetCursor(bview, cursor.par(), cursor.par()->Last());
1313 SetCursor(bview, cursor.par(), cursor.par()->size());
1318 void LyXText::ToggleFree(BufferView * bview,
1319 LyXFont const & font, bool toggleall)
1321 // If the mask is completely neutral, tell user
1322 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1323 // Could only happen with user style
1324 bview->owner()->message(_("No font change defined. Use Character under the Layout menu to define font change."));
1328 // Try implicit word selection
1329 // If there is a change in the language the implicit word selection
1331 LyXCursor resetCursor = cursor;
1332 bool implicitSelection = (font.language() == ignore_language
1333 && font.number() == LyXFont::IGNORE)
1334 ? SelectWordWhenUnderCursor(bview) : false;
1337 SetFont(bview, font, toggleall);
1339 /* Implicit selections are cleared afterwards and cursor is set to the
1340 original position. */
1341 if (implicitSelection) {
1342 ClearSelection(bview);
1343 cursor = resetCursor;
1344 SetCursor(bview, cursor.par(), cursor.pos());
1345 sel_cursor = cursor;
1348 inset_owner->SetUpdateStatus(bview, InsetText::CURSOR_PAR);
1352 LyXParagraph::size_type
1353 LyXText::BeginningOfMainBody(Buffer const * buf,
1354 LyXParagraph const * par) const
1356 if (textclasslist.Style(buf->params.textclass,
1357 par->GetLayout()).labeltype != LABEL_MANUAL)
1360 return par->BeginningOfMainBody();
1365 /* if there is a selection, reset every environment you can find
1366 * in the selection, otherwise just the environment you are in */
1367 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1369 LyXParagraph * tmppar, * firsttmppar;
1371 ClearSelection(bview);
1373 /* is is only allowed, if the cursor is IN an open footnote.
1374 * Otherwise it is too dangerous */
1375 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1378 SetUndo(bview->buffer(), Undo::FINISH,
1379 cursor.par()->PreviousBeforeFootnote()->previous_,
1380 cursor.par()->NextAfterFootnote()->next_);
1382 /* ok, move to the beginning of the footnote. */
1383 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1384 cursor.par(cursor.par()->previous());
1386 SetCursor(bview, cursor.par(), cursor.par()->Last());
1387 /* this is just faster than using CursorLeft(); */
1389 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1390 tmppar = firsttmppar;
1391 /* tmppar is now the paragraph right before the footnote */
1393 bool first_footnote_par_is_not_empty = tmppar->next_->size();
1395 while (tmppar->next_
1396 && tmppar->next_->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1397 tmppar = tmppar->next_; /* I use next instead of Next(),
1398 * because there cannot be any
1399 * footnotes in a footnote
1401 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1403 /* remember the captions and empty paragraphs */
1404 if ((textclasslist.Style(bview->buffer()->params.textclass,
1405 tmppar->GetLayout())
1406 .labeltype == LABEL_SENSITIVE)
1408 tmppar->SetLayout(bview->buffer()->params, 0);
1411 // now we will paste the ex-footnote, if the layouts allow it
1412 // first restore the layout of the paragraph right behind
1415 tmppar->next_->MakeSameLayout(cursor.par());
1418 if (!tmppar->GetLayout()
1420 && (!tmppar->next()->Last()
1421 || tmppar->next()->HasSameLayout(tmppar)))) {
1422 if (tmppar->next()->Last()
1423 && tmppar->next()->IsLineSeparator(0))
1424 tmppar->next()->Erase(0);
1425 tmppar->PasteParagraph(bview->buffer()->params);
1428 tmppar = tmppar->next(); /* make sure tmppar cannot be touched
1429 * by the pasting of the beginning */
1431 /* then the beginning */
1432 /* if there is no space between the text and the footnote, so we insert
1434 * (only if the previous par and the footnotepar are not empty!) */
1435 if (!firsttmppar->next_->GetLayout()
1436 || firsttmppar->HasSameLayout(firsttmppar->next_)) {
1437 if (firsttmppar->size()
1438 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1439 && first_footnote_par_is_not_empty) {
1440 firsttmppar->next_->InsertChar(0, ' ');
1442 firsttmppar->PasteParagraph(bview->buffer()->params);
1445 /* now redo the paragaphs */
1446 RedoParagraphs(bview, cursor, tmppar);
1448 SetCursor(bview, cursor.par(), cursor.pos());
1450 /* sometimes it can happen, that there is a counter change */
1451 Row * row = cursor.row();
1452 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1454 UpdateCounters(bview, row);
1457 ClearSelection(bview);
1462 /* the DTP switches for paragraphs. LyX will store them in the
1463 * first physicla paragraph. When a paragraph is broken, the top settings
1464 * rest, the bottom settings are given to the new one. So I can make shure,
1465 * they do not duplicate themself and you cannnot make dirty things with
1468 void LyXText::SetParagraph(BufferView * bview,
1469 bool line_top, bool line_bottom,
1470 bool pagebreak_top, bool pagebreak_bottom,
1471 VSpace const & space_top,
1472 VSpace const & space_bottom,
1474 string labelwidthstring,
1477 LyXCursor tmpcursor = cursor;
1479 sel_start_cursor = cursor;
1480 sel_end_cursor = cursor;
1483 // make sure that the depth behind the selection are restored, too
1485 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
1487 LyXParagraph * endpar = sel_end_cursor.par()->next();
1489 LyXParagraph * undoendpar = endpar;
1491 if (endpar && endpar->GetDepth()) {
1492 while (endpar && endpar->GetDepth()) {
1494 endpar = endpar->LastPhysicalPar()->next();
1496 endpar = endpar->next();
1498 undoendpar = endpar;
1502 endpar = endpar->next(); // because of parindents etc.
1505 SetUndo(bview->buffer(), Undo::EDIT,
1508 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
1510 sel_start_cursor.par()->previous(),
1515 LyXParagraph * tmppar = sel_end_cursor.par();
1517 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->previous()) {
1518 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1520 while (tmppar != sel_start_cursor.par()->previous()) {
1521 SetCursor(bview, tmppar, 0);
1523 status = LyXText::NEED_MORE_REFRESH;
1524 refresh_row = cursor.row();
1525 refresh_y = cursor.y() - cursor.row()->baseline();
1527 if (cursor.par()->footnoteflag ==
1528 sel_start_cursor.par()->footnoteflag) {
1530 cursor.par()->params.lineTop(line_top);
1531 cursor.par()->params.lineBottom(line_bottom);
1532 cursor.par()->params.pagebreakTop(pagebreak_top);
1533 cursor.par()->params.pagebreakBottom(pagebreak_bottom);
1534 cursor.par()->params.spaceTop(space_top);
1535 cursor.par()->params.spaceBottom(space_bottom);
1536 // does the layout allow the new alignment?
1537 if (align == LYX_ALIGN_LAYOUT)
1538 align = textclasslist
1539 .Style(bview->buffer()->params.textclass,
1540 cursor.par()->GetLayout()).align;
1541 if (align & textclasslist
1542 .Style(bview->buffer()->params.textclass,
1543 cursor.par()->GetLayout()).alignpossible) {
1544 if (align == textclasslist
1545 .Style(bview->buffer()->params.textclass,
1546 cursor.par()->GetLayout()).align)
1547 cursor.par()->params.align(LYX_ALIGN_LAYOUT);
1549 cursor.par()->params.align(align);
1551 cursor.par()->SetLabelWidthString(labelwidthstring);
1552 cursor.par()->params.noindent(noindent);
1556 tmppar = cursor.par()->FirstPhysicalPar()->previous();
1558 tmppar = cursor.par()->previous();
1562 RedoParagraphs(bview, sel_start_cursor, endpar);
1564 ClearSelection(bview);
1565 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1566 sel_cursor = cursor;
1567 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1568 SetSelection(bview);
1569 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1571 bview->updateInset(inset_owner, true);
1576 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1577 string const & width,
1578 string const & widthp,
1579 int alignment, bool hfill,
1580 bool start_minipage)
1582 LyXCursor tmpcursor = cursor;
1583 LyXParagraph * tmppar;
1585 sel_start_cursor = cursor;
1586 sel_end_cursor = cursor;
1589 // make sure that the depth behind the selection are restored, too
1591 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
1593 LyXParagraph * endpar = sel_end_cursor.par()->next();
1595 LyXParagraph * undoendpar = endpar;
1597 if (endpar && endpar->GetDepth()) {
1598 while (endpar && endpar->GetDepth()) {
1600 endpar = endpar->LastPhysicalPar()->next();
1602 endpar = endpar->next();
1604 undoendpar = endpar;
1608 endpar = endpar->next(); // because of parindents etc.
1611 SetUndo(bview->buffer(), Undo::EDIT,
1614 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
1616 sel_start_cursor.par()->previous(),
1620 tmppar = sel_end_cursor.par();
1622 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->previous()) {
1623 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1625 while(tmppar != sel_start_cursor.par()->previous()) {
1626 SetCursor(bview, tmppar, 0);
1628 status = LyXText::NEED_MORE_REFRESH;
1629 refresh_row = cursor.row();
1630 refresh_y = cursor.y() - cursor.row()->baseline();
1632 if (cursor.par()->footnoteflag ==
1633 sel_start_cursor.par()->footnoteflag) {
1636 if (type == LyXParagraph::PEXTRA_NONE) {
1637 if (cursor.par()->params.pextraType() != LyXParagraph::PEXTRA_NONE) {
1638 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1639 cursor.par()->params.pextraType(LyXParagraph::PEXTRA_NONE);
1642 cursor.par()->SetPExtraType(bview->buffer()->params,
1643 type, width, widthp);
1644 cursor.par()->params.pextraHfill(hfill);
1645 cursor.par()->params.pextraStartMinipage(start_minipage);
1646 cursor.par()->params.pextraAlignment(alignment);
1651 tmppar = cursor.par()->FirstPhysicalPar()->previous();
1653 tmppar = cursor.par()->previous();
1656 RedoParagraphs(bview, sel_start_cursor, endpar);
1657 ClearSelection(bview);
1658 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1659 sel_cursor = cursor;
1660 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1661 SetSelection(bview);
1662 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1667 char loweralphaCounter(int n)
1669 if (n < 1 || n > 26)
1679 char alphaCounter(int n)
1681 if (n < 1 || n > 26)
1689 char hebrewCounter(int n)
1691 static const char hebrew[22] = {
1692 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1693 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1694 '÷', 'ø', 'ù', 'ú'
1696 if (n < 1 || n > 22)
1704 string const romanCounter(int n)
1706 static char const * roman[20] = {
1707 "i", "ii", "iii", "iv", "v",
1708 "vi", "vii", "viii", "ix", "x",
1709 "xi", "xii", "xiii", "xiv", "xv",
1710 "xvi", "xvii", "xviii", "xix", "xx"
1712 if (n < 1 || n > 20)
1721 // set the counter of a paragraph. This includes the labels
1722 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1725 // this is only relevant for the beginning of paragraph
1726 par = par->FirstPhysicalPar();
1728 LyXLayout const & layout =
1729 textclasslist.Style(buf->params.textclass,
1732 LyXTextClass const & textclass =
1733 textclasslist.TextClass(buf->params.textclass);
1735 /* copy the prev-counters to this one, unless this is the start of a
1736 footnote or of a bibliography or the very first paragraph */
1739 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1740 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1741 && par->footnotekind == LyXParagraph::FOOTNOTE)
1743 && !(textclasslist.Style(buf->params.textclass,
1744 par->previous()->GetLayout()
1745 ).labeltype != LABEL_BIBLIO
1746 && layout.labeltype == LABEL_BIBLIO)) {
1747 for (int i = 0; i < 10; ++i) {
1748 par->setCounter(i, par->previous()->GetFirstCounter(i));
1751 par->params.appendix(par->previous()->FirstPhysicalPar()->params.appendix());
1753 par->params.appendix(par->previous()->params.appendix());
1755 if (!par->params.appendix() && par->params.startOfAppendix()) {
1756 par->params.appendix(true);
1757 for (int i = 0; i < 10; ++i) {
1758 par->setCounter(i, 0);
1762 par->enumdepth = par->previous()->FirstPhysicalPar()->enumdepth;
1763 par->itemdepth = par->previous()->FirstPhysicalPar()->itemdepth;
1765 par->enumdepth = par->previous()->enumdepth;
1766 par->itemdepth = par->previous()->itemdepth;
1769 for (int i = 0; i < 10; ++i) {
1770 par->setCounter(i, 0);
1772 par->params.appendix(par->params.startOfAppendix());
1778 // if this is an open marginnote and this is the first
1779 // entry in the marginnote and the enclosing
1780 // environment is an enum/item then correct for the
1781 // LaTeX behaviour (ARRae)
1782 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1783 && par->footnotekind == LyXParagraph::MARGIN
1785 && par->previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1786 && (par->PreviousBeforeFootnote()
1787 && textclasslist.Style(buf->params.textclass,
1788 par->PreviousBeforeFootnote()->GetLayout()
1789 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1790 // Any itemize or enumerate environment in a marginnote
1791 // that is embedded in an itemize or enumerate
1792 // paragraph is seen by LaTeX as being at a deeper
1793 // level within that enclosing itemization/enumeration
1794 // even if there is a "standard" layout at the start of
1800 /* Maybe we have to increment the enumeration depth.
1801 * BUT, enumeration in a footnote is considered in isolation from its
1802 * surrounding paragraph so don't increment if this is the
1803 * first line of the footnote
1804 * AND, bibliographies can't have their depth changed ie. they
1805 * are always of depth 0
1808 && par->previous()->GetDepth() < par->GetDepth()
1809 && textclasslist.Style(buf->params.textclass,
1810 par->previous()->GetLayout()
1811 ).labeltype == LABEL_COUNTER_ENUMI
1812 && par->enumdepth < 3
1814 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1815 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1816 && par->footnotekind == LyXParagraph::FOOTNOTE)
1818 && layout.labeltype != LABEL_BIBLIO) {
1822 /* Maybe we have to decrement the enumeration depth, see note above */
1824 && par->previous()->GetDepth() > par->GetDepth()
1826 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1827 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1828 && par->footnotekind == LyXParagraph::FOOTNOTE)
1830 && layout.labeltype != LABEL_BIBLIO) {
1831 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1832 par->setCounter(6 + par->enumdepth,
1833 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1834 /* reset the counters.
1835 * A depth change is like a breaking layout
1837 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1838 par->setCounter(i, 0);
1841 if (!par->params.labelString().empty()) {
1842 par->params.labelString(string());
1845 if (layout.margintype == MARGIN_MANUAL) {
1846 if (par->params.labelWidthString().empty()) {
1847 par->SetLabelWidthString(layout.labelstring());
1850 par->SetLabelWidthString(string());
1853 /* is it a layout that has an automatic label ? */
1854 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1856 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1857 if (i >= 0 && i<= buf->params.secnumdepth) {
1858 par->incCounter(i); // increment the counter
1860 // Is there a label? Useful for Chapter layout
1861 if (!par->params.appendix()) {
1862 if (!layout.labelstring().empty())
1863 par->params.labelString(layout.labelstring());
1865 par->params.labelString(string());
1867 if (!layout.labelstring_appendix().empty())
1868 par->params.labelString(layout.labelstring_appendix());
1870 par->params.labelString(string());
1873 std::ostringstream s;
1875 if (!par->params.appendix()) {
1876 switch (2 * LABEL_COUNTER_CHAPTER -
1877 textclass.maxcounter() + i) {
1878 case LABEL_COUNTER_CHAPTER:
1879 s << par->getCounter(i);
1881 case LABEL_COUNTER_SECTION:
1882 s << par->getCounter(i - 1) << '.'
1883 << par->getCounter(i);
1885 case LABEL_COUNTER_SUBSECTION:
1886 s << par->getCounter(i - 2) << '.'
1887 << par->getCounter(i - 1) << '.'
1888 << par->getCounter(i);
1890 case LABEL_COUNTER_SUBSUBSECTION:
1891 s << par->getCounter(i - 3) << '.'
1892 << par->getCounter(i - 2) << '.'
1893 << par->getCounter(i - 1) << '.'
1894 << par->getCounter(i);
1897 case LABEL_COUNTER_PARAGRAPH:
1898 s << par->getCounter(i - 4) << '.'
1899 << par->getCounter(i - 3) << '.'
1900 << par->getCounter(i - 2) << '.'
1901 << par->getCounter(i - 1) << '.'
1902 << par->getCounter(i);
1904 case LABEL_COUNTER_SUBPARAGRAPH:
1905 s << par->getCounter(i - 5) << '.'
1906 << par->getCounter(i - 4) << '.'
1907 << par->getCounter(i - 3) << '.'
1908 << par->getCounter(i - 2) << '.'
1909 << par->getCounter(i - 1) << '.'
1910 << par->getCounter(i);
1914 // Can this ever be reached? And in the
1915 // case it is, how can this be correct?
1917 s << par->getCounter(i) << '.';
1920 } else { // appendix
1921 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1922 case LABEL_COUNTER_CHAPTER:
1923 if (par->isRightToLeftPar(buf->params))
1924 s << hebrewCounter(par->getCounter(i));
1926 s << alphaCounter(par->getCounter(i));
1928 case LABEL_COUNTER_SECTION:
1929 if (par->isRightToLeftPar(buf->params))
1930 s << hebrewCounter(par->getCounter(i - 1));
1932 s << alphaCounter(par->getCounter(i - 1));
1935 << par->getCounter(i);
1938 case LABEL_COUNTER_SUBSECTION:
1939 if (par->isRightToLeftPar(buf->params))
1940 s << hebrewCounter(par->getCounter(i - 2));
1942 s << alphaCounter(par->getCounter(i - 2));
1945 << par->getCounter(i-1) << '.'
1946 << par->getCounter(i);
1949 case LABEL_COUNTER_SUBSUBSECTION:
1950 if (par->isRightToLeftPar(buf->params))
1951 s << hebrewCounter(par->getCounter(i-3));
1953 s << alphaCounter(par->getCounter(i-3));
1956 << par->getCounter(i-2) << '.'
1957 << par->getCounter(i-1) << '.'
1958 << par->getCounter(i);
1961 case LABEL_COUNTER_PARAGRAPH:
1962 if (par->isRightToLeftPar(buf->params))
1963 s << hebrewCounter(par->getCounter(i-4));
1965 s << alphaCounter(par->getCounter(i-4));
1968 << par->getCounter(i-3) << '.'
1969 << par->getCounter(i-2) << '.'
1970 << par->getCounter(i-1) << '.'
1971 << par->getCounter(i);
1974 case LABEL_COUNTER_SUBPARAGRAPH:
1975 if (par->isRightToLeftPar(buf->params))
1976 s << hebrewCounter(par->getCounter(i-5));
1978 s << alphaCounter(par->getCounter(i-5));
1981 << par->getCounter(i-4) << '.'
1982 << par->getCounter(i-3) << '.'
1983 << par->getCounter(i-2) << '.'
1984 << par->getCounter(i-1) << '.'
1985 << par->getCounter(i);
1989 // Can this ever be reached? And in the
1990 // case it is, how can this be correct?
1992 s << par->getCounter(i) << '.';
1998 par->params.labelString(par->params.labelString() +s.str().c_str());
1999 // We really want to remove the c_str as soon as
2002 for (i++; i < 10; ++i) {
2003 // reset the following counters
2004 par->setCounter(i, 0);
2006 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
2007 for (i++; i < 10; ++i) {
2008 // reset the following counters
2009 par->setCounter(i, 0);
2011 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
2012 par->incCounter(i + par->enumdepth);
2013 int number = par->getCounter(i + par->enumdepth);
2015 std::ostringstream s;
2017 switch (par->enumdepth) {
2019 if (par->isRightToLeftPar(buf->params))
2021 << hebrewCounter(number)
2025 << loweralphaCounter(number)
2029 if (par->isRightToLeftPar(buf->params))
2030 s << '.' << romanCounter(number);
2032 s << romanCounter(number) << '.';
2035 if (par->isRightToLeftPar(buf->params))
2037 << alphaCounter(number);
2039 s << alphaCounter(number)
2043 if (par->isRightToLeftPar(buf->params))
2050 par->params.labelString(s.str().c_str());
2051 // we really want to get rid of that c_str()
2053 for (i += par->enumdepth + 1; i < 10; ++i)
2054 par->setCounter(i, 0); /* reset the following counters */
2057 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2058 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2060 int number = par->getCounter(i);
2062 InsetCommandParams p( "bibitem" );
2063 par->bibkey = new InsetBibKey(p);
2065 par->bibkey->setCounter(number);
2066 par->params.labelString(layout.labelstring());
2068 // In biblio should't be following counters but...
2070 string s = layout.labelstring();
2072 // the caption hack:
2073 if (layout.labeltype == LABEL_SENSITIVE) {
2074 bool isOK (par->InInset() && par->InInset()->owner() &&
2075 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2077 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2078 && (par->footnotekind == LyXParagraph::FIG
2079 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2080 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2081 ? ":øåéà " : "Figure:";
2082 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2083 && (par->footnotekind == LyXParagraph::TAB
2084 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2085 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2086 ? ":äìáè" : "Table:";
2087 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2088 && par->footnotekind == LyXParagraph::ALGORITHM) {
2089 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2090 ? ":Ãúéøåâìà " : "Algorithm:";
2094 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2096 = floatList.getType(tmp->type());
2097 // We should get the correct number here too.
2098 s = fl.name() + " #:";
2100 /* par->SetLayout(0);
2101 s = layout->labelstring; */
2102 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2103 ? " :úåòîùî øñç" : "Senseless: ";
2106 par->params.labelString(s);
2108 /* reset the enumeration counter. They are always resetted
2109 * when there is any other layout between */
2110 for (int i = 6 + par->enumdepth; i < 10; ++i)
2111 par->setCounter(i, 0);
2116 /* Updates all counters BEHIND the row. Changed paragraphs
2117 * with a dynamic left margin will be rebroken. */
2118 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2125 } else if (row->par()->next_
2126 && row->par()->next_->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
2127 par = row->par()->LastPhysicalPar()->next();
2129 par = row->par()->next_;
2136 par = row->par()->next();
2141 while (row->par() != par)
2144 SetCounter(bview->buffer(), par);
2146 /* now check for the headline layouts. remember that they
2147 * have a dynamic left margin */
2152 ( textclasslist.Style(bview->buffer()->params.textclass,
2153 par->layout).margintype == MARGIN_DYNAMIC
2154 || textclasslist.Style(bview->buffer()->params.textclass,
2155 par->layout).labeltype == LABEL_SENSITIVE)
2158 /* Rebreak the paragraph */
2159 RemoveParagraph(row);
2160 AppendParagraph(bview, row);
2163 /* think about the damned open footnotes! */
2164 while (par->next() &&
2165 (par->next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2166 || par->next()->IsDummy())){
2168 if (par->IsDummy()) {
2169 while (row->par() != par)
2171 RemoveParagraph(row);
2172 AppendParagraph(bview, row);
2178 par = par->LastPhysicalPar()->next();
2187 /* insets an inset. */
2188 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2190 if (!cursor.par()->InsertInsetAllowed(inset))
2192 SetUndo(bview->buffer(), Undo::INSERT,
2194 cursor.par()->ParFromPos(cursor.pos())->previous_,
2195 cursor.par()->ParFromPos(cursor.pos())->next_
2197 cursor.par()->previous(),
2198 cursor.par()->next()
2201 cursor.par()->InsertInset(cursor.pos(), inset);
2202 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2203 * The character will not be inserted a
2206 // If we enter a highly editable inset the cursor should be to before
2207 // the inset. This couldn't happen before as Undo was not handled inside
2208 // inset now after the Undo LyX tries to call inset->Edit(...) again
2209 // and cannot do this as the cursor is behind the inset and GetInset
2210 // does not return the inset!
2211 if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
2212 CursorLeft(bview, true);
2218 void LyXText::copyEnvironmentType()
2220 copylayouttype = cursor.par()->GetLayout();
2224 void LyXText::pasteEnvironmentType(BufferView * bview)
2226 SetLayout(bview, copylayouttype);
2230 void LyXText::CutSelection(BufferView * bview, bool doclear)
2232 // Stuff what we got on the clipboard. Even if there is no selection.
2234 // There is a problem with having the stuffing here in that the
2235 // larger the selection the slower LyX will get. This can be
2236 // solved by running the line below only when the selection has
2237 // finished. The solution used currently just works, to make it
2238 // faster we need to be more clever and probably also have more
2239 // calls to stuffClipboard. (Lgb)
2240 bview->stuffClipboard(selectionAsString(bview->buffer()));
2242 // This doesn't make sense, if there is no selection
2246 // OK, we have a selection. This is always between sel_start_cursor
2247 // and sel_end_cursor
2249 // Check whether there are half footnotes in the selection
2250 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2251 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2252 LyXParagraph * tmppar = sel_start_cursor.par();
2253 while (tmppar != sel_end_cursor.par()){
2254 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2255 WriteAlert(_("Impossible operation"),
2256 _("Don't know what to do with half floats."),
2260 tmppar = tmppar->next();
2265 // make sure that the depth behind the selection are restored, too
2267 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
2269 LyXParagraph * endpar = sel_end_cursor.par()->next();
2271 LyXParagraph * undoendpar = endpar;
2273 if (endpar && endpar->GetDepth()) {
2274 while (endpar && endpar->GetDepth()) {
2276 endpar = endpar->LastPhysicalPar()->next();
2278 endpar = endpar->next();
2280 undoendpar = endpar;
2282 } else if (endpar) {
2283 endpar = endpar->next(); // because of parindents etc.
2286 SetUndo(bview->buffer(), Undo::DELETE,
2289 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
2291 sel_start_cursor.par()->previous(),
2297 // there are two cases: cut only within one paragraph or
2298 // more than one paragraph
2300 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2301 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2303 if (sel_start_cursor.par() == sel_end_cursor.par())
2306 // only within one paragraph
2307 endpar = sel_start_cursor.par();
2308 int pos = sel_end_cursor.pos();
2309 cap.cutSelection(sel_start_cursor.par(), &endpar,
2310 sel_start_cursor.pos(), pos,
2311 bview->buffer()->params.textclass, doclear);
2312 sel_end_cursor.pos(pos);
2314 endpar = sel_end_cursor.par();
2316 int pos = sel_end_cursor.pos();
2317 cap.cutSelection(sel_start_cursor.par(), &endpar,
2318 sel_start_cursor.pos(), pos,
2319 bview->buffer()->params.textclass, doclear);
2321 sel_end_cursor.par(endpar);
2322 sel_end_cursor.pos(pos);
2323 cursor.pos(sel_end_cursor.pos());
2325 endpar = endpar->next();
2327 // sometimes necessary
2329 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2331 RedoParagraphs(bview, sel_start_cursor, endpar);
2333 ClearSelection(bview);
2334 cursor = sel_start_cursor;
2335 SetCursor(bview, cursor.par(), cursor.pos());
2336 sel_cursor = cursor;
2337 UpdateCounters(bview, cursor.row());
2341 void LyXText::CopySelection(BufferView * bview)
2343 // Stuff what we got on the clipboard. Even if there is no selection.
2345 // There is a problem with having the stuffing here in that the
2346 // larger the selection the slower LyX will get. This can be
2347 // solved by running the line below only when the selection has
2348 // finished. The solution used currently just works, to make it
2349 // faster we need to be more clever and probably also have more
2350 // calls to stuffClipboard. (Lgb)
2351 bview->stuffClipboard(selectionAsString(bview->buffer()));
2353 // this doesnt make sense, if there is no selection
2357 // ok we have a selection. This is always between sel_start_cursor
2358 // and sel_end cursor
2361 /* check wether there are half footnotes in the selection */
2362 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2363 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2364 LyXParagraph * tmppar = sel_start_cursor.par();
2365 while (tmppar != sel_end_cursor.par()) {
2366 if (tmppar->footnoteflag !=
2367 sel_end_cursor.par()->footnoteflag) {
2368 WriteAlert(_("Impossible operation"),
2369 _("Don't know what to do"
2370 " with half floats."),
2374 tmppar = tmppar->next();
2379 // copy behind a space if there is one
2381 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2383 while (sel_start_cursor.par()->size() > sel_start_cursor.pos()
2385 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2386 && (sel_start_cursor.par() != sel_end_cursor.par()
2387 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2388 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2392 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2393 sel_start_cursor.pos(), sel_end_cursor.pos(),
2394 bview->buffer()->params.textclass);
2398 void LyXText::PasteSelection(BufferView * bview)
2402 // this does not make sense, if there is nothing to paste
2403 if (!cap.checkPastePossible(cursor.par()))
2406 SetUndo(bview->buffer(), Undo::INSERT,
2408 cursor.par()->ParFromPos(cursor.pos())->previous_,
2409 cursor.par()->ParFromPos(cursor.pos())->next_
2411 cursor.par()->previous(),
2412 cursor.par()->next()
2416 LyXParagraph * endpar;
2417 LyXParagraph * actpar = cursor.par();
2419 int pos = cursor.pos();
2420 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2422 RedoParagraphs(bview, cursor, endpar);
2424 SetCursor(bview, cursor.par(), cursor.pos());
2425 ClearSelection(bview);
2427 sel_cursor = cursor;
2428 SetCursor(bview, actpar, pos);
2429 SetSelection(bview);
2430 UpdateCounters(bview, cursor.row());
2434 // returns a pointer to the very first LyXParagraph
2435 LyXParagraph * LyXText::FirstParagraph() const
2437 return OwnerParagraph();
2441 // sets the selection over the number of characters of string, no check!!
2442 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2444 sel_cursor = cursor;
2445 for (int i = 0; str[i]; ++i)
2447 SetSelection(bview);
2451 // simple replacing. The font of the first selected character is used
2452 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2455 SetCursorParUndo(bview->buffer());
2458 if (!selection) { // create a dummy selection
2459 sel_end_cursor = cursor;
2460 sel_start_cursor = cursor;
2463 // Get font setting before we cut
2464 LyXParagraph::size_type pos = sel_end_cursor.pos();
2465 LyXFont const font = sel_start_cursor.par()
2466 ->GetFontSettings(bview->buffer()->params,
2467 sel_start_cursor.pos());
2469 // Insert the new string
2470 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2471 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2475 // Cut the selection
2476 CutSelection(bview);
2482 // needed to insert the selection
2483 void LyXText::InsertStringA(BufferView * bview, string const & str)
2485 LyXParagraph * par = cursor.par();
2486 LyXParagraph::size_type pos = cursor.pos();
2487 LyXParagraph::size_type a = 0;
2488 LyXParagraph * endpar = cursor.par()->next();
2490 SetCursorParUndo(bview->buffer());
2493 textclasslist.Style(bview->buffer()->params.textclass,
2494 cursor.par()->GetLayout()).isEnvironment();
2495 // only to be sure, should not be neccessary
2496 ClearSelection(bview);
2498 // insert the string, don't insert doublespace
2499 string::size_type i = 0;
2500 while (i < str.length()) {
2501 if (str[i] != '\n') {
2503 && i + 1 < str.length() && str[i + 1] != ' '
2504 && pos && par->GetChar(pos - 1)!= ' ') {
2505 par->InsertChar(pos, ' ', current_font);
2507 } else if (str[i] == ' ') {
2508 InsetSpecialChar * new_inset =
2509 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2510 if (par->InsertInsetAllowed(new_inset)) {
2511 par->InsertInset(pos, new_inset,
2517 } else if (str[i] == '\t') {
2518 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2519 InsetSpecialChar * new_inset =
2520 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2521 if (par->InsertInsetAllowed(new_inset)) {
2522 par->InsertInset(pos, new_inset,
2529 } else if (str[i] != 13 &&
2530 // Ignore unprintables
2531 (str[i] & 127) >= ' ') {
2532 par->InsertChar(pos, str[i], current_font);
2536 if (!par->size()) { // par is empty
2537 InsetSpecialChar * new_inset =
2538 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2539 if (par->InsertInsetAllowed(new_inset)) {
2540 par->InsertInset(pos,
2548 par->BreakParagraph(bview->buffer()->params, pos, flag);
2555 RedoParagraphs(bview, cursor, endpar);
2556 SetCursor(bview, cursor.par(), cursor.pos());
2557 sel_cursor = cursor;
2558 SetCursor(bview, par, pos);
2559 SetSelection(bview);
2563 /* turns double-CR to single CR, others where converted into one blank and 13s
2564 * that are ignored .Double spaces are also converted into one. Spaces at
2565 * the beginning of a paragraph are forbidden. tabs are converted into one
2566 * space. then InsertStringA is called */
2567 void LyXText::InsertStringB(BufferView * bview, string const & s)
2570 string::size_type i = 1;
2571 while (i < str.length()) {
2574 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2576 if (str[i] == '\n' && i + 1 < str.length()) {
2577 if (str[i + 1] != '\n') {
2578 if (str[i - 1] != ' ')
2583 while (i + 1 < str.length()
2584 && (str[i + 1] == ' '
2585 || str[i + 1] == '\t'
2586 || str[i + 1] == '\n'
2587 || str[i + 1] == 13)) {
2594 InsertStringA(bview, str);
2598 bool LyXText::GotoNextInset(BufferView * bview,
2599 std::vector<Inset::Code> const & codes,
2600 string const & contents) const
2602 LyXCursor res = cursor;
2606 if (res.pos() < res.par()->Last() - 1) {
2608 if (res.pos() < res.par()->size() - 1) {
2610 res.pos(res.pos() + 1);
2612 res.par(res.par()->next());
2616 } while (res.par() &&
2617 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2618 && (inset = res.par()->GetInset(res.pos())) != 0
2619 && find(codes.begin(), codes.end(), inset->LyxCode())
2621 && (contents.empty() ||
2622 static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
2626 SetCursor(bview, res.par(), res.pos());
2633 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2634 LyXParagraph::size_type pos)
2636 LyXCursor tmpcursor;
2639 LyXParagraph::size_type z;
2640 Row * row = GetRow(par, pos, y);
2642 // is there a break one row above
2643 if (row->previous() && row->previous()->par() == row->par()) {
2644 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2645 if (z >= row->pos()) {
2646 // set the dimensions of the row above
2647 y -= row->previous()->height();
2649 refresh_row = row->previous();
2650 status = LyXText::NEED_MORE_REFRESH;
2652 BreakAgain(bview, row->previous());
2654 // set the cursor again. Otherwise
2655 // dangling pointers are possible
2656 SetCursor(bview, cursor.par(), cursor.pos(),
2657 false, cursor.boundary());
2658 sel_cursor = cursor;
2663 int const tmpheight = row->height();
2664 LyXParagraph::size_type const tmplast = RowLast(row);
2668 BreakAgain(bview, row);
2669 if (row->height() == tmpheight && RowLast(row) == tmplast)
2670 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2672 status = LyXText::NEED_MORE_REFRESH;
2674 // check the special right address boxes
2675 if (textclasslist.Style(bview->buffer()->params.textclass,
2676 par->GetLayout()).margintype
2677 == MARGIN_RIGHT_ADDRESS_BOX) {
2684 RedoDrawingOfParagraph(bview, tmpcursor);
2687 // set the cursor again. Otherwise dangling pointers are possible
2688 // also set the selection
2692 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2693 false, sel_cursor.boundary());
2694 sel_cursor = cursor;
2695 SetCursorIntern(bview, sel_start_cursor.par(),
2696 sel_start_cursor.pos(),
2697 false, sel_start_cursor.boundary());
2698 sel_start_cursor = cursor;
2699 SetCursorIntern(bview, sel_end_cursor.par(),
2700 sel_end_cursor.pos(),
2701 false, sel_end_cursor.boundary());
2702 sel_end_cursor = cursor;
2703 SetCursorIntern(bview, last_sel_cursor.par(),
2704 last_sel_cursor.pos(),
2705 false, last_sel_cursor.boundary());
2706 last_sel_cursor = cursor;
2709 SetCursorIntern(bview, cursor.par(), cursor.pos(),
2710 false, cursor.boundary());
2714 // returns false if inset wasn't found
2715 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2717 // first check the current paragraph
2718 int pos = cursor.par()->GetPositionOfInset(inset);
2720 CheckParagraph(bview, cursor.par(), pos);
2724 // check every paragraph
2726 LyXParagraph * par = FirstParagraph();
2729 // make sure the paragraph is open
2730 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2732 pos = par->GetPositionOfInset(inset);
2734 CheckParagraph(bview, par, pos);
2747 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2748 LyXParagraph::size_type pos,
2749 bool setfont, bool boundary) const
2751 LyXCursor old_cursor = cursor;
2752 SetCursorIntern(bview, par, pos, setfont, boundary);
2753 DeleteEmptyParagraphMechanism(bview, old_cursor);
2757 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2758 LyXParagraph::size_type pos, bool boundary) const
2761 // correct the cursor position if impossible
2762 if (pos > par->Last()){
2763 LyXParagraph * tmppar = par->ParFromPos(pos);
2764 pos = par->PositionInParFromPos(pos);
2767 if (par->IsDummy() && par->previous_ &&
2768 par->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2769 while (par->previous_ &&
2770 ((par->previous_->IsDummy() &&
2771 (par->previous_->previous_->footnoteflag ==
2772 LyXParagraph::CLOSED_FOOTNOTE)) ||
2773 (par->previous_->footnoteflag ==
2774 LyXParagraph::CLOSED_FOOTNOTE))) {
2775 par = par->previous_;
2776 if (par->IsDummy() &&
2777 (par->previous_->footnoteflag ==
2778 LyXParagraph::CLOSED_FOOTNOTE))
2779 pos += par->size() + 1;
2781 if (par->previous_) {
2782 par = par->previous_;
2784 pos += par->size() + 1;
2789 cur.boundary(boundary);
2791 /* get the cursor y position in text */
2793 Row * row = GetRow(par, pos, y);
2794 /* y is now the beginning of the cursor row */
2795 y += row->baseline();
2796 /* y is now the cursor baseline */
2799 /* now get the cursors x position */
2801 float fill_separator, fill_hfill, fill_label_hfill;
2802 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2804 LyXParagraph::size_type cursor_vpos = 0;
2805 LyXParagraph::size_type last = RowLastPrintable(row);
2807 if (pos > last + 1) // This shouldn't happen.
2809 else if (pos < row->pos())
2812 if (last < row->pos())
2813 cursor_vpos = row->pos();
2814 else if (pos > last && !boundary)
2815 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2816 ? row->pos() : last + 1;
2817 else if (pos > row->pos() &&
2818 (pos > last || boundary))
2819 /// Place cursor after char at (logical) position pos - 1
2820 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2821 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2823 /// Place cursor before char at (logical) position pos
2824 cursor_vpos = (bidi_level(pos) % 2 == 0)
2825 ? log2vis(pos) : log2vis(pos) + 1;
2827 LyXParagraph::size_type main_body =
2828 BeginningOfMainBody(bview->buffer(), row->par());
2829 if ((main_body > 0) &&
2830 ((main_body-1 > last) ||
2831 !row->par()->IsLineSeparator(main_body-1)))
2834 for (LyXParagraph::size_type vpos = row->pos();
2835 vpos < cursor_vpos; ++vpos) {
2836 pos = vis2log(vpos);
2837 if (main_body > 0 && pos == main_body - 1) {
2838 x += fill_label_hfill +
2839 lyxfont::width(textclasslist.Style(
2840 bview->buffer()->params.textclass,
2841 row->par()->GetLayout())
2843 GetFont(bview->buffer(), row->par(), -2));
2844 if (row->par()->IsLineSeparator(main_body-1))
2845 x -= SingleWidth(bview, row->par(),main_body-1);
2847 if (HfillExpansion(bview->buffer(), row, pos)) {
2848 x += SingleWidth(bview, row->par(), pos);
2849 if (pos >= main_body)
2852 x += fill_label_hfill;
2853 } else if (row->par()->IsSeparator(pos)) {
2854 x += SingleWidth(bview, row->par(), pos);
2855 if (pos >= main_body)
2856 x += fill_separator;
2858 x += SingleWidth(bview, row->par(), pos);
2867 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2868 LyXParagraph::size_type pos,
2869 bool setfont, bool boundary) const
2871 SetCursor(bview, cursor, par, pos, boundary);
2873 SetCurrentFont(bview);
2877 void LyXText::SetCurrentFont(BufferView * bview) const
2879 LyXParagraph::size_type pos = cursor.pos();
2880 if (cursor.boundary() && pos > 0)
2885 if (pos == cursor.par()->Last())
2887 if (pos == cursor.par()->size())
2890 else if (cursor.par()->IsSeparator(pos)) {
2891 if (pos > cursor.row()->pos() &&
2892 bidi_level(pos) % 2 ==
2893 bidi_level(pos - 1) % 2)
2896 else if (pos + 1 < cursor.par()->Last())
2898 else if (pos + 1 < cursor.par()->size())
2905 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2906 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2909 if (cursor.pos() == cursor.par()->Last() &&
2911 if (cursor.pos() == cursor.par()->size() &&
2913 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2914 !cursor.boundary()) {
2915 Language const * lang =
2916 cursor.par()->getParLanguage(bview->buffer()->params);
2917 current_font.setLanguage(lang);
2918 current_font.setNumber(LyXFont::OFF);
2919 real_current_font.setLanguage(lang);
2920 real_current_font.setNumber(LyXFont::OFF);
2925 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2927 LyXCursor old_cursor = cursor;
2929 /* get the row first */
2931 Row * row = GetRowNearY(y);
2932 cursor.par(row->par());
2935 int column = GetColumnNearX(bview, row, x, bound);
2936 cursor.pos(row->pos() + column);
2938 cursor.y(y + row->baseline());
2940 cursor.boundary(bound);
2941 SetCurrentFont(bview);
2942 DeleteEmptyParagraphMechanism(bview, old_cursor);
2946 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2949 /* get the row first */
2951 Row * row = GetRowNearY(y);
2953 int column = GetColumnNearX(bview, row, x, bound);
2955 cur.par(row->par());
2956 cur.pos(row->pos() + column);
2958 cur.y(y + row->baseline());
2960 cur.boundary(bound);
2964 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2966 if (cursor.pos() > 0) {
2967 bool boundary = cursor.boundary();
2968 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2969 if (!internal && !boundary &&
2970 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2971 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2972 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2973 LyXParagraph * par = cursor.par()->previous();
2975 SetCursor(bview, par, par->Last());
2977 SetCursor(bview, par, par->size());
2983 void LyXText::CursorRight(BufferView * bview, bool internal) const
2985 if (!internal && cursor.boundary() &&
2986 !cursor.par()->IsNewline(cursor.pos()))
2987 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2989 else if (cursor.pos() < cursor.par()->Last()) {
2991 else if (cursor.pos() < cursor.par()->size()) {
2993 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2995 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2996 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2997 } else if (cursor.par()->next())
2998 SetCursor(bview, cursor.par()->next(), 0);
3002 void LyXText::CursorUp(BufferView * bview) const
3004 SetCursorFromCoordinates(bview, cursor.x_fix(),
3005 cursor.y() - cursor.row()->baseline() - 1);
3009 void LyXText::CursorDown(BufferView * bview) const
3011 SetCursorFromCoordinates(bview, cursor.x_fix(),
3012 cursor.y() - cursor.row()->baseline()
3013 + cursor.row()->height() + 1);
3017 void LyXText::CursorUpParagraph(BufferView * bview) const
3019 if (cursor.pos() > 0) {
3020 SetCursor(bview, cursor.par(), 0);
3022 else if (cursor.par()->previous()) {
3023 SetCursor(bview, cursor.par()->previous(), 0);
3028 void LyXText::CursorDownParagraph(BufferView * bview) const
3030 if (cursor.par()->next()) {
3031 SetCursor(bview, cursor.par()->next(), 0);
3034 SetCursor(bview, cursor.par(), cursor.par()->Last());
3036 SetCursor(bview, cursor.par(), cursor.par()->size());
3042 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3043 LyXCursor const & old_cursor) const
3045 // Would be wrong to delete anything if we have a selection.
3046 if (selection) return;
3048 // We allow all kinds of "mumbo-jumbo" when freespacing.
3049 if (textclasslist.Style(bview->buffer()->params.textclass,
3050 old_cursor.par()->GetLayout()).free_spacing)
3053 bool deleted = false;
3055 /* Ok I'll put some comments here about what is missing.
3056 I have fixed BackSpace (and thus Delete) to not delete
3057 double-spaces automagically. I have also changed Cut,
3058 Copy and Paste to hopefully do some sensible things.
3059 There are still some small problems that can lead to
3060 double spaces stored in the document file or space at
3061 the beginning of paragraphs. This happens if you have
3062 the cursor betwenn to spaces and then save. Or if you
3063 cut and paste and the selection have a space at the
3064 beginning and then save right after the paste. I am
3065 sure none of these are very hard to fix, but I will
3066 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3067 that I can get some feedback. (Lgb)
3070 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3071 // delete the LineSeparator.
3074 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3075 // delete the LineSeparator.
3078 // If the pos around the old_cursor were spaces, delete one of them.
3079 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3080 // Only if the cursor has really moved
3082 if (old_cursor.pos() > 0
3084 && old_cursor.pos() < old_cursor.par()->Last()
3086 && old_cursor.pos() < old_cursor.par()->size()
3088 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3089 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3090 old_cursor.par()->Erase(old_cursor.pos() - 1);
3091 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3093 if (old_cursor.par() == cursor.par() &&
3094 cursor.pos() > old_cursor.pos()) {
3095 SetCursorIntern(bview, cursor.par(),
3098 SetCursorIntern(bview, cursor.par(),
3104 // Do not delete empty paragraphs with keepempty set.
3105 if ((textclasslist.Style(bview->buffer()->params.textclass,
3106 old_cursor.par()->GetLayout())).keepempty)
3109 LyXCursor tmpcursor;
3112 if (old_cursor.par() != cursor.par()) {
3113 if ((old_cursor.par()->Last() == 0
3114 || (old_cursor.par()->Last() == 1
3115 && old_cursor.par()->IsLineSeparator(0)))
3116 && old_cursor.par()->FirstPhysicalPar()
3117 == old_cursor.par()->LastPhysicalPar()
3119 if (old_cursor.par() != cursor.par()) {
3120 if ((old_cursor.par()->size() == 0
3121 || (old_cursor.par()->size() == 1
3122 && old_cursor.par()->IsLineSeparator(0)))
3125 // ok, we will delete anything
3127 // make sure that you do not delete any environments
3130 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3131 !(old_cursor.row()->previous()
3132 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3133 && !(old_cursor.row()->next()
3134 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3135 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3136 && ((old_cursor.row()->previous()
3137 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3138 || (old_cursor.row()->next()
3139 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3142 status = LyXText::NEED_MORE_REFRESH;
3145 if (old_cursor.row()->previous()) {
3146 refresh_row = old_cursor.row()->previous();
3147 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3149 cursor = old_cursor; // that undo can restore the right cursor position
3151 LyXParagraph * endpar = old_cursor.par()->next_;
3152 if (endpar && endpar->GetDepth()) {
3153 while (endpar && endpar->GetDepth()) {
3154 endpar = endpar->LastPhysicalPar()->next();
3157 SetUndo(bview->buffer(), Undo::DELETE,
3158 old_cursor.par()->previous_,
3163 RemoveRow(old_cursor.row());
3164 if (OwnerParagraph() == old_cursor.par()) {
3165 OwnerParagraph(OwnerParagraph()->next_);
3168 LyXParagraph * endpar = old_cursor.par()->next();
3169 if (endpar && endpar->GetDepth()) {
3170 while (endpar && endpar->GetDepth()) {
3171 endpar = endpar->next();
3174 SetUndo(bview->buffer(), Undo::DELETE,
3175 old_cursor.par()->previous(),
3180 RemoveRow(old_cursor.row());
3181 if (OwnerParagraph() == old_cursor.par()) {
3182 OwnerParagraph(OwnerParagraph()->next());
3186 delete old_cursor.par();
3188 /* Breakagain the next par. Needed
3189 * because of the parindent that
3190 * can occur or dissappear. The
3191 * next row can change its height,
3192 * if there is another layout before */
3193 if (refresh_row->next()) {
3194 BreakAgain(bview, refresh_row->next());
3195 UpdateCounters(bview, refresh_row);
3197 SetHeightOfRow(bview, refresh_row);
3199 refresh_row = old_cursor.row()->next();
3200 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3203 cursor = old_cursor; // that undo can restore the right cursor position
3205 LyXParagraph * endpar = old_cursor.par()->next_;
3206 if (endpar && endpar->GetDepth()) {
3207 while (endpar && endpar->GetDepth()) {
3208 endpar = endpar->LastPhysicalPar()->next();
3211 SetUndo(bview->buffer(), Undo::DELETE,
3212 old_cursor.par()->previous_,
3217 RemoveRow(old_cursor.row());
3219 if (OwnerParagraph() == old_cursor.par()) {
3220 OwnerParagraph(OwnerParagraph()->next_);
3223 LyXParagraph * endpar = old_cursor.par()->next();
3224 if (endpar && endpar->GetDepth()) {
3225 while (endpar && endpar->GetDepth()) {
3226 endpar = endpar->next();
3229 SetUndo(bview->buffer(), Undo::DELETE,
3230 old_cursor.par()->previous(),
3235 RemoveRow(old_cursor.row());
3237 if (OwnerParagraph() == old_cursor.par()) {
3238 OwnerParagraph(OwnerParagraph()->next());
3241 delete old_cursor.par();
3243 /* Breakagain the next par. Needed
3244 because of the parindent that can
3245 occur or dissappear.
3246 The next row can change its height,
3247 if there is another layout before
3250 BreakAgain(bview, refresh_row);
3251 UpdateCounters(bview, refresh_row->previous());
3257 SetCursorIntern(bview, cursor.par(), cursor.pos());
3259 if (sel_cursor.par() == old_cursor.par()
3260 && sel_cursor.pos() == sel_cursor.pos()) {
3261 // correct selection
3262 sel_cursor = cursor;
3269 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3270 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3272 SetCursorIntern(bview, cursor.par(), cursor.pos());
3273 sel_cursor = cursor;
3281 LyXParagraph * LyXText::GetParFromID(int id)
3283 LyXParagraph * result = FirstParagraph();
3284 while (result && result->id() != id)
3285 result = result->next_;
3289 LyXParagraph * LyXText::GetParFromID(int id)
3291 LyXParagraph * result = FirstParagraph();
3292 while (result && result->id() != id)
3293 result = result->next();
3300 bool LyXText::TextUndo(BufferView * bview)
3304 // returns false if no undo possible
3305 Undo * undo = bview->buffer()->undostack.pop();
3309 bview->buffer()->redostack
3310 .push(CreateUndo(bview->buffer(), undo->kind,
3311 GetParFromID(undo->number_of_before_par),
3312 GetParFromID(undo->number_of_behind_par)));
3314 return TextHandleUndo(bview, undo);
3318 bool LyXText::TextRedo(BufferView * bview)
3322 // returns false if no redo possible
3323 Undo * undo = bview->buffer()->redostack.pop();
3327 bview->buffer()->undostack
3328 .push(CreateUndo(bview->buffer(), undo->kind,
3329 GetParFromID(undo->number_of_before_par),
3330 GetParFromID(undo->number_of_behind_par)));
3332 return TextHandleUndo(bview, undo);
3336 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3340 // returns false if no undo possible
3341 bool result = false;
3343 LyXParagraph * before =
3344 GetParFromID(undo->number_of_before_par);
3345 LyXParagraph * behind =
3346 GetParFromID(undo->number_of_behind_par);
3347 LyXParagraph * tmppar;
3348 LyXParagraph * tmppar2;
3349 LyXParagraph * endpar;
3350 LyXParagraph * tmppar5;
3352 // if there's no before take the beginning
3353 // of the document for redoing
3355 SetCursorIntern(bview, FirstParagraph(), 0);
3357 // replace the paragraphs with the undo informations
3359 LyXParagraph * tmppar3 = undo->par;
3360 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3361 LyXParagraph * tmppar4 = tmppar3;
3364 while (tmppar4->next_)
3365 tmppar4 = tmppar4->next_;
3366 } // get last undo par
3368 // now remove the old text if there is any
3369 if (before != behind || (!behind && !before)) {
3371 tmppar5 = before->next();
3373 tmppar5 = OwnerParagraph();
3375 while (tmppar5 && tmppar5 != behind) {
3377 tmppar5 = tmppar5->next();
3378 // a memory optimization for edit: Only layout information
3379 // is stored in the undo. So restore the text informations.
3380 if (undo->kind == Undo::EDIT) {
3381 tmppar2->setContentsFromPar(tmppar);
3382 tmppar->clearContents();
3383 tmppar2 = tmppar2->next();
3390 while (tmppar4->next())
3391 tmppar4 = tmppar4->next();
3392 } // get last undo par
3394 // now remove the old text if there is any
3395 if (before != behind || (!behind && !before)) {
3397 tmppar5 = before->next();
3399 tmppar5 = OwnerParagraph();
3401 while (tmppar5 && tmppar5 != behind) {
3403 tmppar5 = tmppar5->next();
3404 // a memory optimization for edit: Only layout information
3405 // is stored in the undo. So restore the text informations.
3406 if (undo->kind == Undo::EDIT) {
3407 tmppar2->setContentsFromPar(tmppar);
3408 tmppar->clearContents();
3409 tmppar2 = tmppar2->next();
3415 // put the new stuff in the list if there is one
3418 before->next(tmppar3);
3420 OwnerParagraph(tmppar3);
3421 tmppar3->previous(before);
3424 OwnerParagraph(behind);
3427 tmppar4->next(behind);
3429 behind->previous(tmppar4);
3433 // Set the cursor for redoing
3436 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3438 SetCursorIntern(bview, before, 0);
3441 // check wether before points to a closed float and open it if necessary
3442 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3443 && before->next_ && before->next_->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3445 while (tmppar4->previous_ &&
3446 tmppar4->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3447 tmppar4 = tmppar4->previous_;
3448 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3449 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3450 tmppar4 = tmppar4->next_;
3457 // open a cosed footnote at the end if necessary
3458 if (behind && behind->previous_ &&
3459 behind->previous_->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3460 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3461 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3462 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3463 behind = behind->next_;
3468 // calculate the endpar for redoing the paragraphs.
3471 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3472 endpar = behind->LastPhysicalPar()->next();
3474 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->next();
3476 endpar = behind->next();
3481 tmppar = GetParFromID(undo->number_of_cursor_par);
3482 RedoParagraphs(bview, cursor, endpar);
3484 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3485 UpdateCounters(bview, cursor.row());
3495 void LyXText::FinishUndo()
3499 // makes sure the next operation will be stored
3500 undo_finished = true;
3504 void LyXText::FreezeUndo()
3508 // this is dangerous and for internal use only
3513 void LyXText::UnFreezeUndo()
3517 // this is dangerous and for internal use only
3518 undo_frozen = false;
3522 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3523 LyXParagraph const * before,
3524 LyXParagraph const * behind) const
3529 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3530 buf->redostack.clear();
3534 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3535 LyXParagraph const * before, LyXParagraph const * behind)
3539 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3543 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3544 LyXParagraph const * before,
3545 LyXParagraph const * behind) const
3550 int before_number = -1;
3551 int behind_number = -1;
3553 before_number = before->id();
3555 behind_number = behind->id();
3556 // Undo::EDIT and Undo::FINISH are
3557 // always finished. (no overlapping there)
3558 // overlapping only with insert and delete inside one paragraph:
3559 // Nobody wants all removed character
3560 // appear one by one when undoing.
3561 // EDIT is special since only layout information, not the
3562 // contents of a paragaph are stored.
3563 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3564 // check wether storing is needed
3565 if (!buf->undostack.empty() &&
3566 buf->undostack.top()->kind == kind &&
3567 buf->undostack.top()->number_of_before_par == before_number &&
3568 buf->undostack.top()->number_of_behind_par == behind_number ){
3573 // create a new Undo
3574 LyXParagraph * undopar;
3575 LyXParagraph * tmppar;
3576 LyXParagraph * tmppar2;
3578 LyXParagraph * start = 0;
3579 LyXParagraph * end = 0;
3583 start = before->next_;
3585 start = FirstParagraph();
3587 end = behind->previous_;
3589 end = FirstParagraph();
3593 if (start && end && (start != end->next_) &&
3594 ((before != behind) || (!before && !behind))) {
3596 tmppar2 = tmppar->Clone();
3597 tmppar2->id(tmppar->id());
3599 // a memory optimization: Just store the layout information
3601 if (kind == Undo::EDIT){
3602 //tmppar2->text.clear();
3603 tmppar2->clearContents();
3608 while (tmppar != end && tmppar->next_) {
3609 tmppar = tmppar->next_;
3610 tmppar2->next(tmppar->Clone());
3611 tmppar2->next_->id(tmppar->id());
3612 // a memory optimization: Just store the layout
3613 // information when only edit
3614 if (kind == Undo::EDIT){
3615 //tmppar2->next->text.clear();
3616 tmppar2->clearContents();
3618 tmppar2->next_->previous(tmppar2);
3619 tmppar2 = tmppar2->next_;
3623 undopar = 0; // nothing to replace (undo of delete maybe)
3625 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3626 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3629 start = const_cast<LyXParagraph*>(before->next());
3631 start = FirstParagraph();
3633 end = const_cast<LyXParagraph*>(behind->previous());
3635 end = FirstParagraph();
3639 if (start && end && (start != end->next()) &&
3640 ((before != behind) || (!before && !behind))) {
3642 tmppar2 = tmppar->Clone();
3643 tmppar2->id(tmppar->id());
3645 // a memory optimization: Just store the layout information
3647 if (kind == Undo::EDIT){
3648 //tmppar2->text.clear();
3649 tmppar2->clearContents();
3654 while (tmppar != end && tmppar->next()) {
3655 tmppar = tmppar->next();
3656 tmppar2->next(tmppar->Clone());
3657 tmppar2->next()->id(tmppar->id());
3658 // a memory optimization: Just store the layout
3659 // information when only edit
3660 if (kind == Undo::EDIT){
3661 //tmppar2->next->text.clear();
3662 tmppar2->clearContents();
3664 tmppar2->next()->previous(tmppar2);
3665 tmppar2 = tmppar2->next();
3669 undopar = 0; // nothing to replace (undo of delete maybe)
3671 int cursor_par = cursor.par()->id();
3672 int cursor_pos = cursor.pos();
3675 Undo * undo = new Undo(kind,
3676 before_number, behind_number,
3677 cursor_par, cursor_pos,
3680 undo_finished = false;
3685 void LyXText::SetCursorParUndo(Buffer * buf)
3689 SetUndo(buf, Undo::FINISH,
3691 cursor.par()->ParFromPos(cursor.pos())->previous_,
3692 cursor.par()->ParFromPos(cursor.pos())->next_
3694 cursor.par()->previous(),
3695 cursor.par()->next()
3701 void LyXText::toggleAppendix(BufferView * bview)
3704 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3706 LyXParagraph * par = cursor.par();
3708 bool start = !par->params.startOfAppendix();
3710 // ensure that we have only one start_of_appendix in this document
3711 LyXParagraph * tmp = FirstParagraph();
3713 for (; tmp; tmp = tmp->next_)
3714 tmp->params.startOfAppendix(false);
3716 for (; tmp; tmp = tmp->next())
3717 tmp->params.startOfAppendix(false);
3719 par->params.startOfAppendix(start);
3721 // we can set the refreshing parameters now
3722 status = LyXText::NEED_MORE_REFRESH;
3724 refresh_row = 0; // not needed for full update
3725 UpdateCounters(bview, 0);
3726 SetCursor(bview, cursor.par(), cursor.pos());
3730 LyXParagraph * LyXText::OwnerParagraph() const
3733 return inset_owner->par;
3735 return bv_owner->buffer()->paragraph;
3739 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3742 inset_owner->par = p;
3744 bv_owner->buffer()->paragraph = p;