1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2000 The LyX Team.
9 * ====================================================== */
13 #include FORMS_H_LOCATION
17 #pragma implementation "lyxtext.h"
21 #include "lyxparagraph.h"
22 #include "insets/inseterror.h"
23 #include "insets/insetbib.h"
24 #include "insets/insetspecialchar.h"
25 #include "insets/insettext.h"
26 #include "insets/insetfloat.h"
29 #include "support/textutils.h"
31 #include "minibuffer.h"
33 #include "bufferparams.h"
34 #include "lyx_gui_misc.h"
37 #include "BufferView.h"
40 #include "CutAndPaste.h"
45 #include "FloatList.h"
54 LyXText::LyXText(BufferView * bv)
62 LyXText::LyXText(InsetText * inset)
72 the_locking_inset = 0;
80 status = LyXText::UNCHANGED;
81 // set cursor at the very top position
82 selection = true; /* these setting is necessary
83 because of the delete-empty-
84 paragraph mechanism in
87 LyXParagraph * par = OwnerParagraph();
88 current_font = GetFont(bv_owner->buffer(), par, 0);
90 InsertParagraph(bv_owner, par, lastrow);
93 SetCursor(bv_owner, firstrow->par(), 0);
95 current_font = LyXFont(LyXFont::ALL_SANE);
101 // no rebreak necessary
104 undo_finished = true;
107 // Default layouttype for copy environment type
111 // Dump all rowinformation:
112 Row * tmprow = firstrow;
113 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
115 lyxerr << tmprow->baseline() << '\t'
116 << tmprow->par << '\t'
117 << tmprow->pos() << '\t'
118 << tmprow->height << '\t'
119 << tmprow->ascent_of_text << '\t'
120 << tmprow->fill << '\n';
121 tmprow = tmprow->next();
128 void LyXText::init(BufferView * bview)
133 LyXParagraph * par = OwnerParagraph();
134 current_font = GetFont(bview->buffer(), par, 0);
136 InsertParagraph(bview, par, lastrow);
139 SetCursorIntern(bview, firstrow->par(), 0);
142 // Dump all rowinformation:
143 Row * tmprow = firstrow;
144 lyxerr << "Width = " << width << endl;
145 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
147 lyxerr << tmprow->baseline() << '\t'
148 << tmprow->par() << '\t'
149 << tmprow->pos() << '\t'
150 << tmprow->height() << '\t'
151 << tmprow->ascent_of_text() << '\t'
152 << tmprow->fill() << '\n';
153 tmprow = tmprow->next();
161 // Delete all rows, this does not touch the paragraphs!
162 Row * tmprow = firstrow;
164 tmprow = firstrow->next();
171 // Gets the fully instantiated font at a given position in a paragraph
172 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
173 // The difference is that this one is used for displaying, and thus we
174 // are allowed to make cosmetic improvements. For instance make footnotes
176 // If position is -1, we get the layout font of the paragraph.
177 // If position is -2, we get the font of the manual label of the paragraph.
178 LyXFont const LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
179 LyXParagraph::size_type pos) const
181 LyXLayout const & layout =
182 textclasslist.Style(buf->params.textclass, par->GetLayout());
184 char par_depth = par->GetDepth();
185 // We specialize the 95% common case:
188 par->footnoteflag == LyXParagraph::NO_FOOTNOTE &&
193 if (layout.labeltype == LABEL_MANUAL
194 && pos < BeginningOfMainBody(buf, par)) {
196 LyXFont f = par->GetFontSettings(buf->params,
198 return f.realize(layout.reslabelfont);
200 LyXFont f = par->GetFontSettings(buf->params, pos);
201 return f.realize(layout.resfont);
206 // process layoutfont for pos == -1 and labelfont for pos < -1
208 return layout.resfont;
210 return layout.reslabelfont;
214 // The uncommon case need not be optimized as much
216 LyXFont layoutfont, tmpfont;
220 if (pos < BeginningOfMainBody(buf, par)) {
222 layoutfont = layout.labelfont;
225 layoutfont = layout.font;
227 tmpfont = par->GetFontSettings(buf->params, pos);
228 tmpfont.realize(layoutfont);
231 // process layoutfont for pos == -1 and labelfont for pos < -1
233 tmpfont = layout.font;
235 tmpfont = layout.labelfont;
238 // Resolve against environment font information
239 while (par && par_depth && !tmpfont.resolved()) {
240 par = par->DepthHook(par_depth - 1);
242 tmpfont.realize(textclasslist.
243 Style(buf->params.textclass,
244 par->GetLayout()).font);
245 par_depth = par->GetDepth();
249 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
252 // Cosmetic improvement: If this is an open footnote, make the font
254 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
255 && par->footnotekind == LyXParagraph::FOOTNOTE) {
263 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
264 LyXParagraph::size_type pos,
268 // Let the insets convert their font
269 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
270 if (par->GetInset(pos))
271 font = par->GetInset(pos)->ConvertFont(font);
274 LyXLayout const & layout =
275 textclasslist.Style(buf->params.textclass,
278 // Get concrete layout font to reduce against
281 if (pos < BeginningOfMainBody(buf, par))
282 layoutfont = layout.labelfont;
284 layoutfont = layout.font;
286 // Realize against environment font information
287 if (par->GetDepth()){
288 LyXParagraph * tp = par;
289 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
290 tp = tp->DepthHook(tp->GetDepth()-1);
292 layoutfont.realize(textclasslist.
293 Style(buf->params.textclass,
294 tp->GetLayout()).font);
298 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
301 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
302 && par->footnotekind == LyXParagraph::FOOTNOTE) {
303 layoutfont.decSize();
306 // Now, reduce font against full layout font
307 font.reduce(layoutfont);
309 par->SetFont(pos, font);
313 /* inserts a new row behind the specified row, increments
314 * the touched counters */
315 void LyXText::InsertRow(Row * row, LyXParagraph * par,
316 LyXParagraph::size_type pos) const
318 Row * tmprow = new Row;
321 tmprow->next(firstrow);
324 tmprow->previous(row);
325 tmprow->next(row->next());
330 tmprow->next()->previous(tmprow);
332 if (tmprow->previous())
333 tmprow->previous()->next(tmprow);
341 ++number_of_rows; // one more row
345 // removes the row and reset the touched counters
346 void LyXText::RemoveRow(Row * row) const
348 /* this must not happen before the currentrow for clear reasons.
349 so the trick is just to set the current row onto the previous
352 GetRow(row->par(), row->pos(), unused_y);
355 row->next()->previous(row->previous());
356 if (!row->previous()) {
357 firstrow = row->next();
359 row->previous()->next(row->next());
362 lastrow = row->previous();
364 height -= row->height(); // the text becomes smaller
367 --number_of_rows; // one row less
371 // remove all following rows of the paragraph of the specified row.
372 void LyXText::RemoveParagraph(Row * row) const
374 LyXParagraph * tmppar = row->par();
378 while (row && row->par() == tmppar) {
379 tmprow = row->next();
386 // insert the specified paragraph behind the specified row
387 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
390 InsertRow(row, par, 0); /* insert a new row, starting
393 SetCounter(bview->buffer(), par); // set the counters
395 // and now append the whole paragraph behind the new row
398 AppendParagraph(bview, firstrow);
400 row->next()->height(0);
401 AppendParagraph(bview, row->next());
407 void LyXText::ToggleFootnote(BufferView * bview)
409 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
411 && par->next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
413 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
415 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
416 CloseFootnote(bview);
423 void LyXText::OpenStuff(BufferView * bview)
425 if (cursor.pos() == 0 && cursor.par()->bibkey){
426 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
427 } else if (cursor.pos() < cursor.par()->Last()
428 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
429 && cursor.par()->GetInset(cursor.pos())->Editable()) {
430 bview->owner()->getMiniBuffer()
431 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
432 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
433 SetCursorParUndo(bview->buffer());
434 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
438 ToggleFootnote(bview);
446 void LyXText::CloseFootnote(BufferView * bview)
448 LyXParagraph * tmppar;
449 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
451 // if the cursor is not in an open footnote, or
452 // there is no open footnote in this paragraph, just return.
453 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
456 par->next_->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
457 bview->owner()->getMiniBuffer()
458 ->Set(_("Nothing to do"));
462 // ok, move the cursor right before the footnote
463 // just a little faster than using CursorRight()
465 cursor.par()->ParFromPos(cursor.pos()) != par;) {
466 cursor.pos(cursor.pos() + 1);
469 // now the cursor is at the beginning of the physical par
470 SetCursor(bview, cursor.par(),
472 cursor.par()->ParFromPos(cursor.pos())->size());
474 /* we are in a footnote, so let us move at the beginning */
475 /* this is just faster than using just CursorLeft() */
477 tmppar = cursor.par();
478 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
479 // just a little bit faster than movin the cursor
480 tmppar = tmppar->previous();
482 SetCursor(bview, tmppar, tmppar->Last());
485 // the cursor must be exactly before the footnote
486 par = cursor.par()->ParFromPos(cursor.pos());
488 status = LyXText::NEED_MORE_REFRESH;
489 refresh_row = cursor.row();
490 refresh_y = cursor.y() - cursor.row()->baseline();
492 tmppar = cursor.par();
493 LyXParagraph * endpar = par->NextAfterFootnote()->next();
494 Row * row = cursor.row();
496 tmppar->CloseFootnote(cursor.pos());
498 while (tmppar != endpar) {
499 RemoveRow(row->next());
501 tmppar = row->next()->par();
506 AppendParagraph(bview, cursor.row());
508 SetCursor(bview, cursor.par(), cursor.pos());
512 if (cursor.row()->next())
513 SetHeightOfRow(bview, cursor.row()->next());
518 /* used in setlayout */
519 // Asger is not sure we want to do this...
520 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
524 LyXLayout const & layout =
525 textclasslist.Style(buf->params.textclass, par->GetLayout());
527 LyXFont layoutfont, tmpfont;
528 for (LyXParagraph::size_type pos = 0;
530 pos < par->Last(); ++pos) {
532 pos < par->size(); ++pos) {
534 if (pos < BeginningOfMainBody(buf, par))
535 layoutfont = layout.labelfont;
537 layoutfont = layout.font;
539 tmpfont = par->GetFontSettings(buf->params, pos);
540 tmpfont.reduce(layoutfont);
541 par->SetFont(pos, tmpfont);
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 /* returns a pointer to the row near the specified y-coordinate
1320 * (relative to the whole text). y is set to the real beginning
1322 Row * LyXText::GetRowNearY(int & y) const
1324 Row * tmprow = firstrow;
1327 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1328 tmpy += tmprow->height();
1329 tmprow = tmprow->next();
1332 y = tmpy; // return the real y
1337 void LyXText::ToggleFree(BufferView * bview,
1338 LyXFont const & font, bool toggleall)
1340 // If the mask is completely neutral, tell user
1341 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1342 // Could only happen with user style
1343 bview->owner()->getMiniBuffer()
1344 ->Set(_("No font change defined. Use Character under"
1345 " the Layout menu to define font change."));
1349 // Try implicit word selection
1350 // If there is a change in the language the implicit word selection
1352 LyXCursor resetCursor = cursor;
1353 bool implicitSelection = (font.language() == ignore_language
1354 && font.number() == LyXFont::IGNORE)
1355 ? SelectWordWhenUnderCursor(bview) : false;
1358 SetFont(bview, font, toggleall);
1360 /* Implicit selections are cleared afterwards and cursor is set to the
1361 original position. */
1362 if (implicitSelection) {
1363 ClearSelection(bview);
1364 cursor = resetCursor;
1365 SetCursor(bview, cursor.par(), cursor.pos());
1366 sel_cursor = cursor;
1369 inset_owner->SetUpdateStatus(bview, InsetText::CURSOR_PAR);
1373 LyXParagraph::size_type
1374 LyXText::BeginningOfMainBody(Buffer const * buf,
1375 LyXParagraph const * par) const
1377 if (textclasslist.Style(buf->params.textclass,
1378 par->GetLayout()).labeltype != LABEL_MANUAL)
1381 return par->BeginningOfMainBody();
1386 /* if there is a selection, reset every environment you can find
1387 * in the selection, otherwise just the environment you are in */
1388 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1390 LyXParagraph * tmppar, * firsttmppar;
1392 ClearSelection(bview);
1394 /* is is only allowed, if the cursor is IN an open footnote.
1395 * Otherwise it is too dangerous */
1396 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1399 SetUndo(bview->buffer(), Undo::FINISH,
1400 cursor.par()->PreviousBeforeFootnote()->previous_,
1401 cursor.par()->NextAfterFootnote()->next_);
1403 /* ok, move to the beginning of the footnote. */
1404 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1405 cursor.par(cursor.par()->previous());
1407 SetCursor(bview, cursor.par(), cursor.par()->Last());
1408 /* this is just faster than using CursorLeft(); */
1410 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1411 tmppar = firsttmppar;
1412 /* tmppar is now the paragraph right before the footnote */
1414 bool first_footnote_par_is_not_empty = tmppar->next_->size();
1416 while (tmppar->next_
1417 && tmppar->next_->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1418 tmppar = tmppar->next_; /* I use next instead of Next(),
1419 * because there cannot be any
1420 * footnotes in a footnote
1422 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1424 /* remember the captions and empty paragraphs */
1425 if ((textclasslist.Style(bview->buffer()->params.textclass,
1426 tmppar->GetLayout())
1427 .labeltype == LABEL_SENSITIVE)
1429 tmppar->SetLayout(bview->buffer()->params, 0);
1432 // now we will paste the ex-footnote, if the layouts allow it
1433 // first restore the layout of the paragraph right behind
1436 tmppar->next_->MakeSameLayout(cursor.par());
1439 if (!tmppar->GetLayout()
1441 && (!tmppar->next()->Last()
1442 || tmppar->next()->HasSameLayout(tmppar)))) {
1443 if (tmppar->next()->Last()
1444 && tmppar->next()->IsLineSeparator(0))
1445 tmppar->next()->Erase(0);
1446 tmppar->PasteParagraph(bview->buffer()->params);
1449 tmppar = tmppar->next(); /* make sure tmppar cannot be touched
1450 * by the pasting of the beginning */
1452 /* then the beginning */
1453 /* if there is no space between the text and the footnote, so we insert
1455 * (only if the previous par and the footnotepar are not empty!) */
1456 if (!firsttmppar->next_->GetLayout()
1457 || firsttmppar->HasSameLayout(firsttmppar->next_)) {
1458 if (firsttmppar->size()
1459 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1460 && first_footnote_par_is_not_empty) {
1461 firsttmppar->next_->InsertChar(0, ' ');
1463 firsttmppar->PasteParagraph(bview->buffer()->params);
1466 /* now redo the paragaphs */
1467 RedoParagraphs(bview, cursor, tmppar);
1469 SetCursor(bview, cursor.par(), cursor.pos());
1471 /* sometimes it can happen, that there is a counter change */
1472 Row * row = cursor.row();
1473 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1475 UpdateCounters(bview, row);
1478 ClearSelection(bview);
1483 /* the DTP switches for paragraphs. LyX will store them in the
1484 * first physicla paragraph. When a paragraph is broken, the top settings
1485 * rest, the bottom settings are given to the new one. So I can make shure,
1486 * they do not duplicate themself and you cannnot make dirty things with
1489 void LyXText::SetParagraph(BufferView * bview,
1490 bool line_top, bool line_bottom,
1491 bool pagebreak_top, bool pagebreak_bottom,
1492 VSpace const & space_top,
1493 VSpace const & space_bottom,
1495 string labelwidthstring,
1498 LyXCursor tmpcursor = cursor;
1500 sel_start_cursor = cursor;
1501 sel_end_cursor = cursor;
1504 // make sure that the depth behind the selection are restored, too
1506 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
1508 LyXParagraph * endpar = sel_end_cursor.par()->next();
1510 LyXParagraph * undoendpar = endpar;
1512 if (endpar && endpar->GetDepth()) {
1513 while (endpar && endpar->GetDepth()) {
1515 endpar = endpar->LastPhysicalPar()->next();
1517 endpar = endpar->next();
1519 undoendpar = endpar;
1523 endpar = endpar->next(); // because of parindents etc.
1526 SetUndo(bview->buffer(), Undo::EDIT,
1529 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
1531 sel_start_cursor.par()->previous(),
1536 LyXParagraph * tmppar = sel_end_cursor.par();
1538 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->previous()) {
1539 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1541 while (tmppar != sel_start_cursor.par()->previous()) {
1542 SetCursor(bview, tmppar, 0);
1544 status = LyXText::NEED_MORE_REFRESH;
1545 refresh_row = cursor.row();
1546 refresh_y = cursor.y() - cursor.row()->baseline();
1548 if (cursor.par()->footnoteflag ==
1549 sel_start_cursor.par()->footnoteflag) {
1551 cursor.par()->params.lineTop(line_top);
1552 cursor.par()->params.lineBottom(line_bottom);
1553 cursor.par()->params.pagebreakTop(pagebreak_top);
1554 cursor.par()->params.pagebreakBottom(pagebreak_bottom);
1555 cursor.par()->params.spaceTop(space_top);
1556 cursor.par()->params.spaceBottom(space_bottom);
1557 // does the layout allow the new alignment?
1558 if (align == LYX_ALIGN_LAYOUT)
1559 align = textclasslist
1560 .Style(bview->buffer()->params.textclass,
1561 cursor.par()->GetLayout()).align;
1562 if (align & textclasslist
1563 .Style(bview->buffer()->params.textclass,
1564 cursor.par()->GetLayout()).alignpossible) {
1565 if (align == textclasslist
1566 .Style(bview->buffer()->params.textclass,
1567 cursor.par()->GetLayout()).align)
1568 cursor.par()->params.align(LYX_ALIGN_LAYOUT);
1570 cursor.par()->params.align(align);
1572 cursor.par()->SetLabelWidthString(labelwidthstring);
1573 cursor.par()->params.noindent(noindent);
1577 tmppar = cursor.par()->FirstPhysicalPar()->previous();
1579 tmppar = cursor.par()->previous();
1583 RedoParagraphs(bview, sel_start_cursor, endpar);
1585 ClearSelection(bview);
1586 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1587 sel_cursor = cursor;
1588 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1589 SetSelection(bview);
1590 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1592 bview->updateInset(inset_owner, true);
1597 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1598 string const & width,
1599 string const & widthp,
1600 int alignment, bool hfill,
1601 bool start_minipage)
1603 LyXCursor tmpcursor = cursor;
1604 LyXParagraph * tmppar;
1606 sel_start_cursor = cursor;
1607 sel_end_cursor = cursor;
1610 // make sure that the depth behind the selection are restored, too
1612 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
1614 LyXParagraph * endpar = sel_end_cursor.par()->next();
1616 LyXParagraph * undoendpar = endpar;
1618 if (endpar && endpar->GetDepth()) {
1619 while (endpar && endpar->GetDepth()) {
1621 endpar = endpar->LastPhysicalPar()->next();
1623 endpar = endpar->next();
1625 undoendpar = endpar;
1629 endpar = endpar->next(); // because of parindents etc.
1632 SetUndo(bview->buffer(), Undo::EDIT,
1635 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
1637 sel_start_cursor.par()->previous(),
1641 tmppar = sel_end_cursor.par();
1643 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->previous()) {
1644 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1646 while(tmppar != sel_start_cursor.par()->previous()) {
1647 SetCursor(bview, tmppar, 0);
1649 status = LyXText::NEED_MORE_REFRESH;
1650 refresh_row = cursor.row();
1651 refresh_y = cursor.y() - cursor.row()->baseline();
1653 if (cursor.par()->footnoteflag ==
1654 sel_start_cursor.par()->footnoteflag) {
1657 if (type == LyXParagraph::PEXTRA_NONE) {
1658 if (cursor.par()->params.pextraType() != LyXParagraph::PEXTRA_NONE) {
1659 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1660 cursor.par()->params.pextraType(LyXParagraph::PEXTRA_NONE);
1663 cursor.par()->SetPExtraType(bview->buffer()->params,
1664 type, width, widthp);
1665 cursor.par()->params.pextraHfill(hfill);
1666 cursor.par()->params.pextraStartMinipage(start_minipage);
1667 cursor.par()->params.pextraAlignment(alignment);
1672 tmppar = cursor.par()->FirstPhysicalPar()->previous();
1674 tmppar = cursor.par()->previous();
1677 RedoParagraphs(bview, sel_start_cursor, endpar);
1678 ClearSelection(bview);
1679 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1680 sel_cursor = cursor;
1681 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1682 SetSelection(bview);
1683 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1688 char loweralphaCounter(int n)
1690 if (n < 1 || n > 26)
1700 char alphaCounter(int n)
1702 if (n < 1 || n > 26)
1710 char hebrewCounter(int n)
1712 static const char hebrew[22] = {
1713 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1714 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1715 '÷', 'ø', 'ù', 'ú'
1717 if (n < 1 || n > 22)
1725 string const romanCounter(int n)
1727 static char const * roman[20] = {
1728 "i", "ii", "iii", "iv", "v",
1729 "vi", "vii", "viii", "ix", "x",
1730 "xi", "xii", "xiii", "xiv", "xv",
1731 "xvi", "xvii", "xviii", "xix", "xx"
1733 if (n < 1 || n > 20)
1742 // set the counter of a paragraph. This includes the labels
1743 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1746 // this is only relevant for the beginning of paragraph
1747 par = par->FirstPhysicalPar();
1749 LyXLayout const & layout =
1750 textclasslist.Style(buf->params.textclass,
1753 LyXTextClass const & textclass =
1754 textclasslist.TextClass(buf->params.textclass);
1756 /* copy the prev-counters to this one, unless this is the start of a
1757 footnote or of a bibliography or the very first paragraph */
1760 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1761 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1762 && par->footnotekind == LyXParagraph::FOOTNOTE)
1764 && !(textclasslist.Style(buf->params.textclass,
1765 par->previous()->GetLayout()
1766 ).labeltype != LABEL_BIBLIO
1767 && layout.labeltype == LABEL_BIBLIO)) {
1768 for (int i = 0; i < 10; ++i) {
1769 par->setCounter(i, par->previous()->GetFirstCounter(i));
1772 par->params.appendix(par->previous()->FirstPhysicalPar()->params.appendix());
1774 par->params.appendix(par->previous()->params.appendix());
1776 if (!par->params.appendix() && par->params.startOfAppendix()) {
1777 par->params.appendix(true);
1778 for (int i = 0; i < 10; ++i) {
1779 par->setCounter(i, 0);
1783 par->enumdepth = par->previous()->FirstPhysicalPar()->enumdepth;
1784 par->itemdepth = par->previous()->FirstPhysicalPar()->itemdepth;
1786 par->enumdepth = par->previous()->enumdepth;
1787 par->itemdepth = par->previous()->itemdepth;
1790 for (int i = 0; i < 10; ++i) {
1791 par->setCounter(i, 0);
1793 par->params.appendix(par->params.startOfAppendix());
1799 // if this is an open marginnote and this is the first
1800 // entry in the marginnote and the enclosing
1801 // environment is an enum/item then correct for the
1802 // LaTeX behaviour (ARRae)
1803 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1804 && par->footnotekind == LyXParagraph::MARGIN
1806 && par->previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1807 && (par->PreviousBeforeFootnote()
1808 && textclasslist.Style(buf->params.textclass,
1809 par->PreviousBeforeFootnote()->GetLayout()
1810 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1811 // Any itemize or enumerate environment in a marginnote
1812 // that is embedded in an itemize or enumerate
1813 // paragraph is seen by LaTeX as being at a deeper
1814 // level within that enclosing itemization/enumeration
1815 // even if there is a "standard" layout at the start of
1821 /* Maybe we have to increment the enumeration depth.
1822 * BUT, enumeration in a footnote is considered in isolation from its
1823 * surrounding paragraph so don't increment if this is the
1824 * first line of the footnote
1825 * AND, bibliographies can't have their depth changed ie. they
1826 * are always of depth 0
1829 && par->previous()->GetDepth() < par->GetDepth()
1830 && textclasslist.Style(buf->params.textclass,
1831 par->previous()->GetLayout()
1832 ).labeltype == LABEL_COUNTER_ENUMI
1833 && par->enumdepth < 3
1835 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1836 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1837 && par->footnotekind == LyXParagraph::FOOTNOTE)
1839 && layout.labeltype != LABEL_BIBLIO) {
1843 /* Maybe we have to decrement the enumeration depth, see note above */
1845 && par->previous()->GetDepth() > par->GetDepth()
1847 && !(par->previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1848 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1849 && par->footnotekind == LyXParagraph::FOOTNOTE)
1851 && layout.labeltype != LABEL_BIBLIO) {
1852 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1853 par->setCounter(6 + par->enumdepth,
1854 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1855 /* reset the counters.
1856 * A depth change is like a breaking layout
1858 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1859 par->setCounter(i, 0);
1862 if (!par->params.labelString().empty()) {
1863 par->params.labelString(string());
1866 if (layout.margintype == MARGIN_MANUAL) {
1867 if (par->params.labelWidthString().empty()) {
1868 par->SetLabelWidthString(layout.labelstring());
1871 par->SetLabelWidthString(string());
1874 /* is it a layout that has an automatic label ? */
1875 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1877 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1878 if (i >= 0 && i<= buf->params.secnumdepth) {
1879 par->incCounter(i); // increment the counter
1881 // Is there a label? Useful for Chapter layout
1882 if (!par->params.appendix()) {
1883 if (!layout.labelstring().empty())
1884 par->params.labelString(layout.labelstring());
1886 par->params.labelString(string());
1888 if (!layout.labelstring_appendix().empty())
1889 par->params.labelString(layout.labelstring_appendix());
1891 par->params.labelString(string());
1894 std::ostringstream s;
1896 if (!par->params.appendix()) {
1897 switch (2 * LABEL_COUNTER_CHAPTER -
1898 textclass.maxcounter() + i) {
1899 case LABEL_COUNTER_CHAPTER:
1900 s << par->getCounter(i);
1902 case LABEL_COUNTER_SECTION:
1903 s << par->getCounter(i - 1) << '.'
1904 << par->getCounter(i);
1906 case LABEL_COUNTER_SUBSECTION:
1907 s << par->getCounter(i - 2) << '.'
1908 << par->getCounter(i - 1) << '.'
1909 << par->getCounter(i);
1911 case LABEL_COUNTER_SUBSUBSECTION:
1912 s << par->getCounter(i - 3) << '.'
1913 << par->getCounter(i - 2) << '.'
1914 << par->getCounter(i - 1) << '.'
1915 << par->getCounter(i);
1918 case LABEL_COUNTER_PARAGRAPH:
1919 s << par->getCounter(i - 4) << '.'
1920 << par->getCounter(i - 3) << '.'
1921 << par->getCounter(i - 2) << '.'
1922 << par->getCounter(i - 1) << '.'
1923 << par->getCounter(i);
1925 case LABEL_COUNTER_SUBPARAGRAPH:
1926 s << par->getCounter(i - 5) << '.'
1927 << par->getCounter(i - 4) << '.'
1928 << par->getCounter(i - 3) << '.'
1929 << par->getCounter(i - 2) << '.'
1930 << par->getCounter(i - 1) << '.'
1931 << par->getCounter(i);
1935 // Can this ever be reached? And in the
1936 // case it is, how can this be correct?
1938 s << par->getCounter(i) << '.';
1941 } else { // appendix
1942 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1943 case LABEL_COUNTER_CHAPTER:
1944 if (par->isRightToLeftPar(buf->params))
1945 s << hebrewCounter(par->getCounter(i));
1947 s << alphaCounter(par->getCounter(i));
1949 case LABEL_COUNTER_SECTION:
1950 if (par->isRightToLeftPar(buf->params))
1951 s << hebrewCounter(par->getCounter(i - 1));
1953 s << alphaCounter(par->getCounter(i - 1));
1956 << par->getCounter(i);
1959 case LABEL_COUNTER_SUBSECTION:
1960 if (par->isRightToLeftPar(buf->params))
1961 s << hebrewCounter(par->getCounter(i - 2));
1963 s << alphaCounter(par->getCounter(i - 2));
1966 << par->getCounter(i-1) << '.'
1967 << par->getCounter(i);
1970 case LABEL_COUNTER_SUBSUBSECTION:
1971 if (par->isRightToLeftPar(buf->params))
1972 s << hebrewCounter(par->getCounter(i-3));
1974 s << alphaCounter(par->getCounter(i-3));
1977 << par->getCounter(i-2) << '.'
1978 << par->getCounter(i-1) << '.'
1979 << par->getCounter(i);
1982 case LABEL_COUNTER_PARAGRAPH:
1983 if (par->isRightToLeftPar(buf->params))
1984 s << hebrewCounter(par->getCounter(i-4));
1986 s << alphaCounter(par->getCounter(i-4));
1989 << par->getCounter(i-3) << '.'
1990 << par->getCounter(i-2) << '.'
1991 << par->getCounter(i-1) << '.'
1992 << par->getCounter(i);
1995 case LABEL_COUNTER_SUBPARAGRAPH:
1996 if (par->isRightToLeftPar(buf->params))
1997 s << hebrewCounter(par->getCounter(i-5));
1999 s << alphaCounter(par->getCounter(i-5));
2002 << par->getCounter(i-4) << '.'
2003 << par->getCounter(i-3) << '.'
2004 << par->getCounter(i-2) << '.'
2005 << par->getCounter(i-1) << '.'
2006 << par->getCounter(i);
2010 // Can this ever be reached? And in the
2011 // case it is, how can this be correct?
2013 s << par->getCounter(i) << '.';
2019 par->params.labelString(par->params.labelString() +s.str().c_str());
2020 // We really want to remove the c_str as soon as
2023 for (i++; i < 10; ++i) {
2024 // reset the following counters
2025 par->setCounter(i, 0);
2027 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
2028 for (i++; i < 10; ++i) {
2029 // reset the following counters
2030 par->setCounter(i, 0);
2032 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
2033 par->incCounter(i + par->enumdepth);
2034 int number = par->getCounter(i + par->enumdepth);
2036 std::ostringstream s;
2038 switch (par->enumdepth) {
2040 if (par->isRightToLeftPar(buf->params))
2042 << hebrewCounter(number)
2046 << loweralphaCounter(number)
2050 if (par->isRightToLeftPar(buf->params))
2051 s << '.' << romanCounter(number);
2053 s << romanCounter(number) << '.';
2056 if (par->isRightToLeftPar(buf->params))
2058 << alphaCounter(number);
2060 s << alphaCounter(number)
2064 if (par->isRightToLeftPar(buf->params))
2071 par->params.labelString(s.str().c_str());
2072 // we really want to get rid of that c_str()
2074 for (i += par->enumdepth + 1; i < 10; ++i)
2075 par->setCounter(i, 0); /* reset the following counters */
2078 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2079 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2081 int number = par->getCounter(i);
2083 InsetCommandParams p( "bibitem" );
2084 par->bibkey = new InsetBibKey(p);
2086 par->bibkey->setCounter(number);
2087 par->params.labelString(layout.labelstring());
2089 // In biblio should't be following counters but...
2091 string s = layout.labelstring();
2093 // the caption hack:
2094 if (layout.labeltype == LABEL_SENSITIVE) {
2095 bool isOK (par->InInset() && par->InInset()->owner() &&
2096 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2098 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2099 && (par->footnotekind == LyXParagraph::FIG
2100 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2101 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2102 ? ":øåéà " : "Figure:";
2103 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2104 && (par->footnotekind == LyXParagraph::TAB
2105 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2106 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2107 ? ":äìáè" : "Table:";
2108 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2109 && par->footnotekind == LyXParagraph::ALGORITHM) {
2110 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2111 ? ":Ãúéøåâìà " : "Algorithm:";
2115 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2117 = floatList.getType(tmp->type());
2118 // We should get the correct number here too.
2119 s = fl.name() + " #:";
2121 /* par->SetLayout(0);
2122 s = layout->labelstring; */
2123 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2124 ? " :úåòîùî øñç" : "Senseless: ";
2127 par->params.labelString(s);
2129 /* reset the enumeration counter. They are always resetted
2130 * when there is any other layout between */
2131 for (int i = 6 + par->enumdepth; i < 10; ++i)
2132 par->setCounter(i, 0);
2137 /* Updates all counters BEHIND the row. Changed paragraphs
2138 * with a dynamic left margin will be rebroken. */
2139 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2146 } else if (row->par()->next_
2147 && row->par()->next_->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
2148 par = row->par()->LastPhysicalPar()->next();
2150 par = row->par()->next_;
2157 par = row->par()->next();
2162 while (row->par() != par)
2165 SetCounter(bview->buffer(), par);
2167 /* now check for the headline layouts. remember that they
2168 * have a dynamic left margin */
2173 ( textclasslist.Style(bview->buffer()->params.textclass,
2174 par->layout).margintype == MARGIN_DYNAMIC
2175 || textclasslist.Style(bview->buffer()->params.textclass,
2176 par->layout).labeltype == LABEL_SENSITIVE)
2179 /* Rebreak the paragraph */
2180 RemoveParagraph(row);
2181 AppendParagraph(bview, row);
2184 /* think about the damned open footnotes! */
2185 while (par->next() &&
2186 (par->next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2187 || par->next()->IsDummy())){
2189 if (par->IsDummy()) {
2190 while (row->par() != par)
2192 RemoveParagraph(row);
2193 AppendParagraph(bview, row);
2199 par = par->LastPhysicalPar()->next();
2208 /* insets an inset. */
2209 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2211 if (!cursor.par()->InsertInsetAllowed(inset))
2213 SetUndo(bview->buffer(), Undo::INSERT,
2215 cursor.par()->ParFromPos(cursor.pos())->previous_,
2216 cursor.par()->ParFromPos(cursor.pos())->next_
2218 cursor.par()->previous(),
2219 cursor.par()->next()
2222 cursor.par()->InsertInset(cursor.pos(), inset);
2223 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2224 * The character will not be inserted a
2227 // If we enter a highly editable inset the cursor should be to before
2228 // the inset. This couldn't happen before as Undo was not handled inside
2229 // inset now after the Undo LyX tries to call inset->Edit(...) again
2230 // and cannot do this as the cursor is behind the inset and GetInset
2231 // does not return the inset!
2232 if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
2233 CursorLeft(bview, true);
2239 void LyXText::copyEnvironmentType()
2241 copylayouttype = cursor.par()->GetLayout();
2245 void LyXText::pasteEnvironmentType(BufferView * bview)
2247 SetLayout(bview, copylayouttype);
2251 void LyXText::CutSelection(BufferView * bview, bool doclear)
2253 // Stuff what we got on the clipboard. Even if there is no selection.
2255 // There is a problem with having the stuffing here in that the
2256 // larger the selection the slower LyX will get. This can be
2257 // solved by running the line below only when the selection has
2258 // finished. The solution used currently just works, to make it
2259 // faster we need to be more clever and probably also have more
2260 // calls to stuffClipboard. (Lgb)
2261 bview->stuffClipboard(selectionAsString(bview->buffer()));
2263 // This doesn't make sense, if there is no selection
2267 // OK, we have a selection. This is always between sel_start_cursor
2268 // and sel_end_cursor
2270 // Check whether there are half footnotes in the selection
2271 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2272 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2273 LyXParagraph * tmppar = sel_start_cursor.par();
2274 while (tmppar != sel_end_cursor.par()){
2275 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2276 WriteAlert(_("Impossible operation"),
2277 _("Don't know what to do with half floats."),
2281 tmppar = tmppar->next();
2286 // make sure that the depth behind the selection are restored, too
2288 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->next();
2290 LyXParagraph * endpar = sel_end_cursor.par()->next();
2292 LyXParagraph * undoendpar = endpar;
2294 if (endpar && endpar->GetDepth()) {
2295 while (endpar && endpar->GetDepth()) {
2297 endpar = endpar->LastPhysicalPar()->next();
2299 endpar = endpar->next();
2301 undoendpar = endpar;
2303 } else if (endpar) {
2304 endpar = endpar->next(); // because of parindents etc.
2307 SetUndo(bview->buffer(), Undo::DELETE,
2310 .par()->ParFromPos(sel_start_cursor.pos())->previous_,
2312 sel_start_cursor.par()->previous(),
2318 // there are two cases: cut only within one paragraph or
2319 // more than one paragraph
2321 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2322 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2324 if (sel_start_cursor.par() == sel_end_cursor.par())
2327 // only within one paragraph
2328 endpar = sel_start_cursor.par();
2329 int pos = sel_end_cursor.pos();
2330 cap.cutSelection(sel_start_cursor.par(), &endpar,
2331 sel_start_cursor.pos(), pos,
2332 bview->buffer()->params.textclass, doclear);
2333 sel_end_cursor.pos(pos);
2335 endpar = sel_end_cursor.par();
2337 int pos = sel_end_cursor.pos();
2338 cap.cutSelection(sel_start_cursor.par(), &endpar,
2339 sel_start_cursor.pos(), pos,
2340 bview->buffer()->params.textclass, doclear);
2342 sel_end_cursor.par(endpar);
2343 sel_end_cursor.pos(pos);
2344 cursor.pos(sel_end_cursor.pos());
2346 endpar = endpar->next();
2348 // sometimes necessary
2350 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2352 RedoParagraphs(bview, sel_start_cursor, endpar);
2354 ClearSelection(bview);
2355 cursor = sel_start_cursor;
2356 SetCursor(bview, cursor.par(), cursor.pos());
2357 sel_cursor = cursor;
2358 UpdateCounters(bview, cursor.row());
2362 void LyXText::CopySelection(BufferView * bview)
2364 // Stuff what we got on the clipboard. Even if there is no selection.
2366 // There is a problem with having the stuffing here in that the
2367 // larger the selection the slower LyX will get. This can be
2368 // solved by running the line below only when the selection has
2369 // finished. The solution used currently just works, to make it
2370 // faster we need to be more clever and probably also have more
2371 // calls to stuffClipboard. (Lgb)
2372 bview->stuffClipboard(selectionAsString(bview->buffer()));
2374 // this doesnt make sense, if there is no selection
2378 // ok we have a selection. This is always between sel_start_cursor
2379 // and sel_end cursor
2382 /* check wether there are half footnotes in the selection */
2383 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2384 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2385 LyXParagraph * tmppar = sel_start_cursor.par();
2386 while (tmppar != sel_end_cursor.par()) {
2387 if (tmppar->footnoteflag !=
2388 sel_end_cursor.par()->footnoteflag) {
2389 WriteAlert(_("Impossible operation"),
2390 _("Don't know what to do"
2391 " with half floats."),
2395 tmppar = tmppar->next();
2400 // copy behind a space if there is one
2402 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2404 while (sel_start_cursor.par()->size() > sel_start_cursor.pos()
2406 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2407 && (sel_start_cursor.par() != sel_end_cursor.par()
2408 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2409 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2413 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2414 sel_start_cursor.pos(), sel_end_cursor.pos(),
2415 bview->buffer()->params.textclass);
2419 void LyXText::PasteSelection(BufferView * bview)
2423 // this does not make sense, if there is nothing to paste
2424 if (!cap.checkPastePossible(cursor.par()))
2427 SetUndo(bview->buffer(), Undo::INSERT,
2429 cursor.par()->ParFromPos(cursor.pos())->previous_,
2430 cursor.par()->ParFromPos(cursor.pos())->next_
2432 cursor.par()->previous(),
2433 cursor.par()->next()
2437 LyXParagraph * endpar;
2438 LyXParagraph * actpar = cursor.par();
2440 int pos = cursor.pos();
2441 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2443 RedoParagraphs(bview, cursor, endpar);
2445 SetCursor(bview, cursor.par(), cursor.pos());
2446 ClearSelection(bview);
2448 sel_cursor = cursor;
2449 SetCursor(bview, actpar, pos);
2450 SetSelection(bview);
2451 UpdateCounters(bview, cursor.row());
2455 // returns a pointer to the very first LyXParagraph
2456 LyXParagraph * LyXText::FirstParagraph() const
2458 return OwnerParagraph();
2462 // sets the selection over the number of characters of string, no check!!
2463 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2465 sel_cursor = cursor;
2466 for (int i = 0; str[i]; ++i)
2468 SetSelection(bview);
2472 // simple replacing. The font of the first selected character is used
2473 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2476 SetCursorParUndo(bview->buffer());
2479 if (!selection) { // create a dummy selection
2480 sel_end_cursor = cursor;
2481 sel_start_cursor = cursor;
2484 // Get font setting before we cut
2485 LyXParagraph::size_type pos = sel_end_cursor.pos();
2486 LyXFont const font = sel_start_cursor.par()
2487 ->GetFontSettings(bview->buffer()->params,
2488 sel_start_cursor.pos());
2490 // Insert the new string
2491 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2492 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2496 // Cut the selection
2497 CutSelection(bview);
2503 // needed to insert the selection
2504 void LyXText::InsertStringA(BufferView * bview, string const & str)
2506 LyXParagraph * par = cursor.par();
2507 LyXParagraph::size_type pos = cursor.pos();
2508 LyXParagraph::size_type a = 0;
2509 LyXParagraph * endpar = cursor.par()->next();
2511 SetCursorParUndo(bview->buffer());
2514 textclasslist.Style(bview->buffer()->params.textclass,
2515 cursor.par()->GetLayout()).isEnvironment();
2516 // only to be sure, should not be neccessary
2517 ClearSelection(bview);
2519 // insert the string, don't insert doublespace
2520 string::size_type i = 0;
2521 while (i < str.length()) {
2522 if (str[i] != '\n') {
2524 && i + 1 < str.length() && str[i + 1] != ' '
2525 && pos && par->GetChar(pos - 1)!= ' ') {
2526 par->InsertChar(pos, ' ', current_font);
2528 } else if (str[i] == ' ') {
2529 InsetSpecialChar * new_inset =
2530 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2531 if (par->InsertInsetAllowed(new_inset)) {
2532 par->InsertInset(pos, new_inset,
2538 } else if (str[i] == '\t') {
2539 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2540 InsetSpecialChar * new_inset =
2541 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2542 if (par->InsertInsetAllowed(new_inset)) {
2543 par->InsertInset(pos, new_inset,
2550 } else if (str[i] != 13 &&
2551 // Ignore unprintables
2552 (str[i] & 127) >= ' ') {
2553 par->InsertChar(pos, str[i], current_font);
2557 if (!par->size()) { // par is empty
2558 InsetSpecialChar * new_inset =
2559 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2560 if (par->InsertInsetAllowed(new_inset)) {
2561 par->InsertInset(pos,
2569 par->BreakParagraph(bview->buffer()->params, pos, flag);
2576 RedoParagraphs(bview, cursor, endpar);
2577 SetCursor(bview, cursor.par(), cursor.pos());
2578 sel_cursor = cursor;
2579 SetCursor(bview, par, pos);
2580 SetSelection(bview);
2584 /* turns double-CR to single CR, others where converted into one blank and 13s
2585 * that are ignored .Double spaces are also converted into one. Spaces at
2586 * the beginning of a paragraph are forbidden. tabs are converted into one
2587 * space. then InsertStringA is called */
2588 void LyXText::InsertStringB(BufferView * bview, string const & s)
2591 string::size_type i = 1;
2592 while (i < str.length()) {
2595 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2597 if (str[i] == '\n' && i + 1 < str.length()) {
2598 if (str[i + 1] != '\n') {
2599 if (str[i - 1] != ' ')
2604 while (i + 1 < str.length()
2605 && (str[i + 1] == ' '
2606 || str[i + 1] == '\t'
2607 || str[i + 1] == '\n'
2608 || str[i + 1] == 13)) {
2615 InsertStringA(bview, str);
2619 bool LyXText::GotoNextInset(BufferView * bview,
2620 std::vector<Inset::Code> const & codes,
2621 string const & contents) const
2623 LyXCursor res = cursor;
2627 if (res.pos() < res.par()->Last() - 1) {
2629 if (res.pos() < res.par()->size() - 1) {
2631 res.pos(res.pos() + 1);
2633 res.par(res.par()->next());
2637 } while (res.par() &&
2638 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2639 && (inset = res.par()->GetInset(res.pos())) != 0
2640 && find(codes.begin(), codes.end(), inset->LyxCode())
2642 && (contents.empty() ||
2643 static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
2647 SetCursor(bview, res.par(), res.pos());
2654 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2655 LyXParagraph::size_type pos)
2657 LyXCursor tmpcursor;
2660 LyXParagraph::size_type z;
2661 Row * row = GetRow(par, pos, y);
2663 // is there a break one row above
2664 if (row->previous() && row->previous()->par() == row->par()) {
2665 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2666 if (z >= row->pos()) {
2667 // set the dimensions of the row above
2668 y -= row->previous()->height();
2670 refresh_row = row->previous();
2671 status = LyXText::NEED_MORE_REFRESH;
2673 BreakAgain(bview, row->previous());
2675 // set the cursor again. Otherwise
2676 // dangling pointers are possible
2677 SetCursor(bview, cursor.par(), cursor.pos(),
2678 false, cursor.boundary());
2679 sel_cursor = cursor;
2684 int const tmpheight = row->height();
2685 LyXParagraph::size_type const tmplast = RowLast(row);
2689 BreakAgain(bview, row);
2690 if (row->height() == tmpheight && RowLast(row) == tmplast)
2691 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2693 status = LyXText::NEED_MORE_REFRESH;
2695 // check the special right address boxes
2696 if (textclasslist.Style(bview->buffer()->params.textclass,
2697 par->GetLayout()).margintype
2698 == MARGIN_RIGHT_ADDRESS_BOX) {
2705 RedoDrawingOfParagraph(bview, tmpcursor);
2708 // set the cursor again. Otherwise dangling pointers are possible
2709 // also set the selection
2713 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2714 false, sel_cursor.boundary());
2715 sel_cursor = cursor;
2716 SetCursorIntern(bview, sel_start_cursor.par(),
2717 sel_start_cursor.pos(),
2718 false, sel_start_cursor.boundary());
2719 sel_start_cursor = cursor;
2720 SetCursorIntern(bview, sel_end_cursor.par(),
2721 sel_end_cursor.pos(),
2722 false, sel_end_cursor.boundary());
2723 sel_end_cursor = cursor;
2724 SetCursorIntern(bview, last_sel_cursor.par(),
2725 last_sel_cursor.pos(),
2726 false, last_sel_cursor.boundary());
2727 last_sel_cursor = cursor;
2730 SetCursorIntern(bview, cursor.par(), cursor.pos(),
2731 false, cursor.boundary());
2735 // returns false if inset wasn't found
2736 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2738 // first check the current paragraph
2739 int pos = cursor.par()->GetPositionOfInset(inset);
2741 CheckParagraph(bview, cursor.par(), pos);
2745 // check every paragraph
2747 LyXParagraph * par = FirstParagraph();
2750 // make sure the paragraph is open
2751 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2753 pos = par->GetPositionOfInset(inset);
2755 CheckParagraph(bview, par, pos);
2768 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2769 LyXParagraph::size_type pos,
2770 bool setfont, bool boundary) const
2772 LyXCursor old_cursor = cursor;
2773 SetCursorIntern(bview, par, pos, setfont, boundary);
2774 DeleteEmptyParagraphMechanism(bview, old_cursor);
2778 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2779 LyXParagraph::size_type pos, bool boundary) const
2782 // correct the cursor position if impossible
2783 if (pos > par->Last()){
2784 LyXParagraph * tmppar = par->ParFromPos(pos);
2785 pos = par->PositionInParFromPos(pos);
2788 if (par->IsDummy() && par->previous_ &&
2789 par->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2790 while (par->previous_ &&
2791 ((par->previous_->IsDummy() &&
2792 (par->previous_->previous_->footnoteflag ==
2793 LyXParagraph::CLOSED_FOOTNOTE)) ||
2794 (par->previous_->footnoteflag ==
2795 LyXParagraph::CLOSED_FOOTNOTE))) {
2796 par = par->previous_;
2797 if (par->IsDummy() &&
2798 (par->previous_->footnoteflag ==
2799 LyXParagraph::CLOSED_FOOTNOTE))
2800 pos += par->size() + 1;
2802 if (par->previous_) {
2803 par = par->previous_;
2805 pos += par->size() + 1;
2810 cur.boundary(boundary);
2812 /* get the cursor y position in text */
2814 Row * row = GetRow(par, pos, y);
2815 /* y is now the beginning of the cursor row */
2816 y += row->baseline();
2817 /* y is now the cursor baseline */
2820 /* now get the cursors x position */
2822 float fill_separator, fill_hfill, fill_label_hfill;
2823 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2825 LyXParagraph::size_type cursor_vpos = 0;
2826 LyXParagraph::size_type last = RowLastPrintable(row);
2828 if (pos > last + 1) // This shouldn't happen.
2830 else if (pos < row->pos())
2833 if (last < row->pos())
2834 cursor_vpos = row->pos();
2835 else if (pos > last && !boundary)
2836 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2837 ? row->pos() : last + 1;
2838 else if (pos > row->pos() &&
2839 (pos > last || boundary))
2840 /// Place cursor after char at (logical) position pos - 1
2841 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2842 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2844 /// Place cursor before char at (logical) position pos
2845 cursor_vpos = (bidi_level(pos) % 2 == 0)
2846 ? log2vis(pos) : log2vis(pos) + 1;
2848 LyXParagraph::size_type main_body =
2849 BeginningOfMainBody(bview->buffer(), row->par());
2850 if ((main_body > 0) &&
2851 ((main_body-1 > last) ||
2852 !row->par()->IsLineSeparator(main_body-1)))
2855 for (LyXParagraph::size_type vpos = row->pos();
2856 vpos < cursor_vpos; ++vpos) {
2857 pos = vis2log(vpos);
2858 if (main_body > 0 && pos == main_body - 1) {
2859 x += fill_label_hfill +
2860 lyxfont::width(textclasslist.Style(
2861 bview->buffer()->params.textclass,
2862 row->par()->GetLayout())
2864 GetFont(bview->buffer(), row->par(), -2));
2865 if (row->par()->IsLineSeparator(main_body-1))
2866 x -= SingleWidth(bview, row->par(),main_body-1);
2868 if (HfillExpansion(bview->buffer(), row, pos)) {
2869 x += SingleWidth(bview, row->par(), pos);
2870 if (pos >= main_body)
2873 x += fill_label_hfill;
2874 } else if (row->par()->IsSeparator(pos)) {
2875 x += SingleWidth(bview, row->par(), pos);
2876 if (pos >= main_body)
2877 x += fill_separator;
2879 x += SingleWidth(bview, row->par(), pos);
2888 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2889 LyXParagraph::size_type pos,
2890 bool setfont, bool boundary) const
2892 SetCursor(bview, cursor, par, pos, boundary);
2894 SetCurrentFont(bview);
2898 void LyXText::SetCurrentFont(BufferView * bview) const
2900 LyXParagraph::size_type pos = cursor.pos();
2901 if (cursor.boundary() && pos > 0)
2906 if (pos == cursor.par()->Last())
2908 if (pos == cursor.par()->size())
2911 else if (cursor.par()->IsSeparator(pos)) {
2912 if (pos > cursor.row()->pos() &&
2913 bidi_level(pos) % 2 ==
2914 bidi_level(pos - 1) % 2)
2917 else if (pos + 1 < cursor.par()->Last())
2919 else if (pos + 1 < cursor.par()->size())
2926 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2927 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2930 if (cursor.pos() == cursor.par()->Last() &&
2932 if (cursor.pos() == cursor.par()->size() &&
2934 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2935 !cursor.boundary()) {
2936 Language const * lang =
2937 cursor.par()->getParLanguage(bview->buffer()->params);
2938 current_font.setLanguage(lang);
2939 current_font.setNumber(LyXFont::OFF);
2940 real_current_font.setLanguage(lang);
2941 real_current_font.setNumber(LyXFont::OFF);
2946 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2948 LyXCursor old_cursor = cursor;
2950 /* get the row first */
2952 Row * row = GetRowNearY(y);
2953 cursor.par(row->par());
2956 int column = GetColumnNearX(bview, row, x, bound);
2957 cursor.pos(row->pos() + column);
2959 cursor.y(y + row->baseline());
2961 cursor.boundary(bound);
2962 SetCurrentFont(bview);
2963 DeleteEmptyParagraphMechanism(bview, old_cursor);
2967 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2970 /* get the row first */
2972 Row * row = GetRowNearY(y);
2974 int column = GetColumnNearX(bview, row, x, bound);
2976 cur.par(row->par());
2977 cur.pos(row->pos() + column);
2979 cur.y(y + row->baseline());
2981 cur.boundary(bound);
2985 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2987 if (cursor.pos() > 0) {
2988 bool boundary = cursor.boundary();
2989 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2990 if (!internal && !boundary &&
2991 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2992 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2993 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2994 LyXParagraph * par = cursor.par()->previous();
2996 SetCursor(bview, par, par->Last());
2998 SetCursor(bview, par, par->size());
3004 void LyXText::CursorRight(BufferView * bview, bool internal) const
3006 if (!internal && cursor.boundary() &&
3007 !cursor.par()->IsNewline(cursor.pos()))
3008 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
3010 else if (cursor.pos() < cursor.par()->Last()) {
3012 else if (cursor.pos() < cursor.par()->size()) {
3014 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
3016 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
3017 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
3018 } else if (cursor.par()->next())
3019 SetCursor(bview, cursor.par()->next(), 0);
3023 void LyXText::CursorUp(BufferView * bview) const
3025 SetCursorFromCoordinates(bview, cursor.x_fix(),
3026 cursor.y() - cursor.row()->baseline() - 1);
3030 void LyXText::CursorDown(BufferView * bview) const
3032 SetCursorFromCoordinates(bview, cursor.x_fix(),
3033 cursor.y() - cursor.row()->baseline()
3034 + cursor.row()->height() + 1);
3038 void LyXText::CursorUpParagraph(BufferView * bview) const
3040 if (cursor.pos() > 0) {
3041 SetCursor(bview, cursor.par(), 0);
3043 else if (cursor.par()->previous()) {
3044 SetCursor(bview, cursor.par()->previous(), 0);
3049 void LyXText::CursorDownParagraph(BufferView * bview) const
3051 if (cursor.par()->next()) {
3052 SetCursor(bview, cursor.par()->next(), 0);
3055 SetCursor(bview, cursor.par(), cursor.par()->Last());
3057 SetCursor(bview, cursor.par(), cursor.par()->size());
3063 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3064 LyXCursor const & old_cursor) const
3066 // Would be wrong to delete anything if we have a selection.
3067 if (selection) return;
3069 // We allow all kinds of "mumbo-jumbo" when freespacing.
3070 if (textclasslist.Style(bview->buffer()->params.textclass,
3071 old_cursor.par()->GetLayout()).free_spacing)
3074 bool deleted = false;
3076 /* Ok I'll put some comments here about what is missing.
3077 I have fixed BackSpace (and thus Delete) to not delete
3078 double-spaces automagically. I have also changed Cut,
3079 Copy and Paste to hopefully do some sensible things.
3080 There are still some small problems that can lead to
3081 double spaces stored in the document file or space at
3082 the beginning of paragraphs. This happens if you have
3083 the cursor betwenn to spaces and then save. Or if you
3084 cut and paste and the selection have a space at the
3085 beginning and then save right after the paste. I am
3086 sure none of these are very hard to fix, but I will
3087 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3088 that I can get some feedback. (Lgb)
3091 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3092 // delete the LineSeparator.
3095 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3096 // delete the LineSeparator.
3099 // If the pos around the old_cursor were spaces, delete one of them.
3100 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3101 // Only if the cursor has really moved
3103 if (old_cursor.pos() > 0
3105 && old_cursor.pos() < old_cursor.par()->Last()
3107 && old_cursor.pos() < old_cursor.par()->size()
3109 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3110 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3111 old_cursor.par()->Erase(old_cursor.pos() - 1);
3112 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3114 if (old_cursor.par() == cursor.par() &&
3115 cursor.pos() > old_cursor.pos()) {
3116 SetCursorIntern(bview, cursor.par(),
3119 SetCursorIntern(bview, cursor.par(),
3125 // Do not delete empty paragraphs with keepempty set.
3126 if ((textclasslist.Style(bview->buffer()->params.textclass,
3127 old_cursor.par()->GetLayout())).keepempty)
3130 LyXCursor tmpcursor;
3133 if (old_cursor.par() != cursor.par()) {
3134 if ((old_cursor.par()->Last() == 0
3135 || (old_cursor.par()->Last() == 1
3136 && old_cursor.par()->IsLineSeparator(0)))
3137 && old_cursor.par()->FirstPhysicalPar()
3138 == old_cursor.par()->LastPhysicalPar()
3140 if (old_cursor.par() != cursor.par()) {
3141 if ((old_cursor.par()->size() == 0
3142 || (old_cursor.par()->size() == 1
3143 && old_cursor.par()->IsLineSeparator(0)))
3146 // ok, we will delete anything
3148 // make sure that you do not delete any environments
3151 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3152 !(old_cursor.row()->previous()
3153 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3154 && !(old_cursor.row()->next()
3155 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3156 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3157 && ((old_cursor.row()->previous()
3158 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3159 || (old_cursor.row()->next()
3160 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3163 status = LyXText::NEED_MORE_REFRESH;
3166 if (old_cursor.row()->previous()) {
3167 refresh_row = old_cursor.row()->previous();
3168 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3170 cursor = old_cursor; // that undo can restore the right cursor position
3172 LyXParagraph * endpar = old_cursor.par()->next_;
3173 if (endpar && endpar->GetDepth()) {
3174 while (endpar && endpar->GetDepth()) {
3175 endpar = endpar->LastPhysicalPar()->next();
3178 SetUndo(bview->buffer(), Undo::DELETE,
3179 old_cursor.par()->previous_,
3184 RemoveRow(old_cursor.row());
3185 if (OwnerParagraph() == old_cursor.par()) {
3186 OwnerParagraph(OwnerParagraph()->next_);
3189 LyXParagraph * endpar = old_cursor.par()->next();
3190 if (endpar && endpar->GetDepth()) {
3191 while (endpar && endpar->GetDepth()) {
3192 endpar = endpar->next();
3195 SetUndo(bview->buffer(), Undo::DELETE,
3196 old_cursor.par()->previous(),
3201 RemoveRow(old_cursor.row());
3202 if (OwnerParagraph() == old_cursor.par()) {
3203 OwnerParagraph(OwnerParagraph()->next());
3207 delete old_cursor.par();
3209 /* Breakagain the next par. Needed
3210 * because of the parindent that
3211 * can occur or dissappear. The
3212 * next row can change its height,
3213 * if there is another layout before */
3214 if (refresh_row->next()) {
3215 BreakAgain(bview, refresh_row->next());
3216 UpdateCounters(bview, refresh_row);
3218 SetHeightOfRow(bview, refresh_row);
3220 refresh_row = old_cursor.row()->next();
3221 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3224 cursor = old_cursor; // that undo can restore the right cursor position
3226 LyXParagraph * endpar = old_cursor.par()->next_;
3227 if (endpar && endpar->GetDepth()) {
3228 while (endpar && endpar->GetDepth()) {
3229 endpar = endpar->LastPhysicalPar()->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 LyXParagraph * endpar = old_cursor.par()->next();
3245 if (endpar && endpar->GetDepth()) {
3246 while (endpar && endpar->GetDepth()) {
3247 endpar = endpar->next();
3250 SetUndo(bview->buffer(), Undo::DELETE,
3251 old_cursor.par()->previous(),
3256 RemoveRow(old_cursor.row());
3258 if (OwnerParagraph() == old_cursor.par()) {
3259 OwnerParagraph(OwnerParagraph()->next());
3262 delete old_cursor.par();
3264 /* Breakagain the next par. Needed
3265 because of the parindent that can
3266 occur or dissappear.
3267 The next row can change its height,
3268 if there is another layout before
3271 BreakAgain(bview, refresh_row);
3272 UpdateCounters(bview, refresh_row->previous());
3278 SetCursorIntern(bview, cursor.par(), cursor.pos());
3280 if (sel_cursor.par() == old_cursor.par()
3281 && sel_cursor.pos() == sel_cursor.pos()) {
3282 // correct selection
3283 sel_cursor = cursor;
3290 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3291 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3293 SetCursorIntern(bview, cursor.par(), cursor.pos());
3294 sel_cursor = cursor;
3302 LyXParagraph * LyXText::GetParFromID(int id)
3304 LyXParagraph * result = FirstParagraph();
3305 while (result && result->id() != id)
3306 result = result->next_;
3310 LyXParagraph * LyXText::GetParFromID(int id)
3312 LyXParagraph * result = FirstParagraph();
3313 while (result && result->id() != id)
3314 result = result->next();
3321 bool LyXText::TextUndo(BufferView * bview)
3325 // returns false if no undo possible
3326 Undo * undo = bview->buffer()->undostack.pop();
3330 bview->buffer()->redostack
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::TextRedo(BufferView * bview)
3343 // returns false if no redo possible
3344 Undo * undo = bview->buffer()->redostack.pop();
3348 bview->buffer()->undostack
3349 .push(CreateUndo(bview->buffer(), undo->kind,
3350 GetParFromID(undo->number_of_before_par),
3351 GetParFromID(undo->number_of_behind_par)));
3353 return TextHandleUndo(bview, undo);
3357 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3361 // returns false if no undo possible
3362 bool result = false;
3364 LyXParagraph * before =
3365 GetParFromID(undo->number_of_before_par);
3366 LyXParagraph * behind =
3367 GetParFromID(undo->number_of_behind_par);
3368 LyXParagraph * tmppar;
3369 LyXParagraph * tmppar2;
3370 LyXParagraph * endpar;
3371 LyXParagraph * tmppar5;
3373 // if there's no before take the beginning
3374 // of the document for redoing
3376 SetCursorIntern(bview, FirstParagraph(), 0);
3378 // replace the paragraphs with the undo informations
3380 LyXParagraph * tmppar3 = undo->par;
3381 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3382 LyXParagraph * tmppar4 = tmppar3;
3385 while (tmppar4->next_)
3386 tmppar4 = tmppar4->next_;
3387 } // get last undo par
3389 // now remove the old text if there is any
3390 if (before != behind || (!behind && !before)) {
3392 tmppar5 = before->next();
3394 tmppar5 = OwnerParagraph();
3396 while (tmppar5 && tmppar5 != behind) {
3398 tmppar5 = tmppar5->next();
3399 // a memory optimization for edit: Only layout information
3400 // is stored in the undo. So restore the text informations.
3401 if (undo->kind == Undo::EDIT) {
3402 tmppar2->setContentsFromPar(tmppar);
3403 tmppar->clearContents();
3404 tmppar2 = tmppar2->next();
3411 while (tmppar4->next())
3412 tmppar4 = tmppar4->next();
3413 } // get last undo par
3415 // now remove the old text if there is any
3416 if (before != behind || (!behind && !before)) {
3418 tmppar5 = before->next();
3420 tmppar5 = OwnerParagraph();
3422 while (tmppar5 && tmppar5 != behind) {
3424 tmppar5 = tmppar5->next();
3425 // a memory optimization for edit: Only layout information
3426 // is stored in the undo. So restore the text informations.
3427 if (undo->kind == Undo::EDIT) {
3428 tmppar2->setContentsFromPar(tmppar);
3429 tmppar->clearContents();
3430 tmppar2 = tmppar2->next();
3436 // put the new stuff in the list if there is one
3439 before->next(tmppar3);
3441 OwnerParagraph(tmppar3);
3442 tmppar3->previous(before);
3445 OwnerParagraph(behind);
3448 tmppar4->next(behind);
3450 behind->previous(tmppar4);
3454 // Set the cursor for redoing
3457 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3459 SetCursorIntern(bview, before, 0);
3462 // check wether before points to a closed float and open it if necessary
3463 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3464 && before->next_ && before->next_->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3466 while (tmppar4->previous_ &&
3467 tmppar4->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3468 tmppar4 = tmppar4->previous_;
3469 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3470 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3471 tmppar4 = tmppar4->next_;
3478 // open a cosed footnote at the end if necessary
3479 if (behind && behind->previous_ &&
3480 behind->previous_->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3481 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3482 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3483 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3484 behind = behind->next_;
3489 // calculate the endpar for redoing the paragraphs.
3492 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3493 endpar = behind->LastPhysicalPar()->next();
3495 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->next();
3497 endpar = behind->next();
3502 tmppar = GetParFromID(undo->number_of_cursor_par);
3503 RedoParagraphs(bview, cursor, endpar);
3505 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3506 UpdateCounters(bview, cursor.row());
3516 void LyXText::FinishUndo()
3520 // makes sure the next operation will be stored
3521 undo_finished = true;
3525 void LyXText::FreezeUndo()
3529 // this is dangerous and for internal use only
3534 void LyXText::UnFreezeUndo()
3538 // this is dangerous and for internal use only
3539 undo_frozen = false;
3543 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3544 LyXParagraph const * before,
3545 LyXParagraph const * behind) const
3550 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3551 buf->redostack.clear();
3555 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3556 LyXParagraph const * before, LyXParagraph const * behind)
3560 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3564 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3565 LyXParagraph const * before,
3566 LyXParagraph const * behind) const
3571 int before_number = -1;
3572 int behind_number = -1;
3574 before_number = before->id();
3576 behind_number = behind->id();
3577 // Undo::EDIT and Undo::FINISH are
3578 // always finished. (no overlapping there)
3579 // overlapping only with insert and delete inside one paragraph:
3580 // Nobody wants all removed character
3581 // appear one by one when undoing.
3582 // EDIT is special since only layout information, not the
3583 // contents of a paragaph are stored.
3584 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3585 // check wether storing is needed
3586 if (!buf->undostack.empty() &&
3587 buf->undostack.top()->kind == kind &&
3588 buf->undostack.top()->number_of_before_par == before_number &&
3589 buf->undostack.top()->number_of_behind_par == behind_number ){
3594 // create a new Undo
3595 LyXParagraph * undopar;
3596 LyXParagraph * tmppar;
3597 LyXParagraph * tmppar2;
3599 LyXParagraph * start = 0;
3600 LyXParagraph * end = 0;
3604 start = before->next_;
3606 start = FirstParagraph();
3608 end = behind->previous_;
3610 end = FirstParagraph();
3614 if (start && end && (start != end->next_) &&
3615 ((before != behind) || (!before && !behind))) {
3617 tmppar2 = tmppar->Clone();
3618 tmppar2->id(tmppar->id());
3620 // a memory optimization: Just store the layout information
3622 if (kind == Undo::EDIT){
3623 //tmppar2->text.clear();
3624 tmppar2->clearContents();
3629 while (tmppar != end && tmppar->next_) {
3630 tmppar = tmppar->next_;
3631 tmppar2->next(tmppar->Clone());
3632 tmppar2->next_->id(tmppar->id());
3633 // a memory optimization: Just store the layout
3634 // information when only edit
3635 if (kind == Undo::EDIT){
3636 //tmppar2->next->text.clear();
3637 tmppar2->clearContents();
3639 tmppar2->next_->previous(tmppar2);
3640 tmppar2 = tmppar2->next_;
3644 undopar = 0; // nothing to replace (undo of delete maybe)
3646 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3647 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3650 start = const_cast<LyXParagraph*>(before->next());
3652 start = FirstParagraph();
3654 end = const_cast<LyXParagraph*>(behind->previous());
3656 end = FirstParagraph();
3660 if (start && end && (start != end->next()) &&
3661 ((before != behind) || (!before && !behind))) {
3663 tmppar2 = tmppar->Clone();
3664 tmppar2->id(tmppar->id());
3666 // a memory optimization: Just store the layout information
3668 if (kind == Undo::EDIT){
3669 //tmppar2->text.clear();
3670 tmppar2->clearContents();
3675 while (tmppar != end && tmppar->next()) {
3676 tmppar = tmppar->next();
3677 tmppar2->next(tmppar->Clone());
3678 tmppar2->next()->id(tmppar->id());
3679 // a memory optimization: Just store the layout
3680 // information when only edit
3681 if (kind == Undo::EDIT){
3682 //tmppar2->next->text.clear();
3683 tmppar2->clearContents();
3685 tmppar2->next()->previous(tmppar2);
3686 tmppar2 = tmppar2->next();
3690 undopar = 0; // nothing to replace (undo of delete maybe)
3692 int cursor_par = cursor.par()->id();
3693 int cursor_pos = cursor.pos();
3696 Undo * undo = new Undo(kind,
3697 before_number, behind_number,
3698 cursor_par, cursor_pos,
3701 undo_finished = false;
3706 void LyXText::SetCursorParUndo(Buffer * buf)
3710 SetUndo(buf, Undo::FINISH,
3712 cursor.par()->ParFromPos(cursor.pos())->previous_,
3713 cursor.par()->ParFromPos(cursor.pos())->next_
3715 cursor.par()->previous(),
3716 cursor.par()->next()
3722 void LyXText::toggleAppendix(BufferView * bview)
3725 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3727 LyXParagraph * par = cursor.par();
3729 bool start = !par->params.startOfAppendix();
3731 // ensure that we have only one start_of_appendix in this document
3732 LyXParagraph * tmp = FirstParagraph();
3734 for (; tmp; tmp = tmp->next_)
3735 tmp->params.startOfAppendix(false);
3737 for (; tmp; tmp = tmp->next())
3738 tmp->params.startOfAppendix(false);
3740 par->params.startOfAppendix(start);
3742 // we can set the refreshing parameters now
3743 status = LyXText::NEED_MORE_REFRESH;
3745 refresh_row = 0; // not needed for full update
3746 UpdateCounters(bview, 0);
3747 SetCursor(bview, cursor.par(), cursor.pos());
3751 LyXParagraph * LyXText::OwnerParagraph() const
3754 return inset_owner->par;
3756 return bv_owner->buffer()->paragraph;
3760 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3763 inset_owner->par = p;
3765 bv_owner->buffer()->paragraph = p;