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"
54 LyXText::LyXText(BufferView * bv)
62 LyXText::LyXText(InsetText * inset)
72 the_locking_inset = 0;
80 status = LyXText::UNCHANGED;
81 // set cursor at the very top position
82 selection = true; /* these setting is necessary
83 because of the delete-empty-
84 paragraph mechanism in
87 LyXParagraph * par = OwnerParagraph();
88 current_font = GetFont(bv_owner->buffer(), par, 0);
90 InsertParagraph(bv_owner, par, lastrow);
93 SetCursor(bv_owner, firstrow->par(), 0);
95 current_font = LyXFont(LyXFont::ALL_SANE);
101 // no rebreak necessary
104 undo_finished = true;
107 // Default layouttype for copy environment type
111 // Dump all rowinformation:
112 Row * tmprow = firstrow;
113 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
115 lyxerr << tmprow->baseline() << '\t'
116 << tmprow->par << '\t'
117 << tmprow->pos() << '\t'
118 << tmprow->height << '\t'
119 << tmprow->ascent_of_text << '\t'
120 << tmprow->fill << '\n';
121 tmprow = tmprow->next();
128 void LyXText::init(BufferView * bview)
133 LyXParagraph * par = OwnerParagraph();
134 current_font = GetFont(bview->buffer(), par, 0);
136 InsertParagraph(bview, par, lastrow);
139 SetCursorIntern(bview, firstrow->par(), 0);
142 // Dump all rowinformation:
143 Row * tmprow = firstrow;
144 lyxerr << "Width = " << width << endl;
145 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
147 lyxerr << tmprow->baseline() << '\t'
148 << tmprow->par() << '\t'
149 << tmprow->pos() << '\t'
150 << tmprow->height() << '\t'
151 << tmprow->ascent_of_text() << '\t'
152 << tmprow->fill() << '\n';
153 tmprow = tmprow->next();
161 // Delete all rows, this does not touch the paragraphs!
162 Row * tmprow = firstrow;
164 tmprow = firstrow->next();
171 // Gets the fully instantiated font at a given position in a paragraph
172 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
173 // The difference is that this one is used for displaying, and thus we
174 // are allowed to make cosmetic improvements. For instance make footnotes
176 // If position is -1, we get the layout font of the paragraph.
177 // If position is -2, we get the font of the manual label of the paragraph.
178 LyXFont const LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
179 LyXParagraph::size_type pos) const
181 LyXLayout const & layout =
182 textclasslist.Style(buf->params.textclass, par->GetLayout());
184 char par_depth = par->GetDepth();
185 // We specialize the 95% common case:
188 par->footnoteflag == LyXParagraph::NO_FOOTNOTE &&
193 if (layout.labeltype == LABEL_MANUAL
194 && pos < BeginningOfMainBody(buf, par)) {
196 LyXFont f = par->GetFontSettings(buf->params,
198 return f.realize(layout.reslabelfont);
200 LyXFont f = par->GetFontSettings(buf->params, pos);
201 return f.realize(layout.resfont);
206 // process layoutfont for pos == -1 and labelfont for pos < -1
208 return layout.resfont;
210 return layout.reslabelfont;
214 // The uncommon case need not be optimized as much
216 LyXFont layoutfont, tmpfont;
220 if (pos < BeginningOfMainBody(buf, par)) {
222 layoutfont = layout.labelfont;
225 layoutfont = layout.font;
227 tmpfont = par->GetFontSettings(buf->params, pos);
228 tmpfont.realize(layoutfont);
231 // process layoutfont for pos == -1 and labelfont for pos < -1
233 tmpfont = layout.font;
235 tmpfont = layout.labelfont;
238 // Resolve against environment font information
239 while (par && par_depth && !tmpfont.resolved()) {
240 par = par->DepthHook(par_depth - 1);
242 tmpfont.realize(textclasslist.
243 Style(buf->params.textclass,
244 par->GetLayout()).font);
245 par_depth = par->GetDepth();
249 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
252 // Cosmetic improvement: If this is an open footnote, make the font
254 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
255 && par->footnotekind == LyXParagraph::FOOTNOTE) {
263 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
264 LyXParagraph::size_type pos,
268 // Let the insets convert their font
269 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
270 if (par->GetInset(pos))
271 font = par->GetInset(pos)->ConvertFont(font);
274 LyXLayout const & layout =
275 textclasslist.Style(buf->params.textclass,
278 // Get concrete layout font to reduce against
281 if (pos < BeginningOfMainBody(buf, par))
282 layoutfont = layout.labelfont;
284 layoutfont = layout.font;
286 // Realize against environment font information
287 if (par->GetDepth()){
288 LyXParagraph * tp = par;
289 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
290 tp = tp->DepthHook(tp->GetDepth()-1);
292 layoutfont.realize(textclasslist.
293 Style(buf->params.textclass,
294 tp->GetLayout()).font);
298 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
301 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
302 && par->footnotekind == LyXParagraph::FOOTNOTE) {
303 layoutfont.decSize();
306 // Now, reduce font against full layout font
307 font.reduce(layoutfont);
309 par->SetFont(pos, font);
313 /* inserts a new row behind the specified row, increments
314 * the touched counters */
315 void LyXText::InsertRow(Row * row, LyXParagraph * par,
316 LyXParagraph::size_type pos) const
318 Row * tmprow = new Row;
321 tmprow->next(firstrow);
324 tmprow->previous(row);
325 tmprow->next(row->next());
330 tmprow->next()->previous(tmprow);
332 if (tmprow->previous())
333 tmprow->previous()->next(tmprow);
341 ++number_of_rows; // one more row
345 // removes the row and reset the touched counters
346 void LyXText::RemoveRow(Row * row) const
348 /* this must not happen before the currentrow for clear reasons.
349 so the trick is just to set the current row onto the previous
352 GetRow(row->par(), row->pos(), unused_y);
355 row->next()->previous(row->previous());
356 if (!row->previous()) {
357 firstrow = row->next();
359 row->previous()->next(row->next());
362 lastrow = row->previous();
364 height -= row->height(); // the text becomes smaller
367 --number_of_rows; // one row less
371 // remove all following rows of the paragraph of the specified row.
372 void LyXText::RemoveParagraph(Row * row) const
374 LyXParagraph * tmppar = row->par();
378 while (row && row->par() == tmppar) {
379 tmprow = row->next();
386 // insert the specified paragraph behind the specified row
387 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
390 InsertRow(row, par, 0); /* insert a new row, starting
393 SetCounter(bview->buffer(), par); // set the counters
395 // and now append the whole paragraph behind the new row
398 AppendParagraph(bview, firstrow);
400 row->next()->height(0);
401 AppendParagraph(bview, row->next());
407 void LyXText::ToggleFootnote(BufferView * bview)
409 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
411 && par->next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
413 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
415 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
416 CloseFootnote(bview);
423 void LyXText::OpenStuff(BufferView * bview)
425 if (cursor.pos() == 0 && cursor.par()->bibkey){
426 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
427 } else if (cursor.pos() < cursor.par()->Last()
428 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
429 && cursor.par()->GetInset(cursor.pos())->Editable()) {
430 bview->owner()->getMiniBuffer()
431 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
432 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
433 SetCursorParUndo(bview->buffer());
434 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
438 ToggleFootnote(bview);
446 void LyXText::CloseFootnote(BufferView * bview)
448 LyXParagraph * tmppar;
449 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
451 // if the cursor is not in an open footnote, or
452 // there is no open footnote in this paragraph, just return.
453 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
456 par->next_->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
457 bview->owner()->getMiniBuffer()
458 ->Set(_("Nothing to do"));
462 // ok, move the cursor right before the footnote
463 // just a little faster than using CursorRight()
465 cursor.par()->ParFromPos(cursor.pos()) != par;) {
466 cursor.pos(cursor.pos() + 1);
469 // now the cursor is at the beginning of the physical par
470 SetCursor(bview, cursor.par(),
472 cursor.par()->ParFromPos(cursor.pos())->size());
474 /* we are in a footnote, so let us move at the beginning */
475 /* this is just faster than using just CursorLeft() */
477 tmppar = cursor.par();
478 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
479 // just a little bit faster than movin the cursor
480 tmppar = tmppar->previous();
482 SetCursor(bview, tmppar, tmppar->Last());
485 // the cursor must be exactly before the footnote
486 par = cursor.par()->ParFromPos(cursor.pos());
488 status = LyXText::NEED_MORE_REFRESH;
489 refresh_row = cursor.row();
490 refresh_y = cursor.y() - cursor.row()->baseline();
492 tmppar = cursor.par();
493 LyXParagraph * endpar = par->NextAfterFootnote()->next();
494 Row * row = cursor.row();
496 tmppar->CloseFootnote(cursor.pos());
498 while (tmppar != endpar) {
499 RemoveRow(row->next());
501 tmppar = row->next()->par();
506 AppendParagraph(bview, cursor.row());
508 SetCursor(bview, cursor.par(), cursor.pos());
512 if (cursor.row()->next())
513 SetHeightOfRow(bview, cursor.row()->next());
518 /* used in setlayout */
519 // Asger is not sure we want to do this...
520 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
524 LyXLayout const & layout =
525 textclasslist.Style(buf->params.textclass, par->GetLayout());
527 LyXFont layoutfont, tmpfont;
528 for (LyXParagraph::size_type pos = 0;
530 pos < par->Last(); ++pos) {
532 pos < par->size(); ++pos) {
534 if (pos < BeginningOfMainBody(buf, par))
535 layoutfont = layout.labelfont;
537 layoutfont = layout.font;
539 tmpfont = par->GetFontSettings(buf->params, pos);
540 tmpfont.reduce(layoutfont);
541 par->SetFont(pos, tmpfont);
547 LyXParagraph * LyXText::SetLayout(BufferView * bview,
548 LyXCursor & cur, LyXCursor & sstart_cur,
549 LyXCursor & send_cur,
550 LyXTextClass::size_type layout)
552 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->next();
553 LyXParagraph * undoendpar = endpar;
555 if (endpar && endpar->GetDepth()) {
556 while (endpar && endpar->GetDepth()) {
557 endpar = endpar->LastPhysicalPar()->next();
561 endpar = endpar->next(); // because of parindents etc.
564 SetUndo(bview->buffer(), Undo::EDIT,
565 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous_,
568 /* ok we have a selection. This is always between sstart_cur
569 * and sel_end cursor */
572 LyXLayout const & lyxlayout =
573 textclasslist.Style(bview->buffer()->params.textclass, layout);
575 while (cur.par() != send_cur.par()) {
576 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
577 cur.par()->SetLayout(bview->buffer()->params, layout);
578 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
579 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
580 fppar->params.spaceTop(lyxlayout.fill_top ?
581 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
582 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
583 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
584 if (lyxlayout.margintype == MARGIN_MANUAL)
585 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
586 if (lyxlayout.labeltype != LABEL_BIBLIO
588 delete fppar->bibkey;
592 cur.par(cur.par()->next());
594 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
595 cur.par()->SetLayout(bview->buffer()->params, layout);
596 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
597 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
598 fppar->params.spaceTop(lyxlayout.fill_top ?
599 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
600 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
601 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
602 if (lyxlayout.margintype == MARGIN_MANUAL)
603 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
604 if (lyxlayout.labeltype != LABEL_BIBLIO
606 delete fppar->bibkey;
613 LyXParagraph * LyXText::SetLayout(BufferView * bview,
614 LyXCursor & cur, LyXCursor & sstart_cur,
615 LyXCursor & send_cur,
616 LyXTextClass::size_type layout)
618 LyXParagraph * endpar = send_cur.par()->next();
619 LyXParagraph * undoendpar = endpar;
621 if (endpar && endpar->GetDepth()) {
622 while (endpar && endpar->GetDepth()) {
623 endpar = endpar->next();
627 endpar = endpar->next(); // because of parindents etc.
630 SetUndo(bview->buffer(), Undo::EDIT,
631 sstart_cur.par()->previous(),
634 /* ok we have a selection. This is always between sstart_cur
635 * and sel_end cursor */
638 LyXLayout const & lyxlayout =
639 textclasslist.Style(bview->buffer()->params.textclass, layout);
641 while (cur.par() != send_cur.par()) {
642 cur.par()->SetLayout(layout);
643 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
644 LyXParagraph * fppar = cur.par();
645 fppar->params.spaceTop(lyxlayout.fill_top ?
646 VSpace(VSpace::VFILL)
647 : VSpace(VSpace::NONE));
648 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
649 VSpace(VSpace::VFILL)
650 : VSpace(VSpace::NONE));
651 if (lyxlayout.margintype == MARGIN_MANUAL)
652 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
653 if (lyxlayout.labeltype != LABEL_BIBLIO
655 delete fppar->bibkey;
658 cur.par(cur.par()->next());
660 cur.par()->SetLayout(layout);
661 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
662 LyXParagraph * fppar = cur.par();
663 fppar->params.spaceTop(lyxlayout.fill_top ?
664 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
665 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
666 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
667 if (lyxlayout.margintype == MARGIN_MANUAL)
668 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
669 if (lyxlayout.labeltype != LABEL_BIBLIO
671 delete fppar->bibkey;
679 // set layout over selection and make a total rebreak of those paragraphs
680 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
682 LyXCursor tmpcursor = cursor; /* store the current cursor */
684 // if there is no selection just set the layout
685 // of the current paragraph */
687 sel_start_cursor = cursor; // dummy selection
688 sel_end_cursor = cursor;
691 endpar = SetLayout(bview, cursor, sel_start_cursor,
692 sel_end_cursor, layout);
693 RedoParagraphs(bview, sel_start_cursor, endpar);
695 // we have to reset the selection, because the
696 // geometry could have changed
697 SetCursor(bview, sel_start_cursor.par(),
698 sel_start_cursor.pos(), false);
700 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
702 UpdateCounters(bview, cursor.row());
703 ClearSelection(bview);
705 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
709 // increment depth over selection and
710 // make a total rebreak of those paragraphs
711 void LyXText::IncDepth(BufferView * bview)
713 // If there is no selection, just use the current paragraph
715 sel_start_cursor = cursor; // dummy selection
716 sel_end_cursor = cursor;
719 // We end at the next paragraph with depth 0
720 LyXParagraph * endpar =
722 sel_end_cursor.par()->LastPhysicalPar()->next();
724 sel_end_cursor.par()->next();
726 LyXParagraph * undoendpar = endpar;
728 if (endpar && endpar->GetDepth()) {
729 while (endpar && endpar->GetDepth()) {
731 endpar = endpar->LastPhysicalPar()->next();
733 endpar = endpar->next();
739 endpar = endpar->next(); // because of parindents etc.
742 SetUndo(bview->buffer(), Undo::EDIT,
745 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
747 sel_start_cursor.par()->previous(),
751 LyXCursor tmpcursor = cursor; // store the current cursor
753 // ok we have a selection. This is always between sel_start_cursor
754 // and sel_end cursor
755 cursor = sel_start_cursor;
757 bool anything_changed = false;
760 // NOTE: you can't change the depth of a bibliography entry
763 cursor.par()->footnoteflag ==
764 sel_start_cursor.par()->footnoteflag &&
766 textclasslist.Style(bview->buffer()->params.textclass,
767 cursor.par()->GetLayout()
768 ).labeltype != LABEL_BIBLIO) {
769 LyXParagraph * prev =
771 cursor.par()->FirstPhysicalPar()->previous();
773 cursor.par()->previous();
776 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
777 || (prev->GetDepth() == cursor.par()->GetDepth()
778 && textclasslist.Style(bview->buffer()->params.textclass,
779 prev->GetLayout()).isEnvironment()))) {
781 cursor.par()->FirstPhysicalPar()->params.depth(cursor.par()->FirstPhysicalPar()->params.depth() + 1);
783 cursor.par()->params.depth(cursor.par()->params.depth() + 1);
785 anything_changed = true;
788 if (cursor.par() == sel_end_cursor.par())
790 cursor.par(cursor.par()->next());
793 // if nothing changed set all depth to 0
794 if (!anything_changed) {
795 cursor = sel_start_cursor;
796 while (cursor.par() != sel_end_cursor.par()) {
798 cursor.par()->FirstPhysicalPar()->params.depth(0);
800 cursor.par()->params.depth(0);
802 cursor.par(cursor.par()->next());
805 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
806 cursor.par()->FirstPhysicalPar()->params.depth(0);
808 cursor.par()->params.depth(0);
812 RedoParagraphs(bview, sel_start_cursor, endpar);
814 // we have to reset the selection, because the
815 // geometry could have changed
816 SetCursor(bview, sel_start_cursor.par(),
817 sel_start_cursor.pos());
819 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
820 UpdateCounters(bview, cursor.row());
821 ClearSelection(bview);
823 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
827 // decrement depth over selection and
828 // make a total rebreak of those paragraphs
829 void LyXText::DecDepth(BufferView * bview)
831 // if there is no selection just set the layout
832 // of the current paragraph
834 sel_start_cursor = cursor; // dummy selection
835 sel_end_cursor = cursor;
838 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
840 LyXParagraph * endpar = sel_end_cursor.par()->next();
842 LyXParagraph * undoendpar = endpar;
844 if (endpar && endpar->GetDepth()) {
845 while (endpar && endpar->GetDepth()) {
847 endpar = endpar->LastPhysicalPar()->next();
849 endpar = endpar->next();
855 endpar = endpar->next(); // because of parindents etc.
858 SetUndo(bview->buffer(), Undo::EDIT,
861 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
863 sel_start_cursor.par()->previous(),
867 LyXCursor tmpcursor = cursor; // store the current cursor
869 // ok we have a selection. This is always between sel_start_cursor
870 // and sel_end cursor
871 cursor = sel_start_cursor;
875 if (cursor.par()->footnoteflag ==
876 sel_start_cursor.par()->footnoteflag) {
877 if (cursor.par()->FirstPhysicalPar()->params.depth())
878 cursor.par()->FirstPhysicalPar()->params.depth(cursor.par()->FirstPhysicalPar()->params.depth() - 1);
881 if (cursor.par()->params.depth())
882 cursor.par()->params.depth(cursor.par()->params.depth() - 1);
884 if (cursor.par() == sel_end_cursor.par())
886 cursor.par(cursor.par()->next());
889 RedoParagraphs(bview, sel_start_cursor, endpar);
891 // we have to reset the selection, because the
892 // geometry could have changed
893 SetCursor(bview, sel_start_cursor.par(),
894 sel_start_cursor.pos());
896 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
897 UpdateCounters(bview, cursor.row());
898 ClearSelection(bview);
900 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
904 // set font over selection and make a total rebreak of those paragraphs
905 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
907 // if there is no selection just set the current_font
909 // Determine basis font
911 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
913 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
915 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
916 // Update current font
917 real_current_font.update(font,
918 bview->buffer()->params.language,
921 // Reduce to implicit settings
922 current_font = real_current_font;
923 current_font.reduce(layoutfont);
924 // And resolve it completely
925 real_current_font.realize(layoutfont);
929 LyXCursor tmpcursor = cursor; // store the current cursor
931 // ok we have a selection. This is always between sel_start_cursor
932 // and sel_end cursor
934 SetUndo(bview->buffer(), Undo::EDIT,
936 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous_,
937 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next_
939 sel_start_cursor.par()->previous(),
940 sel_end_cursor.par()->next()
943 cursor = sel_start_cursor;
944 while (cursor.par() != sel_end_cursor.par() ||
947 cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag &&
949 cursor.pos() < sel_end_cursor.pos()))
952 if (cursor.pos() < cursor.par()->Last()
953 && cursor.par()->footnoteflag
954 == sel_start_cursor.par()->footnoteflag
956 if (cursor.pos() < cursor.par()->size()
959 // an open footnote should behave
961 LyXFont newfont = GetFont(bview->buffer(),
962 cursor.par(), cursor.pos());
964 bview->buffer()->params.language,
966 SetCharFont(bview->buffer(),
967 cursor.par(), cursor.pos(), newfont);
968 cursor.pos(cursor.pos() + 1);
971 cursor.par(cursor.par()->next());
975 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->next());
977 // we have to reset the selection, because the
978 // geometry could have changed
979 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
981 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
982 ClearSelection(bview);
984 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
985 tmpcursor.boundary());
989 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
991 Row * tmprow = cur.row();
992 int y = cur.y() - tmprow->baseline();
994 SetHeightOfRow(bview, tmprow);
996 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
998 LyXParagraph * first_phys_par = tmprow->par();
1000 // find the first row of the paragraph
1001 if (first_phys_par != tmprow->par())
1002 while (tmprow->previous()
1003 && tmprow->previous()->par() != first_phys_par) {
1004 tmprow = tmprow->previous();
1005 y -= tmprow->height();
1006 SetHeightOfRow(bview, tmprow);
1008 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
1009 tmprow = tmprow->previous();
1010 y -= tmprow->height();
1011 SetHeightOfRow(bview, tmprow);
1014 // we can set the refreshing parameters now
1015 status = LyXText::NEED_MORE_REFRESH;
1017 refresh_row = tmprow;
1018 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
1022 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
1024 Row * tmprow = cur.row();
1026 int y = cur.y() - tmprow->baseline();
1027 SetHeightOfRow(bview, tmprow);
1029 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
1031 LyXParagraph * first_phys_par = tmprow->par();
1033 // find the first row of the paragraph
1034 if (first_phys_par != tmprow->par())
1035 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
1036 tmprow = tmprow->previous();
1037 y -= tmprow->height();
1039 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
1040 tmprow = tmprow->previous();
1041 y -= tmprow->height();
1044 // we can set the refreshing parameters now
1045 if (status == LyXText::UNCHANGED || y < refresh_y) {
1047 refresh_row = tmprow;
1049 status = LyXText::NEED_MORE_REFRESH;
1050 SetCursor(bview, cur.par(), cur.pos());
1054 /* deletes and inserts again all paragaphs between the cursor
1055 * and the specified par
1056 * This function is needed after SetLayout and SetFont etc. */
1057 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
1058 LyXParagraph const * endpar) const
1061 LyXParagraph * tmppar = 0, * first_phys_par = 0;
1063 Row * tmprow = cur.row();
1065 int y = cur.y() - tmprow->baseline();
1067 if (!tmprow->previous()){
1068 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
1071 first_phys_par = tmprow->par()->FirstPhysicalPar();
1073 first_phys_par = tmprow->par();
1075 // find the first row of the paragraph
1076 if (first_phys_par != tmprow->par())
1077 while (tmprow->previous() &&
1078 (tmprow->previous()->par() != first_phys_par)) {
1079 tmprow = tmprow->previous();
1080 y -= tmprow->height();
1082 while (tmprow->previous()
1083 && tmprow->previous()->par() == first_phys_par) {
1084 tmprow = tmprow->previous();
1085 y -= tmprow->height();
1089 // we can set the refreshing parameters now
1090 status = LyXText::NEED_MORE_REFRESH;
1092 refresh_row = tmprow->previous(); /* the real refresh row will
1093 be deleted, so I store
1094 the previous here */
1097 tmppar = tmprow->next()->par();
1100 while (tmppar != endpar) {
1101 RemoveRow(tmprow->next());
1103 tmppar = tmprow->next()->par();
1108 // remove the first one
1109 tmprow2 = tmprow; /* this is because tmprow->previous()
1111 tmprow = tmprow->previous();
1114 tmppar = first_phys_par;
1118 InsertParagraph(bview, tmppar, tmprow);
1121 while (tmprow->next() && tmprow->next()->par() == tmppar)
1122 tmprow = tmprow->next();
1123 tmppar = tmppar->next();
1125 } while (tmppar != endpar);
1127 // this is because of layout changes
1129 refresh_y -= refresh_row->height();
1130 SetHeightOfRow(bview, refresh_row);
1132 refresh_row = firstrow;
1134 SetHeightOfRow(bview, refresh_row);
1137 if (tmprow && tmprow->next())
1138 SetHeightOfRow(bview, tmprow->next());
1142 bool LyXText::FullRebreak(BufferView * bview)
1148 if (need_break_row) {
1149 BreakAgain(bview, need_break_row);
1157 /* important for the screen */
1160 /* the cursor set functions have a special mechanism. When they
1161 * realize, that you left an empty paragraph, they will delete it.
1162 * They also delete the corresponding row */
1164 // need the selection cursor:
1165 void LyXText::SetSelection(BufferView * bview)
1167 const bool lsel = selection;
1170 last_sel_cursor = sel_cursor;
1171 sel_start_cursor = sel_cursor;
1172 sel_end_cursor = sel_cursor;
1177 // first the toggling area
1178 if (cursor.y() < last_sel_cursor.y()
1179 || (cursor.y() == last_sel_cursor.y()
1180 && cursor.x() < last_sel_cursor.x())) {
1181 toggle_end_cursor = last_sel_cursor;
1182 toggle_cursor = cursor;
1184 toggle_end_cursor = cursor;
1185 toggle_cursor = last_sel_cursor;
1188 last_sel_cursor = cursor;
1190 // and now the whole selection
1192 if (sel_cursor.par() == cursor.par())
1193 if (sel_cursor.pos() < cursor.pos()) {
1194 sel_end_cursor = cursor;
1195 sel_start_cursor = sel_cursor;
1197 sel_end_cursor = sel_cursor;
1198 sel_start_cursor = cursor;
1200 else if (sel_cursor.y() < cursor.y() ||
1201 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1202 sel_end_cursor = cursor;
1203 sel_start_cursor = sel_cursor;
1206 sel_end_cursor = sel_cursor;
1207 sel_start_cursor = cursor;
1210 // a selection with no contents is not a selection
1211 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1212 sel_start_cursor.pos() == sel_end_cursor.pos())
1215 if (inset_owner && (selection || lsel))
1216 inset_owner->SetUpdateStatus(bview, InsetText::SELECTION);
1220 string const LyXText::selectionAsString(Buffer const * buffer) const
1222 if (!selection) return string();
1225 // Special handling if the whole selection is within one paragraph
1226 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1227 result += sel_start_cursor.par()->String(buffer,
1228 sel_start_cursor.pos(),
1229 sel_end_cursor.pos());
1233 // The selection spans more than one paragraph
1235 // First paragraph in selection
1237 result += sel_start_cursor.par()->String(buffer,
1238 sel_start_cursor.pos(),
1239 sel_start_cursor.par()->Last())
1242 result += sel_start_cursor.par()->String(buffer,
1243 sel_start_cursor.pos(),
1244 sel_start_cursor.par()->size())
1248 // The paragraphs in between (if any)
1249 LyXCursor tmpcur(sel_start_cursor);
1250 tmpcur.par(tmpcur.par()->next());
1251 while (tmpcur.par() != sel_end_cursor.par()) {
1253 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1255 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->size()) + "\n\n";
1257 tmpcur.par(tmpcur.par()->next()); // Or NextAfterFootnote??
1260 // Last paragraph in selection
1261 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1267 void LyXText::ClearSelection(BufferView * /*bview*/) const
1274 void LyXText::CursorHome(BufferView * bview) const
1276 SetCursor(bview, cursor.par(), cursor.row()->pos());
1280 void LyXText::CursorEnd(BufferView * bview) const
1282 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1283 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1286 if (cursor.par()->Last() &&
1288 if (cursor.par()->size() &&
1290 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1291 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1292 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1294 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1299 void LyXText::CursorTop(BufferView * bview) const
1301 while (cursor.par()->previous())
1302 cursor.par(cursor.par()->previous());
1303 SetCursor(bview, cursor.par(), 0);
1307 void LyXText::CursorBottom(BufferView * bview) const
1309 while (cursor.par()->next())
1310 cursor.par(cursor.par()->next());
1312 SetCursor(bview, cursor.par(), cursor.par()->Last());
1314 SetCursor(bview, cursor.par(), cursor.par()->size());
1319 void LyXText::ToggleFree(BufferView * bview,
1320 LyXFont const & font, bool toggleall)
1322 // If the mask is completely neutral, tell user
1323 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1324 // Could only happen with user style
1325 bview->owner()->getLyXFunc()
1326 ->Dispatch(LFUN_MESSAGE,
1327 _("No font change defined. Use Character under the Layout menu to define font change."));
1331 // Try implicit word selection
1332 // If there is a change in the language the implicit word selection
1334 LyXCursor resetCursor = cursor;
1335 bool implicitSelection = (font.language() == ignore_language
1336 && font.number() == LyXFont::IGNORE)
1337 ? SelectWordWhenUnderCursor(bview) : false;
1340 SetFont(bview, font, toggleall);
1342 /* Implicit selections are cleared afterwards and cursor is set to the
1343 original position. */
1344 if (implicitSelection) {
1345 ClearSelection(bview);
1346 cursor = resetCursor;
1347 SetCursor(bview, cursor.par(), cursor.pos());
1348 sel_cursor = cursor;
1351 inset_owner->SetUpdateStatus(bview, InsetText::CURSOR_PAR);
1355 LyXParagraph::size_type
1356 LyXText::BeginningOfMainBody(Buffer const * buf,
1357 LyXParagraph const * par) const
1359 if (textclasslist.Style(buf->params.textclass,
1360 par->GetLayout()).labeltype != LABEL_MANUAL)
1363 return par->BeginningOfMainBody();
1368 /* if there is a selection, reset every environment you can find
1369 * in the selection, otherwise just the environment you are in */
1370 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1372 LyXParagraph * tmppar, * firsttmppar;
1374 ClearSelection(bview);
1376 /* is is only allowed, if the cursor is IN an open footnote.
1377 * Otherwise it is too dangerous */
1378 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1381 SetUndo(bview->buffer(), Undo::FINISH,
1382 cursor.par()->PreviousBeforeFootnote()->previous_,
1383 cursor.par()->NextAfterFootnote()->next_);
1385 /* ok, move to the beginning of the footnote. */
1386 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1387 cursor.par(cursor.par()->previous());
1389 SetCursor(bview, cursor.par(), cursor.par()->Last());
1390 /* this is just faster than using CursorLeft(); */
1392 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1393 tmppar = firsttmppar;
1394 /* tmppar is now the paragraph right before the footnote */
1396 bool first_footnote_par_is_not_empty = tmppar->next_->size();
1398 while (tmppar->next_
1399 && tmppar->next_->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1400 tmppar = tmppar->next_; /* I use next instead of Next(),
1401 * because there cannot be any
1402 * footnotes in a footnote
1404 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1406 /* remember the captions and empty paragraphs */
1407 if ((textclasslist.Style(bview->buffer()->params.textclass,
1408 tmppar->GetLayout())
1409 .labeltype == LABEL_SENSITIVE)
1411 tmppar->SetLayout(bview->buffer()->params, 0);
1414 // now we will paste the ex-footnote, if the layouts allow it
1415 // first restore the layout of the paragraph right behind
1418 tmppar->next_->MakeSameLayout(cursor.par());
1421 if (!tmppar->GetLayout()
1423 && (!tmppar->next()->Last()
1424 || tmppar->next()->HasSameLayout(tmppar)))) {
1425 if (tmppar->next()->Last()
1426 && tmppar->next()->IsLineSeparator(0))
1427 tmppar->next()->Erase(0);
1428 tmppar->PasteParagraph(bview->buffer()->params);
1431 tmppar = tmppar->next(); /* make sure tmppar cannot be touched
1432 * by the pasting of the beginning */
1434 /* then the beginning */
1435 /* if there is no space between the text and the footnote, so we insert
1437 * (only if the previous par and the footnotepar are not empty!) */
1438 if (!firsttmppar->next_->GetLayout()
1439 || firsttmppar->HasSameLayout(firsttmppar->next_)) {
1440 if (firsttmppar->size()
1441 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1442 && first_footnote_par_is_not_empty) {
1443 firsttmppar->next_->InsertChar(0, ' ');
1445 firsttmppar->PasteParagraph(bview->buffer()->params);
1448 /* now redo the paragaphs */
1449 RedoParagraphs(bview, cursor, tmppar);
1451 SetCursor(bview, cursor.par(), cursor.pos());
1453 /* sometimes it can happen, that there is a counter change */
1454 Row * row = cursor.row();
1455 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1457 UpdateCounters(bview, row);
1460 ClearSelection(bview);
1465 /* the DTP switches for paragraphs. LyX will store them in the
1466 * first physicla paragraph. When a paragraph is broken, the top settings
1467 * rest, the bottom settings are given to the new one. So I can make shure,
1468 * they do not duplicate themself and you cannnot make dirty things with
1471 void LyXText::SetParagraph(BufferView * bview,
1472 bool line_top, bool line_bottom,
1473 bool pagebreak_top, bool pagebreak_bottom,
1474 VSpace const & space_top,
1475 VSpace const & space_bottom,
1477 string labelwidthstring,
1480 LyXCursor tmpcursor = cursor;
1482 sel_start_cursor = cursor;
1483 sel_end_cursor = cursor;
1486 // make sure that the depth behind the selection are restored, too
1488 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
1490 LyXParagraph * endpar = sel_end_cursor.par()->next();
1492 LyXParagraph * undoendpar = endpar;
1494 if (endpar && endpar->GetDepth()) {
1495 while (endpar && endpar->GetDepth()) {
1497 endpar = endpar->LastPhysicalPar()->next();
1499 endpar = endpar->next();
1501 undoendpar = endpar;
1505 endpar = endpar->next(); // because of parindents etc.
1508 SetUndo(bview->buffer(), Undo::EDIT,
1511 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
1513 sel_start_cursor.par()->previous(),
1518 LyXParagraph * tmppar = sel_end_cursor.par();
1520 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->previous()) {
1521 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1523 while (tmppar != sel_start_cursor.par()->previous()) {
1524 SetCursor(bview, tmppar, 0);
1526 status = LyXText::NEED_MORE_REFRESH;
1527 refresh_row = cursor.row();
1528 refresh_y = cursor.y() - cursor.row()->baseline();
1530 if (cursor.par()->footnoteflag ==
1531 sel_start_cursor.par()->footnoteflag) {
1533 cursor.par()->params.lineTop(line_top);
1534 cursor.par()->params.lineBottom(line_bottom);
1535 cursor.par()->params.pagebreakTop(pagebreak_top);
1536 cursor.par()->params.pagebreakBottom(pagebreak_bottom);
1537 cursor.par()->params.spaceTop(space_top);
1538 cursor.par()->params.spaceBottom(space_bottom);
1539 // does the layout allow the new alignment?
1540 if (align == LYX_ALIGN_LAYOUT)
1541 align = textclasslist
1542 .Style(bview->buffer()->params.textclass,
1543 cursor.par()->GetLayout()).align;
1544 if (align & textclasslist
1545 .Style(bview->buffer()->params.textclass,
1546 cursor.par()->GetLayout()).alignpossible) {
1547 if (align == textclasslist
1548 .Style(bview->buffer()->params.textclass,
1549 cursor.par()->GetLayout()).align)
1550 cursor.par()->params.align(LYX_ALIGN_LAYOUT);
1552 cursor.par()->params.align(align);
1554 cursor.par()->SetLabelWidthString(labelwidthstring);
1555 cursor.par()->params.noindent(noindent);
1559 tmppar = cursor.par()->FirstPhysicalPar()->previous();
1561 tmppar = cursor.par()->previous();
1565 RedoParagraphs(bview, sel_start_cursor, endpar);
1567 ClearSelection(bview);
1568 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1569 sel_cursor = cursor;
1570 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1571 SetSelection(bview);
1572 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1574 bview->updateInset(inset_owner, true);
1579 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1580 string const & width,
1581 string const & widthp,
1582 int alignment, bool hfill,
1583 bool start_minipage)
1585 LyXCursor tmpcursor = cursor;
1586 LyXParagraph * tmppar;
1588 sel_start_cursor = cursor;
1589 sel_end_cursor = cursor;
1592 // make sure that the depth behind the selection are restored, too
1594 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
1596 LyXParagraph * endpar = sel_end_cursor.par()->next();
1598 LyXParagraph * undoendpar = endpar;
1600 if (endpar && endpar->GetDepth()) {
1601 while (endpar && endpar->GetDepth()) {
1603 endpar = endpar->LastPhysicalPar()->next();
1605 endpar = endpar->next();
1607 undoendpar = endpar;
1611 endpar = endpar->next(); // because of parindents etc.
1614 SetUndo(bview->buffer(), Undo::EDIT,
1617 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
1619 sel_start_cursor.par()->previous(),
1623 tmppar = sel_end_cursor.par();
1625 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->previous()) {
1626 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1628 while(tmppar != sel_start_cursor.par()->previous()) {
1629 SetCursor(bview, tmppar, 0);
1631 status = LyXText::NEED_MORE_REFRESH;
1632 refresh_row = cursor.row();
1633 refresh_y = cursor.y() - cursor.row()->baseline();
1635 if (cursor.par()->footnoteflag ==
1636 sel_start_cursor.par()->footnoteflag) {
1639 if (type == LyXParagraph::PEXTRA_NONE) {
1640 if (cursor.par()->params.pextraType() != LyXParagraph::PEXTRA_NONE) {
1641 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1642 cursor.par()->params.pextraType(LyXParagraph::PEXTRA_NONE);
1645 cursor.par()->SetPExtraType(bview->buffer()->params,
1646 type, width, widthp);
1647 cursor.par()->params.pextraHfill(hfill);
1648 cursor.par()->params.pextraStartMinipage(start_minipage);
1649 cursor.par()->params.pextraAlignment(alignment);
1654 tmppar = cursor.par()->FirstPhysicalPar()->previous();
1656 tmppar = cursor.par()->previous();
1659 RedoParagraphs(bview, sel_start_cursor, endpar);
1660 ClearSelection(bview);
1661 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1662 sel_cursor = cursor;
1663 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1664 SetSelection(bview);
1665 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1670 char loweralphaCounter(int n)
1672 if (n < 1 || n > 26)
1682 char alphaCounter(int n)
1684 if (n < 1 || n > 26)
1692 char hebrewCounter(int n)
1694 static const char hebrew[22] = {
1695 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1696 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1697 '÷', 'ø', 'ù', 'ú'
1699 if (n < 1 || n > 22)
1707 string const romanCounter(int n)
1709 static char const * roman[20] = {
1710 "i", "ii", "iii", "iv", "v",
1711 "vi", "vii", "viii", "ix", "x",
1712 "xi", "xii", "xiii", "xiv", "xv",
1713 "xvi", "xvii", "xviii", "xix", "xx"
1715 if (n < 1 || n > 20)
1724 // set the counter of a paragraph. This includes the labels
1725 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1728 // this is only relevant for the beginning of paragraph
1729 par = par->FirstPhysicalPar();
1731 LyXLayout const & layout =
1732 textclasslist.Style(buf->params.textclass,
1735 LyXTextClass const & textclass =
1736 textclasslist.TextClass(buf->params.textclass);
1738 /* copy the prev-counters to this one, unless this is the start of a
1739 footnote or of a bibliography or the very first paragraph */
1742 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1743 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1744 && par->footnotekind == LyXParagraph::FOOTNOTE)
1746 && !(textclasslist.Style(buf->params.textclass,
1747 par->previous()->GetLayout()
1748 ).labeltype != LABEL_BIBLIO
1749 && layout.labeltype == LABEL_BIBLIO)) {
1750 for (int i = 0; i < 10; ++i) {
1751 par->setCounter(i, par->previous()->GetFirstCounter(i));
1754 par->params.appendix(par->previous()->FirstPhysicalPar()->params.appendix());
1756 par->params.appendix(par->previous()->params.appendix());
1758 if (!par->params.appendix() && par->params.startOfAppendix()) {
1759 par->params.appendix(true);
1760 for (int i = 0; i < 10; ++i) {
1761 par->setCounter(i, 0);
1765 par->enumdepth = par->previous()->FirstPhysicalPar()->enumdepth;
1766 par->itemdepth = par->previous()->FirstPhysicalPar()->itemdepth;
1768 par->enumdepth = par->previous()->enumdepth;
1769 par->itemdepth = par->previous()->itemdepth;
1772 for (int i = 0; i < 10; ++i) {
1773 par->setCounter(i, 0);
1775 par->params.appendix(par->params.startOfAppendix());
1781 // if this is an open marginnote and this is the first
1782 // entry in the marginnote and the enclosing
1783 // environment is an enum/item then correct for the
1784 // LaTeX behaviour (ARRae)
1785 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1786 && par->footnotekind == LyXParagraph::MARGIN
1788 && par->previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1789 && (par->PreviousBeforeFootnote()
1790 && textclasslist.Style(buf->params.textclass,
1791 par->PreviousBeforeFootnote()->GetLayout()
1792 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1793 // Any itemize or enumerate environment in a marginnote
1794 // that is embedded in an itemize or enumerate
1795 // paragraph is seen by LaTeX as being at a deeper
1796 // level within that enclosing itemization/enumeration
1797 // even if there is a "standard" layout at the start of
1803 /* Maybe we have to increment the enumeration depth.
1804 * BUT, enumeration in a footnote is considered in isolation from its
1805 * surrounding paragraph so don't increment if this is the
1806 * first line of the footnote
1807 * AND, bibliographies can't have their depth changed ie. they
1808 * are always of depth 0
1811 && par->previous()->GetDepth() < par->GetDepth()
1812 && textclasslist.Style(buf->params.textclass,
1813 par->previous()->GetLayout()
1814 ).labeltype == LABEL_COUNTER_ENUMI
1815 && par->enumdepth < 3
1817 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1818 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1819 && par->footnotekind == LyXParagraph::FOOTNOTE)
1821 && layout.labeltype != LABEL_BIBLIO) {
1825 /* Maybe we have to decrement the enumeration depth, see note above */
1827 && par->previous()->GetDepth() > par->GetDepth()
1829 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1830 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1831 && par->footnotekind == LyXParagraph::FOOTNOTE)
1833 && layout.labeltype != LABEL_BIBLIO) {
1834 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1835 par->setCounter(6 + par->enumdepth,
1836 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1837 /* reset the counters.
1838 * A depth change is like a breaking layout
1840 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1841 par->setCounter(i, 0);
1844 if (!par->params.labelString().empty()) {
1845 par->params.labelString(string());
1848 if (layout.margintype == MARGIN_MANUAL) {
1849 if (par->params.labelWidthString().empty()) {
1850 par->SetLabelWidthString(layout.labelstring());
1853 par->SetLabelWidthString(string());
1856 /* is it a layout that has an automatic label ? */
1857 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1859 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1860 if (i >= 0 && i<= buf->params.secnumdepth) {
1861 par->incCounter(i); // increment the counter
1863 // Is there a label? Useful for Chapter layout
1864 if (!par->params.appendix()) {
1865 if (!layout.labelstring().empty())
1866 par->params.labelString(layout.labelstring());
1868 par->params.labelString(string());
1870 if (!layout.labelstring_appendix().empty())
1871 par->params.labelString(layout.labelstring_appendix());
1873 par->params.labelString(string());
1876 std::ostringstream s;
1878 if (!par->params.appendix()) {
1879 switch (2 * LABEL_COUNTER_CHAPTER -
1880 textclass.maxcounter() + i) {
1881 case LABEL_COUNTER_CHAPTER:
1882 s << par->getCounter(i);
1884 case LABEL_COUNTER_SECTION:
1885 s << par->getCounter(i - 1) << '.'
1886 << par->getCounter(i);
1888 case LABEL_COUNTER_SUBSECTION:
1889 s << par->getCounter(i - 2) << '.'
1890 << par->getCounter(i - 1) << '.'
1891 << par->getCounter(i);
1893 case LABEL_COUNTER_SUBSUBSECTION:
1894 s << par->getCounter(i - 3) << '.'
1895 << par->getCounter(i - 2) << '.'
1896 << par->getCounter(i - 1) << '.'
1897 << par->getCounter(i);
1900 case LABEL_COUNTER_PARAGRAPH:
1901 s << par->getCounter(i - 4) << '.'
1902 << par->getCounter(i - 3) << '.'
1903 << par->getCounter(i - 2) << '.'
1904 << par->getCounter(i - 1) << '.'
1905 << par->getCounter(i);
1907 case LABEL_COUNTER_SUBPARAGRAPH:
1908 s << par->getCounter(i - 5) << '.'
1909 << par->getCounter(i - 4) << '.'
1910 << par->getCounter(i - 3) << '.'
1911 << par->getCounter(i - 2) << '.'
1912 << par->getCounter(i - 1) << '.'
1913 << par->getCounter(i);
1917 // Can this ever be reached? And in the
1918 // case it is, how can this be correct?
1920 s << par->getCounter(i) << '.';
1923 } else { // appendix
1924 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1925 case LABEL_COUNTER_CHAPTER:
1926 if (par->isRightToLeftPar(buf->params))
1927 s << hebrewCounter(par->getCounter(i));
1929 s << alphaCounter(par->getCounter(i));
1931 case LABEL_COUNTER_SECTION:
1932 if (par->isRightToLeftPar(buf->params))
1933 s << hebrewCounter(par->getCounter(i - 1));
1935 s << alphaCounter(par->getCounter(i - 1));
1938 << par->getCounter(i);
1941 case LABEL_COUNTER_SUBSECTION:
1942 if (par->isRightToLeftPar(buf->params))
1943 s << hebrewCounter(par->getCounter(i - 2));
1945 s << alphaCounter(par->getCounter(i - 2));
1948 << par->getCounter(i-1) << '.'
1949 << par->getCounter(i);
1952 case LABEL_COUNTER_SUBSUBSECTION:
1953 if (par->isRightToLeftPar(buf->params))
1954 s << hebrewCounter(par->getCounter(i-3));
1956 s << alphaCounter(par->getCounter(i-3));
1959 << par->getCounter(i-2) << '.'
1960 << par->getCounter(i-1) << '.'
1961 << par->getCounter(i);
1964 case LABEL_COUNTER_PARAGRAPH:
1965 if (par->isRightToLeftPar(buf->params))
1966 s << hebrewCounter(par->getCounter(i-4));
1968 s << alphaCounter(par->getCounter(i-4));
1971 << par->getCounter(i-3) << '.'
1972 << par->getCounter(i-2) << '.'
1973 << par->getCounter(i-1) << '.'
1974 << par->getCounter(i);
1977 case LABEL_COUNTER_SUBPARAGRAPH:
1978 if (par->isRightToLeftPar(buf->params))
1979 s << hebrewCounter(par->getCounter(i-5));
1981 s << alphaCounter(par->getCounter(i-5));
1984 << par->getCounter(i-4) << '.'
1985 << par->getCounter(i-3) << '.'
1986 << par->getCounter(i-2) << '.'
1987 << par->getCounter(i-1) << '.'
1988 << par->getCounter(i);
1992 // Can this ever be reached? And in the
1993 // case it is, how can this be correct?
1995 s << par->getCounter(i) << '.';
2001 par->params.labelString(par->params.labelString() +s.str().c_str());
2002 // We really want to remove the c_str as soon as
2005 for (i++; i < 10; ++i) {
2006 // reset the following counters
2007 par->setCounter(i, 0);
2009 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
2010 for (i++; i < 10; ++i) {
2011 // reset the following counters
2012 par->setCounter(i, 0);
2014 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
2015 par->incCounter(i + par->enumdepth);
2016 int number = par->getCounter(i + par->enumdepth);
2018 std::ostringstream s;
2020 switch (par->enumdepth) {
2022 if (par->isRightToLeftPar(buf->params))
2024 << hebrewCounter(number)
2028 << loweralphaCounter(number)
2032 if (par->isRightToLeftPar(buf->params))
2033 s << '.' << romanCounter(number);
2035 s << romanCounter(number) << '.';
2038 if (par->isRightToLeftPar(buf->params))
2040 << alphaCounter(number);
2042 s << alphaCounter(number)
2046 if (par->isRightToLeftPar(buf->params))
2053 par->params.labelString(s.str().c_str());
2054 // we really want to get rid of that c_str()
2056 for (i += par->enumdepth + 1; i < 10; ++i)
2057 par->setCounter(i, 0); /* reset the following counters */
2060 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2061 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2063 int number = par->getCounter(i);
2065 InsetCommandParams p( "bibitem" );
2066 par->bibkey = new InsetBibKey(p);
2068 par->bibkey->setCounter(number);
2069 par->params.labelString(layout.labelstring());
2071 // In biblio should't be following counters but...
2073 string s = layout.labelstring();
2075 // the caption hack:
2076 if (layout.labeltype == LABEL_SENSITIVE) {
2077 bool isOK (par->InInset() && par->InInset()->owner() &&
2078 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2080 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2081 && (par->footnotekind == LyXParagraph::FIG
2082 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2083 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2084 ? ":øåéà " : "Figure:";
2085 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2086 && (par->footnotekind == LyXParagraph::TAB
2087 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2088 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2089 ? ":äìáè" : "Table:";
2090 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2091 && par->footnotekind == LyXParagraph::ALGORITHM) {
2092 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2093 ? ":Ãúéøåâìà " : "Algorithm:";
2097 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2099 = floatList.getType(tmp->type());
2100 // We should get the correct number here too.
2101 s = fl.name() + " #:";
2103 /* par->SetLayout(0);
2104 s = layout->labelstring; */
2105 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2106 ? " :úåòîùî øñç" : "Senseless: ";
2109 par->params.labelString(s);
2111 /* reset the enumeration counter. They are always resetted
2112 * when there is any other layout between */
2113 for (int i = 6 + par->enumdepth; i < 10; ++i)
2114 par->setCounter(i, 0);
2119 /* Updates all counters BEHIND the row. Changed paragraphs
2120 * with a dynamic left margin will be rebroken. */
2121 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2128 } else if (row->par()->next_
2129 && row->par()->next_->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
2130 par = row->par()->LastPhysicalPar()->next();
2132 par = row->par()->next_;
2139 par = row->par()->next();
2144 while (row->par() != par)
2147 SetCounter(bview->buffer(), par);
2149 /* now check for the headline layouts. remember that they
2150 * have a dynamic left margin */
2155 ( textclasslist.Style(bview->buffer()->params.textclass,
2156 par->layout).margintype == MARGIN_DYNAMIC
2157 || textclasslist.Style(bview->buffer()->params.textclass,
2158 par->layout).labeltype == LABEL_SENSITIVE)
2161 /* Rebreak the paragraph */
2162 RemoveParagraph(row);
2163 AppendParagraph(bview, row);
2166 /* think about the damned open footnotes! */
2167 while (par->next() &&
2168 (par->next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2169 || par->next()->IsDummy())){
2171 if (par->IsDummy()) {
2172 while (row->par() != par)
2174 RemoveParagraph(row);
2175 AppendParagraph(bview, row);
2181 par = par->LastPhysicalPar()->next();
2190 /* insets an inset. */
2191 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2193 if (!cursor.par()->InsertInsetAllowed(inset))
2195 SetUndo(bview->buffer(), Undo::INSERT,
2197 cursor.par()->ParFromPos(cursor.pos())->previous_,
2198 cursor.par()->ParFromPos(cursor.pos())->next_
2200 cursor.par()->previous(),
2201 cursor.par()->next()
2204 cursor.par()->InsertInset(cursor.pos(), inset);
2205 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2206 * The character will not be inserted a
2209 // If we enter a highly editable inset the cursor should be to before
2210 // the inset. This couldn't happen before as Undo was not handled inside
2211 // inset now after the Undo LyX tries to call inset->Edit(...) again
2212 // and cannot do this as the cursor is behind the inset and GetInset
2213 // does not return the inset!
2214 if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
2215 CursorLeft(bview, true);
2221 void LyXText::copyEnvironmentType()
2223 copylayouttype = cursor.par()->GetLayout();
2227 void LyXText::pasteEnvironmentType(BufferView * bview)
2229 SetLayout(bview, copylayouttype);
2233 void LyXText::CutSelection(BufferView * bview, bool doclear)
2235 // Stuff what we got on the clipboard. Even if there is no selection.
2237 // There is a problem with having the stuffing here in that the
2238 // larger the selection the slower LyX will get. This can be
2239 // solved by running the line below only when the selection has
2240 // finished. The solution used currently just works, to make it
2241 // faster we need to be more clever and probably also have more
2242 // calls to stuffClipboard. (Lgb)
2243 bview->stuffClipboard(selectionAsString(bview->buffer()));
2245 // This doesn't make sense, if there is no selection
2249 // OK, we have a selection. This is always between sel_start_cursor
2250 // and sel_end_cursor
2252 // Check whether there are half footnotes in the selection
2253 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2254 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2255 LyXParagraph * tmppar = sel_start_cursor.par();
2256 while (tmppar != sel_end_cursor.par()){
2257 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2258 WriteAlert(_("Impossible operation"),
2259 _("Don't know what to do with half floats."),
2263 tmppar = tmppar->next();
2268 // make sure that the depth behind the selection are restored, too
2270 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
2272 LyXParagraph * endpar = sel_end_cursor.par()->next();
2274 LyXParagraph * undoendpar = endpar;
2276 if (endpar && endpar->GetDepth()) {
2277 while (endpar && endpar->GetDepth()) {
2279 endpar = endpar->LastPhysicalPar()->next();
2281 endpar = endpar->next();
2283 undoendpar = endpar;
2285 } else if (endpar) {
2286 endpar = endpar->next(); // because of parindents etc.
2289 SetUndo(bview->buffer(), Undo::DELETE,
2292 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
2294 sel_start_cursor.par()->previous(),
2300 // there are two cases: cut only within one paragraph or
2301 // more than one paragraph
2303 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2304 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2306 if (sel_start_cursor.par() == sel_end_cursor.par())
2309 // only within one paragraph
2310 endpar = sel_start_cursor.par();
2311 int pos = sel_end_cursor.pos();
2312 cap.cutSelection(sel_start_cursor.par(), &endpar,
2313 sel_start_cursor.pos(), pos,
2314 bview->buffer()->params.textclass, doclear);
2315 sel_end_cursor.pos(pos);
2317 endpar = sel_end_cursor.par();
2319 int pos = sel_end_cursor.pos();
2320 cap.cutSelection(sel_start_cursor.par(), &endpar,
2321 sel_start_cursor.pos(), pos,
2322 bview->buffer()->params.textclass, doclear);
2324 sel_end_cursor.par(endpar);
2325 sel_end_cursor.pos(pos);
2326 cursor.pos(sel_end_cursor.pos());
2328 endpar = endpar->next();
2330 // sometimes necessary
2332 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2334 RedoParagraphs(bview, sel_start_cursor, endpar);
2336 ClearSelection(bview);
2337 cursor = sel_start_cursor;
2338 SetCursor(bview, cursor.par(), cursor.pos());
2339 sel_cursor = cursor;
2340 UpdateCounters(bview, cursor.row());
2344 void LyXText::CopySelection(BufferView * bview)
2346 // Stuff what we got on the clipboard. Even if there is no selection.
2348 // There is a problem with having the stuffing here in that the
2349 // larger the selection the slower LyX will get. This can be
2350 // solved by running the line below only when the selection has
2351 // finished. The solution used currently just works, to make it
2352 // faster we need to be more clever and probably also have more
2353 // calls to stuffClipboard. (Lgb)
2354 bview->stuffClipboard(selectionAsString(bview->buffer()));
2356 // this doesnt make sense, if there is no selection
2360 // ok we have a selection. This is always between sel_start_cursor
2361 // and sel_end cursor
2364 /* check wether there are half footnotes in the selection */
2365 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2366 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2367 LyXParagraph * tmppar = sel_start_cursor.par();
2368 while (tmppar != sel_end_cursor.par()) {
2369 if (tmppar->footnoteflag !=
2370 sel_end_cursor.par()->footnoteflag) {
2371 WriteAlert(_("Impossible operation"),
2372 _("Don't know what to do"
2373 " with half floats."),
2377 tmppar = tmppar->next();
2382 // copy behind a space if there is one
2384 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2386 while (sel_start_cursor.par()->size() > sel_start_cursor.pos()
2388 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2389 && (sel_start_cursor.par() != sel_end_cursor.par()
2390 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2391 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2395 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2396 sel_start_cursor.pos(), sel_end_cursor.pos(),
2397 bview->buffer()->params.textclass);
2401 void LyXText::PasteSelection(BufferView * bview)
2405 // this does not make sense, if there is nothing to paste
2406 if (!cap.checkPastePossible(cursor.par()))
2409 SetUndo(bview->buffer(), Undo::INSERT,
2411 cursor.par()->ParFromPos(cursor.pos())->previous_,
2412 cursor.par()->ParFromPos(cursor.pos())->next_
2414 cursor.par()->previous(),
2415 cursor.par()->next()
2419 LyXParagraph * endpar;
2420 LyXParagraph * actpar = cursor.par();
2422 int pos = cursor.pos();
2423 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2425 RedoParagraphs(bview, cursor, endpar);
2427 SetCursor(bview, cursor.par(), cursor.pos());
2428 ClearSelection(bview);
2430 sel_cursor = cursor;
2431 SetCursor(bview, actpar, pos);
2432 SetSelection(bview);
2433 UpdateCounters(bview, cursor.row());
2437 // returns a pointer to the very first LyXParagraph
2438 LyXParagraph * LyXText::FirstParagraph() const
2440 return OwnerParagraph();
2444 // sets the selection over the number of characters of string, no check!!
2445 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2447 sel_cursor = cursor;
2448 for (int i = 0; str[i]; ++i)
2450 SetSelection(bview);
2454 // simple replacing. The font of the first selected character is used
2455 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2458 SetCursorParUndo(bview->buffer());
2461 if (!selection) { // create a dummy selection
2462 sel_end_cursor = cursor;
2463 sel_start_cursor = cursor;
2466 // Get font setting before we cut
2467 LyXParagraph::size_type pos = sel_end_cursor.pos();
2468 LyXFont const font = sel_start_cursor.par()
2469 ->GetFontSettings(bview->buffer()->params,
2470 sel_start_cursor.pos());
2472 // Insert the new string
2473 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2474 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2478 // Cut the selection
2479 CutSelection(bview);
2485 // needed to insert the selection
2486 void LyXText::InsertStringA(BufferView * bview, string const & str)
2488 LyXParagraph * par = cursor.par();
2489 LyXParagraph::size_type pos = cursor.pos();
2490 LyXParagraph::size_type a = 0;
2491 LyXParagraph * endpar = cursor.par()->next();
2493 SetCursorParUndo(bview->buffer());
2496 textclasslist.Style(bview->buffer()->params.textclass,
2497 cursor.par()->GetLayout()).isEnvironment();
2498 // only to be sure, should not be neccessary
2499 ClearSelection(bview);
2501 // insert the string, don't insert doublespace
2502 string::size_type i = 0;
2503 while (i < str.length()) {
2504 if (str[i] != '\n') {
2506 && i + 1 < str.length() && str[i + 1] != ' '
2507 && pos && par->GetChar(pos - 1)!= ' ') {
2508 par->InsertChar(pos, ' ', current_font);
2510 } else if (str[i] == ' ') {
2511 InsetSpecialChar * new_inset =
2512 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2513 if (par->InsertInsetAllowed(new_inset)) {
2514 par->InsertInset(pos, new_inset,
2520 } else if (str[i] == '\t') {
2521 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2522 InsetSpecialChar * new_inset =
2523 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2524 if (par->InsertInsetAllowed(new_inset)) {
2525 par->InsertInset(pos, new_inset,
2532 } else if (str[i] != 13 &&
2533 // Ignore unprintables
2534 (str[i] & 127) >= ' ') {
2535 par->InsertChar(pos, str[i], current_font);
2539 if (!par->size()) { // par is empty
2540 InsetSpecialChar * new_inset =
2541 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2542 if (par->InsertInsetAllowed(new_inset)) {
2543 par->InsertInset(pos,
2551 par->BreakParagraph(bview->buffer()->params, pos, flag);
2558 RedoParagraphs(bview, cursor, endpar);
2559 SetCursor(bview, cursor.par(), cursor.pos());
2560 sel_cursor = cursor;
2561 SetCursor(bview, par, pos);
2562 SetSelection(bview);
2566 /* turns double-CR to single CR, others where converted into one blank and 13s
2567 * that are ignored .Double spaces are also converted into one. Spaces at
2568 * the beginning of a paragraph are forbidden. tabs are converted into one
2569 * space. then InsertStringA is called */
2570 void LyXText::InsertStringB(BufferView * bview, string const & s)
2573 string::size_type i = 1;
2574 while (i < str.length()) {
2577 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2579 if (str[i] == '\n' && i + 1 < str.length()) {
2580 if (str[i + 1] != '\n') {
2581 if (str[i - 1] != ' ')
2586 while (i + 1 < str.length()
2587 && (str[i + 1] == ' '
2588 || str[i + 1] == '\t'
2589 || str[i + 1] == '\n'
2590 || str[i + 1] == 13)) {
2597 InsertStringA(bview, str);
2601 bool LyXText::GotoNextInset(BufferView * bview,
2602 std::vector<Inset::Code> const & codes,
2603 string const & contents) const
2605 LyXCursor res = cursor;
2609 if (res.pos() < res.par()->Last() - 1) {
2611 if (res.pos() < res.par()->size() - 1) {
2613 res.pos(res.pos() + 1);
2615 res.par(res.par()->next());
2619 } while (res.par() &&
2620 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2621 && (inset = res.par()->GetInset(res.pos())) != 0
2622 && find(codes.begin(), codes.end(), inset->LyxCode())
2624 && (contents.empty() ||
2625 static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
2629 SetCursor(bview, res.par(), res.pos());
2636 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2637 LyXParagraph::size_type pos)
2639 LyXCursor tmpcursor;
2642 LyXParagraph::size_type z;
2643 Row * row = GetRow(par, pos, y);
2645 // is there a break one row above
2646 if (row->previous() && row->previous()->par() == row->par()) {
2647 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2648 if (z >= row->pos()) {
2649 // set the dimensions of the row above
2650 y -= row->previous()->height();
2652 refresh_row = row->previous();
2653 status = LyXText::NEED_MORE_REFRESH;
2655 BreakAgain(bview, row->previous());
2657 // set the cursor again. Otherwise
2658 // dangling pointers are possible
2659 SetCursor(bview, cursor.par(), cursor.pos(),
2660 false, cursor.boundary());
2661 sel_cursor = cursor;
2666 int const tmpheight = row->height();
2667 LyXParagraph::size_type const tmplast = RowLast(row);
2671 BreakAgain(bview, row);
2672 if (row->height() == tmpheight && RowLast(row) == tmplast)
2673 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2675 status = LyXText::NEED_MORE_REFRESH;
2677 // check the special right address boxes
2678 if (textclasslist.Style(bview->buffer()->params.textclass,
2679 par->GetLayout()).margintype
2680 == MARGIN_RIGHT_ADDRESS_BOX) {
2687 RedoDrawingOfParagraph(bview, tmpcursor);
2690 // set the cursor again. Otherwise dangling pointers are possible
2691 // also set the selection
2695 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2696 false, sel_cursor.boundary());
2697 sel_cursor = cursor;
2698 SetCursorIntern(bview, sel_start_cursor.par(),
2699 sel_start_cursor.pos(),
2700 false, sel_start_cursor.boundary());
2701 sel_start_cursor = cursor;
2702 SetCursorIntern(bview, sel_end_cursor.par(),
2703 sel_end_cursor.pos(),
2704 false, sel_end_cursor.boundary());
2705 sel_end_cursor = cursor;
2706 SetCursorIntern(bview, last_sel_cursor.par(),
2707 last_sel_cursor.pos(),
2708 false, last_sel_cursor.boundary());
2709 last_sel_cursor = cursor;
2712 SetCursorIntern(bview, cursor.par(), cursor.pos(),
2713 false, cursor.boundary());
2717 // returns false if inset wasn't found
2718 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2720 // first check the current paragraph
2721 int pos = cursor.par()->GetPositionOfInset(inset);
2723 CheckParagraph(bview, cursor.par(), pos);
2727 // check every paragraph
2729 LyXParagraph * par = FirstParagraph();
2732 // make sure the paragraph is open
2733 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2735 pos = par->GetPositionOfInset(inset);
2737 CheckParagraph(bview, par, pos);
2750 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2751 LyXParagraph::size_type pos,
2752 bool setfont, bool boundary) const
2754 LyXCursor old_cursor = cursor;
2755 SetCursorIntern(bview, par, pos, setfont, boundary);
2756 DeleteEmptyParagraphMechanism(bview, old_cursor);
2760 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2761 LyXParagraph::size_type pos, bool boundary) const
2764 // correct the cursor position if impossible
2765 if (pos > par->Last()){
2766 LyXParagraph * tmppar = par->ParFromPos(pos);
2767 pos = par->PositionInParFromPos(pos);
2770 if (par->IsDummy() && par->previous_ &&
2771 par->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2772 while (par->previous_ &&
2773 ((par->previous_->IsDummy() &&
2774 (par->previous_->previous_->footnoteflag ==
2775 LyXParagraph::CLOSED_FOOTNOTE)) ||
2776 (par->previous_->footnoteflag ==
2777 LyXParagraph::CLOSED_FOOTNOTE))) {
2778 par = par->previous_;
2779 if (par->IsDummy() &&
2780 (par->previous_->footnoteflag ==
2781 LyXParagraph::CLOSED_FOOTNOTE))
2782 pos += par->size() + 1;
2784 if (par->previous_) {
2785 par = par->previous_;
2787 pos += par->size() + 1;
2792 cur.boundary(boundary);
2794 /* get the cursor y position in text */
2796 Row * row = GetRow(par, pos, y);
2797 /* y is now the beginning of the cursor row */
2798 y += row->baseline();
2799 /* y is now the cursor baseline */
2802 /* now get the cursors x position */
2804 float fill_separator, fill_hfill, fill_label_hfill;
2805 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2807 LyXParagraph::size_type cursor_vpos = 0;
2808 LyXParagraph::size_type last = RowLastPrintable(row);
2810 if (pos > last + 1) // This shouldn't happen.
2812 else if (pos < row->pos())
2815 if (last < row->pos())
2816 cursor_vpos = row->pos();
2817 else if (pos > last && !boundary)
2818 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2819 ? row->pos() : last + 1;
2820 else if (pos > row->pos() &&
2821 (pos > last || boundary))
2822 /// Place cursor after char at (logical) position pos - 1
2823 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2824 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2826 /// Place cursor before char at (logical) position pos
2827 cursor_vpos = (bidi_level(pos) % 2 == 0)
2828 ? log2vis(pos) : log2vis(pos) + 1;
2830 LyXParagraph::size_type main_body =
2831 BeginningOfMainBody(bview->buffer(), row->par());
2832 if ((main_body > 0) &&
2833 ((main_body-1 > last) ||
2834 !row->par()->IsLineSeparator(main_body-1)))
2837 for (LyXParagraph::size_type vpos = row->pos();
2838 vpos < cursor_vpos; ++vpos) {
2839 pos = vis2log(vpos);
2840 if (main_body > 0 && pos == main_body - 1) {
2841 x += fill_label_hfill +
2842 lyxfont::width(textclasslist.Style(
2843 bview->buffer()->params.textclass,
2844 row->par()->GetLayout())
2846 GetFont(bview->buffer(), row->par(), -2));
2847 if (row->par()->IsLineSeparator(main_body-1))
2848 x -= SingleWidth(bview, row->par(),main_body-1);
2850 if (HfillExpansion(bview->buffer(), row, pos)) {
2851 x += SingleWidth(bview, row->par(), pos);
2852 if (pos >= main_body)
2855 x += fill_label_hfill;
2856 } else if (row->par()->IsSeparator(pos)) {
2857 x += SingleWidth(bview, row->par(), pos);
2858 if (pos >= main_body)
2859 x += fill_separator;
2861 x += SingleWidth(bview, row->par(), pos);
2870 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2871 LyXParagraph::size_type pos,
2872 bool setfont, bool boundary) const
2874 SetCursor(bview, cursor, par, pos, boundary);
2876 SetCurrentFont(bview);
2880 void LyXText::SetCurrentFont(BufferView * bview) const
2882 LyXParagraph::size_type pos = cursor.pos();
2883 if (cursor.boundary() && pos > 0)
2888 if (pos == cursor.par()->Last())
2890 if (pos == cursor.par()->size())
2893 else if (cursor.par()->IsSeparator(pos)) {
2894 if (pos > cursor.row()->pos() &&
2895 bidi_level(pos) % 2 ==
2896 bidi_level(pos - 1) % 2)
2899 else if (pos + 1 < cursor.par()->Last())
2901 else if (pos + 1 < cursor.par()->size())
2908 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2909 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2912 if (cursor.pos() == cursor.par()->Last() &&
2914 if (cursor.pos() == cursor.par()->size() &&
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 current_font.setNumber(LyXFont::OFF);
2922 real_current_font.setLanguage(lang);
2923 real_current_font.setNumber(LyXFont::OFF);
2928 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2930 LyXCursor old_cursor = cursor;
2932 /* get the row first */
2934 Row * row = GetRowNearY(y);
2935 cursor.par(row->par());
2938 int column = GetColumnNearX(bview, row, x, bound);
2939 cursor.pos(row->pos() + column);
2941 cursor.y(y + row->baseline());
2943 cursor.boundary(bound);
2944 SetCurrentFont(bview);
2945 DeleteEmptyParagraphMechanism(bview, old_cursor);
2949 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2952 /* get the row first */
2954 Row * row = GetRowNearY(y);
2956 int column = GetColumnNearX(bview, row, x, bound);
2958 cur.par(row->par());
2959 cur.pos(row->pos() + column);
2961 cur.y(y + row->baseline());
2963 cur.boundary(bound);
2967 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2969 if (cursor.pos() > 0) {
2970 bool boundary = cursor.boundary();
2971 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2972 if (!internal && !boundary &&
2973 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2974 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2975 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2976 LyXParagraph * par = cursor.par()->previous();
2978 SetCursor(bview, par, par->Last());
2980 SetCursor(bview, par, par->size());
2986 void LyXText::CursorRight(BufferView * bview, bool internal) const
2988 if (!internal && cursor.boundary() &&
2989 !cursor.par()->IsNewline(cursor.pos()))
2990 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2992 else if (cursor.pos() < cursor.par()->Last()) {
2994 else if (cursor.pos() < cursor.par()->size()) {
2996 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2998 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2999 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3000 } else if (cursor.par()->next())
3001 SetCursor(bview, cursor.par()->next(), 0);
3005 void LyXText::CursorUp(BufferView * bview) const
3007 SetCursorFromCoordinates(bview, cursor.x_fix(),
3008 cursor.y() - cursor.row()->baseline() - 1);
3012 void LyXText::CursorDown(BufferView * bview) const
3014 SetCursorFromCoordinates(bview, cursor.x_fix(),
3015 cursor.y() - cursor.row()->baseline()
3016 + cursor.row()->height() + 1);
3020 void LyXText::CursorUpParagraph(BufferView * bview) const
3022 if (cursor.pos() > 0) {
3023 SetCursor(bview, cursor.par(), 0);
3025 else if (cursor.par()->previous()) {
3026 SetCursor(bview, cursor.par()->previous(), 0);
3031 void LyXText::CursorDownParagraph(BufferView * bview) const
3033 if (cursor.par()->next()) {
3034 SetCursor(bview, cursor.par()->next(), 0);
3037 SetCursor(bview, cursor.par(), cursor.par()->Last());
3039 SetCursor(bview, cursor.par(), cursor.par()->size());
3045 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3046 LyXCursor const & old_cursor) const
3048 // Would be wrong to delete anything if we have a selection.
3049 if (selection) return;
3051 // We allow all kinds of "mumbo-jumbo" when freespacing.
3052 if (textclasslist.Style(bview->buffer()->params.textclass,
3053 old_cursor.par()->GetLayout()).free_spacing)
3056 bool deleted = false;
3058 /* Ok I'll put some comments here about what is missing.
3059 I have fixed BackSpace (and thus Delete) to not delete
3060 double-spaces automagically. I have also changed Cut,
3061 Copy and Paste to hopefully do some sensible things.
3062 There are still some small problems that can lead to
3063 double spaces stored in the document file or space at
3064 the beginning of paragraphs. This happens if you have
3065 the cursor betwenn to spaces and then save. Or if you
3066 cut and paste and the selection have a space at the
3067 beginning and then save right after the paste. I am
3068 sure none of these are very hard to fix, but I will
3069 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3070 that I can get some feedback. (Lgb)
3073 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3074 // delete the LineSeparator.
3077 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3078 // delete the LineSeparator.
3081 // If the pos around the old_cursor were spaces, delete one of them.
3082 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3083 // Only if the cursor has really moved
3085 if (old_cursor.pos() > 0
3087 && old_cursor.pos() < old_cursor.par()->Last()
3089 && old_cursor.pos() < old_cursor.par()->size()
3091 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3092 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3093 old_cursor.par()->Erase(old_cursor.pos() - 1);
3094 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3096 if (old_cursor.par() == cursor.par() &&
3097 cursor.pos() > old_cursor.pos()) {
3098 SetCursorIntern(bview, cursor.par(),
3101 SetCursorIntern(bview, cursor.par(),
3107 // Do not delete empty paragraphs with keepempty set.
3108 if ((textclasslist.Style(bview->buffer()->params.textclass,
3109 old_cursor.par()->GetLayout())).keepempty)
3112 LyXCursor tmpcursor;
3115 if (old_cursor.par() != cursor.par()) {
3116 if ((old_cursor.par()->Last() == 0
3117 || (old_cursor.par()->Last() == 1
3118 && old_cursor.par()->IsLineSeparator(0)))
3119 && old_cursor.par()->FirstPhysicalPar()
3120 == old_cursor.par()->LastPhysicalPar()
3122 if (old_cursor.par() != cursor.par()) {
3123 if ((old_cursor.par()->size() == 0
3124 || (old_cursor.par()->size() == 1
3125 && old_cursor.par()->IsLineSeparator(0)))
3128 // ok, we will delete anything
3130 // make sure that you do not delete any environments
3133 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3134 !(old_cursor.row()->previous()
3135 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3136 && !(old_cursor.row()->next()
3137 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3138 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3139 && ((old_cursor.row()->previous()
3140 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3141 || (old_cursor.row()->next()
3142 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3145 status = LyXText::NEED_MORE_REFRESH;
3148 if (old_cursor.row()->previous()) {
3149 refresh_row = old_cursor.row()->previous();
3150 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3152 cursor = old_cursor; // that undo can restore the right cursor position
3154 LyXParagraph * endpar = old_cursor.par()->next_;
3155 if (endpar && endpar->GetDepth()) {
3156 while (endpar && endpar->GetDepth()) {
3157 endpar = endpar->LastPhysicalPar()->next();
3160 SetUndo(bview->buffer(), Undo::DELETE,
3161 old_cursor.par()->previous_,
3166 RemoveRow(old_cursor.row());
3167 if (OwnerParagraph() == old_cursor.par()) {
3168 OwnerParagraph(OwnerParagraph()->next_);
3171 LyXParagraph * endpar = old_cursor.par()->next();
3172 if (endpar && endpar->GetDepth()) {
3173 while (endpar && endpar->GetDepth()) {
3174 endpar = endpar->next();
3177 SetUndo(bview->buffer(), Undo::DELETE,
3178 old_cursor.par()->previous(),
3183 RemoveRow(old_cursor.row());
3184 if (OwnerParagraph() == old_cursor.par()) {
3185 OwnerParagraph(OwnerParagraph()->next());
3189 delete old_cursor.par();
3191 /* Breakagain the next par. Needed
3192 * because of the parindent that
3193 * can occur or dissappear. The
3194 * next row can change its height,
3195 * if there is another layout before */
3196 if (refresh_row->next()) {
3197 BreakAgain(bview, refresh_row->next());
3198 UpdateCounters(bview, refresh_row);
3200 SetHeightOfRow(bview, refresh_row);
3202 refresh_row = old_cursor.row()->next();
3203 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3206 cursor = old_cursor; // that undo can restore the right cursor position
3208 LyXParagraph * endpar = old_cursor.par()->next_;
3209 if (endpar && endpar->GetDepth()) {
3210 while (endpar && endpar->GetDepth()) {
3211 endpar = endpar->LastPhysicalPar()->next();
3214 SetUndo(bview->buffer(), Undo::DELETE,
3215 old_cursor.par()->previous_,
3220 RemoveRow(old_cursor.row());
3222 if (OwnerParagraph() == old_cursor.par()) {
3223 OwnerParagraph(OwnerParagraph()->next_);
3226 LyXParagraph * endpar = old_cursor.par()->next();
3227 if (endpar && endpar->GetDepth()) {
3228 while (endpar && endpar->GetDepth()) {
3229 endpar = endpar->next();
3232 SetUndo(bview->buffer(), Undo::DELETE,
3233 old_cursor.par()->previous(),
3238 RemoveRow(old_cursor.row());
3240 if (OwnerParagraph() == old_cursor.par()) {
3241 OwnerParagraph(OwnerParagraph()->next());
3244 delete old_cursor.par();
3246 /* Breakagain the next par. Needed
3247 because of the parindent that can
3248 occur or dissappear.
3249 The next row can change its height,
3250 if there is another layout before
3253 BreakAgain(bview, refresh_row);
3254 UpdateCounters(bview, refresh_row->previous());
3260 SetCursorIntern(bview, cursor.par(), cursor.pos());
3262 if (sel_cursor.par() == old_cursor.par()
3263 && sel_cursor.pos() == sel_cursor.pos()) {
3264 // correct selection
3265 sel_cursor = cursor;
3272 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3273 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3275 SetCursorIntern(bview, cursor.par(), cursor.pos());
3276 sel_cursor = cursor;
3284 LyXParagraph * LyXText::GetParFromID(int id)
3286 LyXParagraph * result = FirstParagraph();
3287 while (result && result->id() != id)
3288 result = result->next_;
3292 LyXParagraph * LyXText::GetParFromID(int id)
3294 LyXParagraph * result = FirstParagraph();
3295 while (result && result->id() != id)
3296 result = result->next();
3303 bool LyXText::TextUndo(BufferView * bview)
3307 // returns false if no undo possible
3308 Undo * undo = bview->buffer()->undostack.pop();
3312 bview->buffer()->redostack
3313 .push(CreateUndo(bview->buffer(), undo->kind,
3314 GetParFromID(undo->number_of_before_par),
3315 GetParFromID(undo->number_of_behind_par)));
3317 return TextHandleUndo(bview, undo);
3321 bool LyXText::TextRedo(BufferView * bview)
3325 // returns false if no redo possible
3326 Undo * undo = bview->buffer()->redostack.pop();
3330 bview->buffer()->undostack
3331 .push(CreateUndo(bview->buffer(), undo->kind,
3332 GetParFromID(undo->number_of_before_par),
3333 GetParFromID(undo->number_of_behind_par)));
3335 return TextHandleUndo(bview, undo);
3339 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3343 // returns false if no undo possible
3344 bool result = false;
3346 LyXParagraph * before =
3347 GetParFromID(undo->number_of_before_par);
3348 LyXParagraph * behind =
3349 GetParFromID(undo->number_of_behind_par);
3350 LyXParagraph * tmppar;
3351 LyXParagraph * tmppar2;
3352 LyXParagraph * endpar;
3353 LyXParagraph * tmppar5;
3355 // if there's no before take the beginning
3356 // of the document for redoing
3358 SetCursorIntern(bview, FirstParagraph(), 0);
3360 // replace the paragraphs with the undo informations
3362 LyXParagraph * tmppar3 = undo->par;
3363 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3364 LyXParagraph * tmppar4 = tmppar3;
3367 while (tmppar4->next_)
3368 tmppar4 = tmppar4->next_;
3369 } // get last undo par
3371 // now remove the old text if there is any
3372 if (before != behind || (!behind && !before)) {
3374 tmppar5 = before->next();
3376 tmppar5 = OwnerParagraph();
3378 while (tmppar5 && tmppar5 != behind) {
3380 tmppar5 = tmppar5->next();
3381 // a memory optimization for edit: Only layout information
3382 // is stored in the undo. So restore the text informations.
3383 if (undo->kind == Undo::EDIT) {
3384 tmppar2->setContentsFromPar(tmppar);
3385 tmppar->clearContents();
3386 tmppar2 = tmppar2->next();
3393 while (tmppar4->next())
3394 tmppar4 = tmppar4->next();
3395 } // get last undo par
3397 // now remove the old text if there is any
3398 if (before != behind || (!behind && !before)) {
3400 tmppar5 = before->next();
3402 tmppar5 = OwnerParagraph();
3404 while (tmppar5 && tmppar5 != behind) {
3406 tmppar5 = tmppar5->next();
3407 // a memory optimization for edit: Only layout information
3408 // is stored in the undo. So restore the text informations.
3409 if (undo->kind == Undo::EDIT) {
3410 tmppar2->setContentsFromPar(tmppar);
3411 tmppar->clearContents();
3412 tmppar2 = tmppar2->next();
3418 // put the new stuff in the list if there is one
3421 before->next(tmppar3);
3423 OwnerParagraph(tmppar3);
3424 tmppar3->previous(before);
3427 OwnerParagraph(behind);
3430 tmppar4->next(behind);
3432 behind->previous(tmppar4);
3436 // Set the cursor for redoing
3439 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3441 SetCursorIntern(bview, before, 0);
3444 // check wether before points to a closed float and open it if necessary
3445 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3446 && before->next_ && before->next_->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3448 while (tmppar4->previous_ &&
3449 tmppar4->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3450 tmppar4 = tmppar4->previous_;
3451 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3452 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3453 tmppar4 = tmppar4->next_;
3460 // open a cosed footnote at the end if necessary
3461 if (behind && behind->previous_ &&
3462 behind->previous_->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3463 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3464 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3465 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3466 behind = behind->next_;
3471 // calculate the endpar for redoing the paragraphs.
3474 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3475 endpar = behind->LastPhysicalPar()->next();
3477 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->next();
3479 endpar = behind->next();
3484 tmppar = GetParFromID(undo->number_of_cursor_par);
3485 RedoParagraphs(bview, cursor, endpar);
3487 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3488 UpdateCounters(bview, cursor.row());
3498 void LyXText::FinishUndo()
3502 // makes sure the next operation will be stored
3503 undo_finished = true;
3507 void LyXText::FreezeUndo()
3511 // this is dangerous and for internal use only
3516 void LyXText::UnFreezeUndo()
3520 // this is dangerous and for internal use only
3521 undo_frozen = false;
3525 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3526 LyXParagraph const * before,
3527 LyXParagraph const * behind) const
3532 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3533 buf->redostack.clear();
3537 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3538 LyXParagraph const * before, LyXParagraph const * behind)
3542 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3546 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3547 LyXParagraph const * before,
3548 LyXParagraph const * behind) const
3553 int before_number = -1;
3554 int behind_number = -1;
3556 before_number = before->id();
3558 behind_number = behind->id();
3559 // Undo::EDIT and Undo::FINISH are
3560 // always finished. (no overlapping there)
3561 // overlapping only with insert and delete inside one paragraph:
3562 // Nobody wants all removed character
3563 // appear one by one when undoing.
3564 // EDIT is special since only layout information, not the
3565 // contents of a paragaph are stored.
3566 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3567 // check wether storing is needed
3568 if (!buf->undostack.empty() &&
3569 buf->undostack.top()->kind == kind &&
3570 buf->undostack.top()->number_of_before_par == before_number &&
3571 buf->undostack.top()->number_of_behind_par == behind_number ){
3576 // create a new Undo
3577 LyXParagraph * undopar;
3578 LyXParagraph * tmppar;
3579 LyXParagraph * tmppar2;
3581 LyXParagraph * start = 0;
3582 LyXParagraph * end = 0;
3586 start = before->next_;
3588 start = FirstParagraph();
3590 end = behind->previous_;
3592 end = FirstParagraph();
3596 if (start && end && (start != end->next_) &&
3597 ((before != behind) || (!before && !behind))) {
3599 tmppar2 = tmppar->Clone();
3600 tmppar2->id(tmppar->id());
3602 // a memory optimization: Just store the layout information
3604 if (kind == Undo::EDIT){
3605 //tmppar2->text.clear();
3606 tmppar2->clearContents();
3611 while (tmppar != end && tmppar->next_) {
3612 tmppar = tmppar->next_;
3613 tmppar2->next(tmppar->Clone());
3614 tmppar2->next_->id(tmppar->id());
3615 // a memory optimization: Just store the layout
3616 // information when only edit
3617 if (kind == Undo::EDIT){
3618 //tmppar2->next->text.clear();
3619 tmppar2->clearContents();
3621 tmppar2->next_->previous(tmppar2);
3622 tmppar2 = tmppar2->next_;
3626 undopar = 0; // nothing to replace (undo of delete maybe)
3628 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3629 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3632 start = const_cast<LyXParagraph*>(before->next());
3634 start = FirstParagraph();
3636 end = const_cast<LyXParagraph*>(behind->previous());
3638 end = FirstParagraph();
3642 if (start && end && (start != end->next()) &&
3643 ((before != behind) || (!before && !behind))) {
3645 tmppar2 = tmppar->Clone();
3646 tmppar2->id(tmppar->id());
3648 // a memory optimization: Just store the layout information
3650 if (kind == Undo::EDIT){
3651 //tmppar2->text.clear();
3652 tmppar2->clearContents();
3657 while (tmppar != end && tmppar->next()) {
3658 tmppar = tmppar->next();
3659 tmppar2->next(tmppar->Clone());
3660 tmppar2->next()->id(tmppar->id());
3661 // a memory optimization: Just store the layout
3662 // information when only edit
3663 if (kind == Undo::EDIT){
3664 //tmppar2->next->text.clear();
3665 tmppar2->clearContents();
3667 tmppar2->next()->previous(tmppar2);
3668 tmppar2 = tmppar2->next();
3672 undopar = 0; // nothing to replace (undo of delete maybe)
3674 int cursor_par = cursor.par()->id();
3675 int cursor_pos = cursor.pos();
3678 Undo * undo = new Undo(kind,
3679 before_number, behind_number,
3680 cursor_par, cursor_pos,
3683 undo_finished = false;
3688 void LyXText::SetCursorParUndo(Buffer * buf)
3692 SetUndo(buf, Undo::FINISH,
3694 cursor.par()->ParFromPos(cursor.pos())->previous_,
3695 cursor.par()->ParFromPos(cursor.pos())->next_
3697 cursor.par()->previous(),
3698 cursor.par()->next()
3704 void LyXText::toggleAppendix(BufferView * bview)
3707 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3709 LyXParagraph * par = cursor.par();
3711 bool start = !par->params.startOfAppendix();
3713 // ensure that we have only one start_of_appendix in this document
3714 LyXParagraph * tmp = FirstParagraph();
3716 for (; tmp; tmp = tmp->next_)
3717 tmp->params.startOfAppendix(false);
3719 for (; tmp; tmp = tmp->next())
3720 tmp->params.startOfAppendix(false);
3722 par->params.startOfAppendix(start);
3724 // we can set the refreshing parameters now
3725 status = LyXText::NEED_MORE_REFRESH;
3727 refresh_row = 0; // not needed for full update
3728 UpdateCounters(bview, 0);
3729 SetCursor(bview, cursor.par(), cursor.pos());
3733 LyXParagraph * LyXText::OwnerParagraph() const
3736 return inset_owner->par;
3738 return bv_owner->buffer()->paragraph;
3742 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3745 inset_owner->par = p;
3747 bv_owner->buffer()->paragraph = p;