1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2001 The LyX Team.
9 * ====================================================== */
13 #include FORMS_H_LOCATION
17 #pragma implementation "lyxtext.h"
22 #include "paragraph.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"
45 #include "ParagraphParameters.h"
54 LyXText::LyXText(BufferView * bv)
62 LyXText::LyXText(InsetText * inset)
72 the_locking_inset = 0;
80 status = LyXText::UNCHANGED;
82 // set cursor at the very top position
83 selection.set(true); /* these setting is necessary
84 because of the delete-empty-
85 paragraph mechanism in
88 Paragraph * par = ownerParagraph();
89 current_font = getFont(bv_owner->buffer(), par, 0);
91 insertParagraph(bv_owner, par, lastrow);
94 setCursor(bv_owner, firstrow->par(), 0);
96 current_font = LyXFont(LyXFont::ALL_SANE);
98 selection.cursor = cursor;
100 selection.mark(false);
102 // no rebreak necessary
105 undo_finished = true;
108 // Default layouttype for copy environment type
112 // Dump all rowinformation:
113 Row * tmprow = firstrow;
114 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
116 lyxerr << tmprow->baseline() << '\t'
117 << tmprow->par << '\t'
118 << tmprow->pos() << '\t'
119 << tmprow->height << '\t'
120 << tmprow->ascent_of_text << '\t'
121 << tmprow->fill << '\n';
122 tmprow = tmprow->next();
129 void LyXText::init(BufferView * bview)
134 Paragraph * par = ownerParagraph();
135 current_font = getFont(bview->buffer(), par, 0);
137 insertParagraph(bview, par, lastrow);
140 setCursorIntern(bview, firstrow->par(), 0);
141 selection.cursor = cursor;
143 printf("TP = %x\n",inset_owner->owner());
144 // Dump all rowinformation:
145 Row * tmprow = firstrow;
146 lyxerr << "Width = " << width << endl;
147 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
149 lyxerr << tmprow->baseline() << '\t'
150 << tmprow->par() << '\t'
151 << tmprow->pos() << '\t'
152 << tmprow->height() << '\t'
153 << tmprow->ascent_of_text() << '\t'
154 << tmprow->fill() << '\n';
155 tmprow = tmprow->next();
163 // Delete all rows, this does not touch the paragraphs!
164 Row * tmprow = firstrow;
166 tmprow = firstrow->next();
173 // Gets the fully instantiated font at a given position in a paragraph
174 // Basically the same routine as Paragraph::getFont() in paragraph.C.
175 // The difference is that this one is used for displaying, and thus we
176 // are allowed to make cosmetic improvements. For instance make footnotes
178 // If position is -1, we get the layout font of the paragraph.
179 // If position is -2, we get the font of the manual label of the paragraph.
180 LyXFont const LyXText::getFont(Buffer const * buf, Paragraph * par,
181 Paragraph::size_type pos) const
183 LyXLayout const & layout =
184 textclasslist.Style(buf->params.textclass, par->getLayout());
186 Paragraph::depth_type par_depth = par->getDepth();
187 // We specialize the 95% common case:
191 if (layout.labeltype == LABEL_MANUAL
192 && pos < beginningOfMainBody(buf, par)) {
194 LyXFont f = par->getFontSettings(buf->params,
196 return f.realize(layout.reslabelfont);
198 LyXFont f = par->getFontSettings(buf->params, pos);
199 return f.realize(layout.resfont);
204 // process layoutfont for pos == -1 and labelfont for pos < -1
206 return layout.resfont;
208 return layout.reslabelfont;
212 // The uncommon case need not be optimized as much
214 LyXFont layoutfont, tmpfont;
218 if (pos < beginningOfMainBody(buf, par)) {
220 layoutfont = layout.labelfont;
223 layoutfont = layout.font;
225 tmpfont = par->getFontSettings(buf->params, pos);
226 tmpfont.realize(layoutfont);
229 // process layoutfont for pos == -1 and labelfont for pos < -1
231 tmpfont = layout.font;
233 tmpfont = layout.labelfont;
236 // Resolve against environment font information
237 while (par && par_depth && !tmpfont.resolved()) {
238 par = par->outerHook();
240 tmpfont.realize(textclasslist.
241 Style(buf->params.textclass,
242 par->getLayout()).font);
243 par_depth = par->getDepth();
247 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
253 void LyXText::setCharFont(BufferView * bv, Paragraph * par,
254 Paragraph::size_type pos, LyXFont const & fnt,
257 Buffer const * buf = bv->buffer();
258 LyXFont font = getFont(buf, par, pos);
259 font.update(fnt, buf->params.language, toggleall);
260 // Let the insets convert their font
261 if (par->getChar(pos) == Paragraph::META_INSET) {
262 Inset * inset = par->getInset(pos);
264 if (inset->Editable()==Inset::HIGHLY_EDITABLE) {
265 UpdatableInset * uinset = static_cast<UpdatableInset *>(inset);
266 uinset->SetFont(bv, fnt, toggleall, true);
268 font = inset->ConvertFont(font);
272 LyXLayout const & layout =
273 textclasslist.Style(buf->params.textclass,
276 // Get concrete layout font to reduce against
279 if (pos < beginningOfMainBody(buf, par))
280 layoutfont = layout.labelfont;
282 layoutfont = layout.font;
284 // Realize against environment font information
285 if (par->getDepth()){
286 Paragraph * tp = par;
287 while (!layoutfont.resolved() && tp && tp->getDepth()) {
288 tp = tp->outerHook();
290 layoutfont.realize(textclasslist.
291 Style(buf->params.textclass,
292 tp->getLayout()).font);
296 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
298 // Now, reduce font against full layout font
299 font.reduce(layoutfont);
301 par->setFont(pos, font);
304 void LyXText::setCharFont(Buffer const * buf, Paragraph * par,
305 Paragraph::size_type pos, LyXFont const & fnt)
308 // Let the insets convert their font
309 if (par->getChar(pos) == Paragraph::META_INSET) {
310 font = par->getInset(pos)->ConvertFont(font);
313 LyXLayout const & layout =
314 textclasslist.Style(buf->params.textclass,
317 // Get concrete layout font to reduce against
320 if (pos < beginningOfMainBody(buf, par))
321 layoutfont = layout.labelfont;
323 layoutfont = layout.font;
325 // Realize against environment font information
326 if (par->getDepth()){
327 Paragraph * tp = par;
328 while (!layoutfont.resolved() && tp && tp->getDepth()) {
329 tp = tp->outerHook();
331 layoutfont.realize(textclasslist.
332 Style(buf->params.textclass,
333 tp->getLayout()).font);
337 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
339 // Now, reduce font against full layout font
340 font.reduce(layoutfont);
342 par->setFont(pos, font);
346 /* inserts a new row behind the specified row, increments
347 * the touched counters */
348 void LyXText::insertRow(Row * row, Paragraph * par,
349 Paragraph::size_type pos) const
351 Row * tmprow = new Row;
354 tmprow->next(firstrow);
357 tmprow->previous(row);
358 tmprow->next(row->next());
363 tmprow->next()->previous(tmprow);
365 if (tmprow->previous())
366 tmprow->previous()->next(tmprow);
374 ++number_of_rows; // one more row
378 // removes the row and reset the touched counters
379 void LyXText::removeRow(Row * row) const
381 /* this must not happen before the currentrow for clear reasons.
382 so the trick is just to set the current row onto the previous
385 getRow(row->par(), row->pos(), unused_y);
388 row->next()->previous(row->previous());
389 if (!row->previous()) {
390 firstrow = row->next();
392 row->previous()->next(row->next());
395 lastrow = row->previous();
397 height -= row->height(); // the text becomes smaller
400 --number_of_rows; // one row less
404 // remove all following rows of the paragraph of the specified row.
405 void LyXText::removeParagraph(Row * row) const
407 Paragraph * tmppar = row->par();
411 while (row && row->par() == tmppar) {
412 tmprow = row->next();
419 // insert the specified paragraph behind the specified row
420 void LyXText::insertParagraph(BufferView * bview, Paragraph * par,
423 insertRow(row, par, 0); /* insert a new row, starting
426 setCounter(bview->buffer(), par); // set the counters
428 // and now append the whole paragraph behind the new row
431 appendParagraph(bview, firstrow);
433 row->next()->height(0);
434 appendParagraph(bview, row->next());
439 /* used in setlayout */
440 // Asger is not sure we want to do this...
441 void LyXText::makeFontEntriesLayoutSpecific(Buffer const * buf,
445 LyXLayout const & layout =
446 textclasslist.Style(buf->params.textclass, par->getLayout());
448 LyXFont layoutfont, tmpfont;
449 for (Paragraph::size_type pos = 0;
450 pos < par->size(); ++pos) {
451 if (pos < beginningOfMainBody(buf, par))
452 layoutfont = layout.labelfont;
454 layoutfont = layout.font;
456 tmpfont = par->getFontSettings(buf->params, pos);
457 tmpfont.reduce(layoutfont);
458 par->setFont(pos, tmpfont);
463 Paragraph * LyXText::setLayout(BufferView * bview,
464 LyXCursor & cur, LyXCursor & sstart_cur,
465 LyXCursor & send_cur,
466 LyXTextClass::size_type layout)
468 Paragraph * endpar = send_cur.par()->next();
469 Paragraph * undoendpar = endpar;
471 if (endpar && endpar->getDepth()) {
472 while (endpar && endpar->getDepth()) {
473 endpar = endpar->next();
477 endpar = endpar->next(); // because of parindents etc.
480 setUndo(bview->buffer(), Undo::EDIT,
481 sstart_cur.par()->previous(),
484 /* ok we have a selection. This is always between sstart_cur
485 * and sel_end cursor */
488 LyXLayout const & lyxlayout =
489 textclasslist.Style(bview->buffer()->params.textclass, layout);
491 while (cur.par() != send_cur.par()) {
492 cur.par()->setLayout(layout);
493 makeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
494 Paragraph * fppar = cur.par();
495 fppar->params().spaceTop(lyxlayout.fill_top ?
496 VSpace(VSpace::VFILL)
497 : VSpace(VSpace::NONE));
498 fppar->params().spaceBottom(lyxlayout.fill_bottom ?
499 VSpace(VSpace::VFILL)
500 : VSpace(VSpace::NONE));
501 if (lyxlayout.margintype == MARGIN_MANUAL)
502 cur.par()->setLabelWidthString(lyxlayout.labelstring());
503 if (lyxlayout.labeltype != LABEL_BIBLIO
505 delete fppar->bibkey;
508 cur.par(cur.par()->next());
510 cur.par()->setLayout(layout);
511 makeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
512 Paragraph * fppar = cur.par();
513 fppar->params().spaceTop(lyxlayout.fill_top ?
514 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
515 fppar->params().spaceBottom(lyxlayout.fill_bottom ?
516 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
517 if (lyxlayout.margintype == MARGIN_MANUAL)
518 cur.par()->setLabelWidthString(lyxlayout.labelstring());
519 if (lyxlayout.labeltype != LABEL_BIBLIO
521 delete fppar->bibkey;
528 // set layout over selection and make a total rebreak of those paragraphs
529 void LyXText::setLayout(BufferView * bview, LyXTextClass::size_type layout)
531 LyXCursor tmpcursor = cursor; /* store the current cursor */
533 // if there is no selection just set the layout
534 // of the current paragraph */
535 if (!selection.set()) {
536 selection.start = cursor; // dummy selection
537 selection.end = cursor;
539 Paragraph * endpar = setLayout(bview, cursor, selection.start,
540 selection.end, layout);
541 redoParagraphs(bview, selection.start, endpar);
543 // we have to reset the selection, because the
544 // geometry could have changed
545 setCursor(bview, selection.start.par(),
546 selection.start.pos(), false);
547 selection.cursor = cursor;
548 setCursor(bview, selection.end.par(), selection.end.pos(),
550 updateCounters(bview, cursor.row());
551 clearSelection(bview);
553 setCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
557 // increment depth over selection and
558 // make a total rebreak of those paragraphs
559 void LyXText::incDepth(BufferView * bview)
561 // If there is no selection, just use the current paragraph
562 if (!selection.set()) {
563 selection.start = cursor; // dummy selection
564 selection.end = cursor;
567 // We end at the next paragraph with depth 0
568 Paragraph * endpar = selection.end.par()->next();
570 Paragraph * undoendpar = endpar;
572 if (endpar && endpar->getDepth()) {
573 while (endpar && endpar->getDepth()) {
574 endpar = endpar->next();
579 endpar = endpar->next(); // because of parindents etc.
582 setUndo(bview->buffer(), Undo::EDIT,
583 selection.start.par()->previous(),
586 LyXCursor tmpcursor = cursor; // store the current cursor
588 // ok we have a selection. This is always between sel_start_cursor
589 // and sel_end cursor
590 cursor = selection.start;
592 bool anything_changed = false;
595 // NOTE: you can't change the depth of a bibliography entry
597 textclasslist.Style(bview->buffer()->params.textclass,
598 cursor.par()->getLayout()
599 ).labeltype != LABEL_BIBLIO) {
600 Paragraph * prev = cursor.par()->previous();
603 && (prev->getDepth() - cursor.par()->getDepth() > 0
604 || (prev->getDepth() == cursor.par()->getDepth()
605 && textclasslist.Style(bview->buffer()->params.textclass,
606 prev->getLayout()).isEnvironment()))) {
607 cursor.par()->params().depth(cursor.par()->params().depth() + 1);
608 anything_changed = true;
611 if (cursor.par() == selection.end.par())
613 cursor.par(cursor.par()->next());
616 // if nothing changed set all depth to 0
617 if (!anything_changed) {
618 cursor = selection.start;
619 while (cursor.par() != selection.end.par()) {
620 cursor.par()->params().depth(0);
621 cursor.par(cursor.par()->next());
623 cursor.par()->params().depth(0);
626 redoParagraphs(bview, selection.start, endpar);
628 // we have to reset the selection, because the
629 // geometry could have changed
630 setCursor(bview, selection.start.par(), selection.start.pos());
631 selection.cursor = cursor;
632 setCursor(bview, selection.end.par(), selection.end.pos());
633 updateCounters(bview, cursor.row());
634 clearSelection(bview);
636 setCursor(bview, tmpcursor.par(), tmpcursor.pos());
640 // decrement depth over selection and
641 // make a total rebreak of those paragraphs
642 void LyXText::decDepth(BufferView * bview)
644 // if there is no selection just set the layout
645 // of the current paragraph
646 if (!selection.set()) {
647 selection.start = cursor; // dummy selection
648 selection.end = cursor;
650 Paragraph * endpar = selection.end.par()->next();
651 Paragraph * undoendpar = endpar;
653 if (endpar && endpar->getDepth()) {
654 while (endpar && endpar->getDepth()) {
655 endpar = endpar->next();
659 endpar = endpar->next(); // because of parindents etc.
662 setUndo(bview->buffer(), Undo::EDIT,
663 selection.start.par()->previous(),
666 LyXCursor tmpcursor = cursor; // store the current cursor
668 // ok we have a selection. This is always between sel_start_cursor
669 // and sel_end cursor
670 cursor = selection.start;
673 if (cursor.par()->params().depth())
674 cursor.par()->params().depth(cursor.par()->params().depth() - 1);
675 if (cursor.par() == selection.end.par())
677 cursor.par(cursor.par()->next());
680 redoParagraphs(bview, selection.start, endpar);
682 // we have to reset the selection, because the
683 // geometry could have changed
684 setCursor(bview, selection.start.par(),
685 selection.start.pos());
686 selection.cursor = cursor;
687 setCursor(bview, selection.end.par(), selection.end.pos());
688 updateCounters(bview, cursor.row());
689 clearSelection(bview);
691 setCursor(bview, tmpcursor.par(), tmpcursor.pos());
695 // set font over selection and make a total rebreak of those paragraphs
696 void LyXText::setFont(BufferView * bview, LyXFont const & font, bool toggleall)
698 // if there is no selection just set the current_font
699 if (!selection.set()) {
700 // Determine basis font
702 if (cursor.pos() < beginningOfMainBody(bview->buffer(),
704 layoutfont = getFont(bview->buffer(), cursor.par(),-2);
706 layoutfont = getFont(bview->buffer(), cursor.par(),-1);
707 // Update current font
708 real_current_font.update(font,
709 bview->buffer()->params.language,
712 // Reduce to implicit settings
713 current_font = real_current_font;
714 current_font.reduce(layoutfont);
715 // And resolve it completely
716 real_current_font.realize(layoutfont);
720 LyXCursor tmpcursor = cursor; // store the current cursor
722 // ok we have a selection. This is always between sel_start_cursor
723 // and sel_end cursor
725 setUndo(bview->buffer(), Undo::EDIT,
726 selection.start.par()->previous(),
727 selection.end.par()->next());
729 cursor = selection.start;
730 while (cursor.par() != selection.end.par() ||
731 (cursor.pos() < selection.end.pos())) {
732 if (cursor.pos() < cursor.par()->size()) {
733 // an open footnote should behave
735 setCharFont(bview, cursor.par(), cursor.pos(), font, toggleall);
736 cursor.pos(cursor.pos() + 1);
739 cursor.par(cursor.par()->next());
744 redoParagraphs(bview, selection.start, selection.end.par()->next());
746 // we have to reset the selection, because the
747 // geometry could have changed
748 setCursor(bview, selection.start.par(), selection.start.pos());
749 selection.cursor = cursor;
750 setCursor(bview, selection.end.par(), selection.end.pos());
751 clearSelection(bview);
753 setCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
754 tmpcursor.boundary());
758 void LyXText::redoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
760 Row * tmprow = cur.row();
761 int y = cur.y() - tmprow->baseline();
763 setHeightOfRow(bview, tmprow);
764 Paragraph * first_phys_par = tmprow->par();
766 // find the first row of the paragraph
767 if (first_phys_par != tmprow->par())
768 while (tmprow->previous()
769 && tmprow->previous()->par() != first_phys_par) {
770 tmprow = tmprow->previous();
771 y -= tmprow->height();
772 setHeightOfRow(bview, tmprow);
774 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
775 tmprow = tmprow->previous();
776 y -= tmprow->height();
777 setHeightOfRow(bview, tmprow);
780 // we can set the refreshing parameters now
781 status = LyXText::NEED_MORE_REFRESH;
783 refresh_row = tmprow;
784 setCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
788 void LyXText::redoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
790 Row * tmprow = cur.row();
792 int y = cur.y() - tmprow->baseline();
793 setHeightOfRow(bview, tmprow);
794 Paragraph * first_phys_par = tmprow->par();
796 // find the first row of the paragraph
797 if (first_phys_par != tmprow->par())
798 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
799 tmprow = tmprow->previous();
800 y -= tmprow->height();
802 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
803 tmprow = tmprow->previous();
804 y -= tmprow->height();
807 // we can set the refreshing parameters now
808 if (status == LyXText::UNCHANGED || y < refresh_y) {
810 refresh_row = tmprow;
812 status = LyXText::NEED_MORE_REFRESH;
813 setCursor(bview, cur.par(), cur.pos());
817 /* deletes and inserts again all paragaphs between the cursor
818 * and the specified par
819 * This function is needed after SetLayout and SetFont etc. */
820 void LyXText::redoParagraphs(BufferView * bview, LyXCursor const & cur,
821 Paragraph const * endpar) const
824 Paragraph * tmppar = 0, * first_phys_par = 0;
826 Row * tmprow = cur.row();
828 int y = cur.y() - tmprow->baseline();
830 if (!tmprow->previous()){
831 first_phys_par = firstParagraph(); // a trick/hack for UNDO
833 first_phys_par = tmprow->par();
834 // find the first row of the paragraph
835 if (first_phys_par != tmprow->par())
836 while (tmprow->previous() &&
837 (tmprow->previous()->par() != first_phys_par)) {
838 tmprow = tmprow->previous();
839 y -= tmprow->height();
841 while (tmprow->previous()
842 && tmprow->previous()->par() == first_phys_par) {
843 tmprow = tmprow->previous();
844 y -= tmprow->height();
848 // we can set the refreshing parameters now
849 status = LyXText::NEED_MORE_REFRESH;
851 refresh_row = tmprow->previous(); /* the real refresh row will
852 be deleted, so I store
856 tmppar = tmprow->next()->par();
859 while (tmppar != endpar) {
860 removeRow(tmprow->next());
862 tmppar = tmprow->next()->par();
867 // remove the first one
868 tmprow2 = tmprow; /* this is because tmprow->previous()
870 tmprow = tmprow->previous();
873 tmppar = first_phys_par;
877 insertParagraph(bview, tmppar, tmprow);
880 while (tmprow->next() && tmprow->next()->par() == tmppar)
881 tmprow = tmprow->next();
882 tmppar = tmppar->next();
884 } while (tmppar != endpar);
886 // this is because of layout changes
888 refresh_y -= refresh_row->height();
889 setHeightOfRow(bview, refresh_row);
891 refresh_row = firstrow;
893 setHeightOfRow(bview, refresh_row);
896 if (tmprow && tmprow->next())
897 setHeightOfRow(bview, tmprow->next());
901 bool LyXText::fullRebreak(BufferView * bview)
907 if (need_break_row) {
908 breakAgain(bview, need_break_row);
916 /* important for the screen */
919 /* the cursor set functions have a special mechanism. When they
920 * realize, that you left an empty paragraph, they will delete it.
921 * They also delete the corresponding row */
923 // need the selection cursor:
924 void LyXText::setSelection(BufferView * bview)
926 bool const lsel = selection.set();
928 if (!selection.set()) {
929 last_sel_cursor = selection.cursor;
930 selection.start = selection.cursor;
931 selection.end = selection.cursor;
936 // first the toggling area
937 if (cursor.y() < last_sel_cursor.y()
938 || (cursor.y() == last_sel_cursor.y()
939 && cursor.x() < last_sel_cursor.x())) {
940 toggle_end_cursor = last_sel_cursor;
941 toggle_cursor = cursor;
943 toggle_end_cursor = cursor;
944 toggle_cursor = last_sel_cursor;
947 last_sel_cursor = cursor;
949 // and now the whole selection
951 if (selection.cursor.par() == cursor.par())
952 if (selection.cursor.pos() < cursor.pos()) {
953 selection.end = cursor;
954 selection.start = selection.cursor;
956 selection.end = selection.cursor;
957 selection.start = cursor;
959 else if (selection.cursor.y() < cursor.y() ||
960 (selection.cursor.y() == cursor.y() && selection.cursor.x() < cursor.x())) {
961 selection.end = cursor;
962 selection.start = selection.cursor;
965 selection.end = selection.cursor;
966 selection.start = cursor;
969 // a selection with no contents is not a selection
970 if (selection.start.par() == selection.end.par() &&
971 selection.start.pos() == selection.end.pos())
972 selection.set(false);
974 if (inset_owner && (selection.set() || lsel))
975 inset_owner->SetUpdateStatus(bview, InsetText::SELECTION);
979 string const LyXText::selectionAsString(Buffer const * buffer) const
981 if (!selection.set()) return string();
984 // Special handling if the whole selection is within one paragraph
985 if (selection.start.par() == selection.end.par()) {
986 result += selection.start.par()->asString(buffer,
987 selection.start.pos(),
988 selection.end.pos());
992 // The selection spans more than one paragraph
994 // First paragraph in selection
995 result += selection.start.par()->asString(buffer,
996 selection.start.pos(),
997 selection.start.par()->size())
1000 // The paragraphs in between (if any)
1001 LyXCursor tmpcur(selection.start);
1002 tmpcur.par(tmpcur.par()->next());
1003 while (tmpcur.par() != selection.end.par()) {
1004 result += tmpcur.par()->asString(buffer, 0, tmpcur.par()->size()) + "\n\n";
1005 tmpcur.par(tmpcur.par()->next()); // Or NextAfterFootnote??
1008 // Last paragraph in selection
1009 result += selection.end.par()->asString(buffer, 0, selection.end.pos());
1015 void LyXText::clearSelection(BufferView * /*bview*/) const
1017 selection.set(false);
1018 selection.mark(false);
1019 selection.end = selection.start = cursor;
1023 void LyXText::cursorHome(BufferView * bview) const
1025 setCursor(bview, cursor.par(), cursor.row()->pos());
1029 void LyXText::cursorEnd(BufferView * bview) const
1031 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1032 setCursor(bview, cursor.par(), rowLast(cursor.row()) + 1);
1034 if (cursor.par()->size() &&
1035 (cursor.par()->getChar(rowLast(cursor.row())) == ' '
1036 || cursor.par()->isNewline(rowLast(cursor.row()))))
1037 setCursor(bview, cursor.par(), rowLast(cursor.row()));
1039 setCursor(bview,cursor.par(), rowLast(cursor.row()) + 1);
1044 void LyXText::cursorTop(BufferView * bview) const
1046 while (cursor.par()->previous())
1047 cursor.par(cursor.par()->previous());
1048 setCursor(bview, cursor.par(), 0);
1052 void LyXText::cursorBottom(BufferView * bview) const
1054 while (cursor.par()->next())
1055 cursor.par(cursor.par()->next());
1056 setCursor(bview, cursor.par(), cursor.par()->size());
1060 void LyXText::toggleFree(BufferView * bview,
1061 LyXFont const & font, bool toggleall)
1063 // If the mask is completely neutral, tell user
1064 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1065 // Could only happen with user style
1066 bview->owner()->message(_("No font change defined. Use Character under the Layout menu to define font change."));
1070 // Try implicit word selection
1071 // If there is a change in the language the implicit word selection
1073 LyXCursor resetCursor = cursor;
1074 bool implicitSelection = (font.language() == ignore_language
1075 && font.number() == LyXFont::IGNORE)
1076 ? selectWordWhenUnderCursor(bview) : false;
1079 setFont(bview, font, toggleall);
1081 /* Implicit selections are cleared afterwards and cursor is set to the
1082 original position. */
1083 if (implicitSelection) {
1084 clearSelection(bview);
1085 cursor = resetCursor;
1086 setCursor(bview, cursor.par(), cursor.pos());
1087 selection.cursor = cursor;
1090 inset_owner->SetUpdateStatus(bview, InsetText::CURSOR_PAR);
1094 Paragraph::size_type
1095 LyXText::beginningOfMainBody(Buffer const * buf,
1096 Paragraph const * par) const
1098 if (textclasslist.Style(buf->params.textclass,
1099 par->getLayout()).labeltype != LABEL_MANUAL)
1102 return par->beginningOfMainBody();
1106 /* the DTP switches for paragraphs. LyX will store them in the
1107 * first physicla paragraph. When a paragraph is broken, the top settings
1108 * rest, the bottom settings are given to the new one. So I can make shure,
1109 * they do not duplicate themself and you cannnot make dirty things with
1112 void LyXText::setParagraph(BufferView * bview,
1113 bool line_top, bool line_bottom,
1114 bool pagebreak_top, bool pagebreak_bottom,
1115 VSpace const & space_top,
1116 VSpace const & space_bottom,
1118 string labelwidthstring,
1121 LyXCursor tmpcursor = cursor;
1122 if (!selection.set()) {
1123 selection.start = cursor;
1124 selection.end = cursor;
1127 // make sure that the depth behind the selection are restored, too
1128 Paragraph * endpar = selection.end.par()->next();
1129 Paragraph * undoendpar = endpar;
1131 if (endpar && endpar->getDepth()) {
1132 while (endpar && endpar->getDepth()) {
1133 endpar = endpar->next();
1134 undoendpar = endpar;
1138 endpar = endpar->next(); // because of parindents etc.
1141 setUndo(bview->buffer(), Undo::EDIT,
1142 selection.start.par()->previous(),
1146 Paragraph * tmppar = selection.end.par();
1147 while (tmppar != selection.start.par()->previous()) {
1148 setCursor(bview, tmppar, 0);
1149 status = LyXText::NEED_MORE_REFRESH;
1150 refresh_row = cursor.row();
1151 refresh_y = cursor.y() - cursor.row()->baseline();
1152 cursor.par()->params().lineTop(line_top);
1153 cursor.par()->params().lineBottom(line_bottom);
1154 cursor.par()->params().pagebreakTop(pagebreak_top);
1155 cursor.par()->params().pagebreakBottom(pagebreak_bottom);
1156 cursor.par()->params().spaceTop(space_top);
1157 cursor.par()->params().spaceBottom(space_bottom);
1158 // does the layout allow the new alignment?
1159 if (align == LYX_ALIGN_LAYOUT)
1160 align = textclasslist
1161 .Style(bview->buffer()->params.textclass,
1162 cursor.par()->getLayout()).align;
1163 if (align & textclasslist
1164 .Style(bview->buffer()->params.textclass,
1165 cursor.par()->getLayout()).alignpossible) {
1166 if (align == textclasslist
1167 .Style(bview->buffer()->params.textclass,
1168 cursor.par()->getLayout()).align)
1169 cursor.par()->params().align(LYX_ALIGN_LAYOUT);
1171 cursor.par()->params().align(align);
1173 cursor.par()->setLabelWidthString(labelwidthstring);
1174 cursor.par()->params().noindent(noindent);
1175 tmppar = cursor.par()->previous();
1178 redoParagraphs(bview, selection.start, endpar);
1180 clearSelection(bview);
1181 setCursor(bview, selection.start.par(), selection.start.pos());
1182 selection.cursor = cursor;
1183 setCursor(bview, selection.end.par(), selection.end.pos());
1184 setSelection(bview);
1185 setCursor(bview, tmpcursor.par(), tmpcursor.pos());
1187 bview->updateInset(inset_owner, true);
1191 char loweralphaCounter(int n)
1193 if (n < 1 || n > 26)
1203 char alphaCounter(int n)
1205 if (n < 1 || n > 26)
1213 char hebrewCounter(int n)
1215 static const char hebrew[22] = {
1216 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1217 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1218 '÷', 'ø', 'ù', 'ú'
1220 if (n < 1 || n > 22)
1228 string const romanCounter(int n)
1230 static char const * roman[20] = {
1231 "i", "ii", "iii", "iv", "v",
1232 "vi", "vii", "viii", "ix", "x",
1233 "xi", "xii", "xiii", "xiv", "xv",
1234 "xvi", "xvii", "xviii", "xix", "xx"
1236 if (n < 1 || n > 20)
1245 // set the counter of a paragraph. This includes the labels
1246 void LyXText::setCounter(Buffer const * buf, Paragraph * par) const
1248 LyXLayout const & layout =
1249 textclasslist.Style(buf->params.textclass,
1252 LyXTextClass const & textclass =
1253 textclasslist.TextClass(buf->params.textclass);
1255 /* copy the prev-counters to this one, unless this is the start of a
1256 footnote or of a bibliography or the very first paragraph */
1258 && !(textclasslist.Style(buf->params.textclass,
1259 par->previous()->getLayout()
1260 ).labeltype != LABEL_BIBLIO
1261 && layout.labeltype == LABEL_BIBLIO)) {
1262 for (int i = 0; i < 10; ++i) {
1263 par->setCounter(i, par->previous()->getFirstCounter(i));
1265 par->params().appendix(par->previous()->params().appendix());
1266 if (!par->params().appendix() && par->params().startOfAppendix()) {
1267 par->params().appendix(true);
1268 for (int i = 0; i < 10; ++i) {
1269 par->setCounter(i, 0);
1272 par->enumdepth = par->previous()->enumdepth;
1273 par->itemdepth = par->previous()->itemdepth;
1275 for (int i = 0; i < 10; ++i) {
1276 par->setCounter(i, 0);
1278 par->params().appendix(par->params().startOfAppendix());
1283 /* Maybe we have to increment the enumeration depth.
1284 * BUT, enumeration in a footnote is considered in isolation from its
1285 * surrounding paragraph so don't increment if this is the
1286 * first line of the footnote
1287 * AND, bibliographies can't have their depth changed ie. they
1288 * are always of depth 0
1291 && par->previous()->getDepth() < par->getDepth()
1292 && textclasslist.Style(buf->params.textclass,
1293 par->previous()->getLayout()
1294 ).labeltype == LABEL_COUNTER_ENUMI
1295 && par->enumdepth < 3
1296 && layout.labeltype != LABEL_BIBLIO) {
1300 /* Maybe we have to decrement the enumeration depth, see note above */
1302 && par->previous()->getDepth() > par->getDepth()
1303 && layout.labeltype != LABEL_BIBLIO) {
1304 par->enumdepth = par->depthHook(par->getDepth())->enumdepth;
1305 par->setCounter(6 + par->enumdepth,
1306 par->depthHook(par->getDepth())->getCounter(6 + par->enumdepth));
1307 /* reset the counters.
1308 * A depth change is like a breaking layout
1310 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1311 par->setCounter(i, 0);
1314 if (!par->params().labelString().empty()) {
1315 par->params().labelString(string());
1318 if (layout.margintype == MARGIN_MANUAL) {
1319 if (par->params().labelWidthString().empty()) {
1320 par->setLabelWidthString(layout.labelstring());
1323 par->setLabelWidthString(string());
1326 /* is it a layout that has an automatic label ? */
1327 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1329 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1330 if (i >= 0 && i<= buf->params.secnumdepth) {
1331 par->incCounter(i); // increment the counter
1333 // Is there a label? Useful for Chapter layout
1334 if (!par->params().appendix()) {
1335 if (!layout.labelstring().empty())
1336 par->params().labelString(layout.labelstring());
1338 par->params().labelString(string());
1340 if (!layout.labelstring_appendix().empty())
1341 par->params().labelString(layout.labelstring_appendix());
1343 par->params().labelString(string());
1346 std::ostringstream s;
1348 if (!par->params().appendix()) {
1349 switch (2 * LABEL_COUNTER_CHAPTER -
1350 textclass.maxcounter() + i) {
1351 case LABEL_COUNTER_CHAPTER:
1352 s << par->getCounter(i);
1354 case LABEL_COUNTER_SECTION:
1355 s << par->getCounter(i - 1) << '.'
1356 << par->getCounter(i);
1358 case LABEL_COUNTER_SUBSECTION:
1359 s << par->getCounter(i - 2) << '.'
1360 << par->getCounter(i - 1) << '.'
1361 << par->getCounter(i);
1363 case LABEL_COUNTER_SUBSUBSECTION:
1364 s << par->getCounter(i - 3) << '.'
1365 << par->getCounter(i - 2) << '.'
1366 << par->getCounter(i - 1) << '.'
1367 << par->getCounter(i);
1370 case LABEL_COUNTER_PARAGRAPH:
1371 s << par->getCounter(i - 4) << '.'
1372 << par->getCounter(i - 3) << '.'
1373 << par->getCounter(i - 2) << '.'
1374 << par->getCounter(i - 1) << '.'
1375 << par->getCounter(i);
1377 case LABEL_COUNTER_SUBPARAGRAPH:
1378 s << par->getCounter(i - 5) << '.'
1379 << par->getCounter(i - 4) << '.'
1380 << par->getCounter(i - 3) << '.'
1381 << par->getCounter(i - 2) << '.'
1382 << par->getCounter(i - 1) << '.'
1383 << par->getCounter(i);
1387 // Can this ever be reached? And in the
1388 // case it is, how can this be correct?
1390 s << par->getCounter(i) << '.';
1393 } else { // appendix
1394 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1395 case LABEL_COUNTER_CHAPTER:
1396 if (par->isRightToLeftPar(buf->params))
1397 s << hebrewCounter(par->getCounter(i));
1399 s << alphaCounter(par->getCounter(i));
1401 case LABEL_COUNTER_SECTION:
1402 if (par->isRightToLeftPar(buf->params))
1403 s << hebrewCounter(par->getCounter(i - 1));
1405 s << alphaCounter(par->getCounter(i - 1));
1408 << par->getCounter(i);
1411 case LABEL_COUNTER_SUBSECTION:
1412 if (par->isRightToLeftPar(buf->params))
1413 s << hebrewCounter(par->getCounter(i - 2));
1415 s << alphaCounter(par->getCounter(i - 2));
1418 << par->getCounter(i-1) << '.'
1419 << par->getCounter(i);
1422 case LABEL_COUNTER_SUBSUBSECTION:
1423 if (par->isRightToLeftPar(buf->params))
1424 s << hebrewCounter(par->getCounter(i-3));
1426 s << alphaCounter(par->getCounter(i-3));
1429 << par->getCounter(i-2) << '.'
1430 << par->getCounter(i-1) << '.'
1431 << par->getCounter(i);
1434 case LABEL_COUNTER_PARAGRAPH:
1435 if (par->isRightToLeftPar(buf->params))
1436 s << hebrewCounter(par->getCounter(i-4));
1438 s << alphaCounter(par->getCounter(i-4));
1441 << par->getCounter(i-3) << '.'
1442 << par->getCounter(i-2) << '.'
1443 << par->getCounter(i-1) << '.'
1444 << par->getCounter(i);
1447 case LABEL_COUNTER_SUBPARAGRAPH:
1448 if (par->isRightToLeftPar(buf->params))
1449 s << hebrewCounter(par->getCounter(i-5));
1451 s << alphaCounter(par->getCounter(i-5));
1454 << par->getCounter(i-4) << '.'
1455 << par->getCounter(i-3) << '.'
1456 << par->getCounter(i-2) << '.'
1457 << par->getCounter(i-1) << '.'
1458 << par->getCounter(i);
1462 // Can this ever be reached? And in the
1463 // case it is, how can this be correct?
1465 s << par->getCounter(i) << '.';
1471 par->params().labelString(par->params().labelString() +s.str().c_str());
1472 // We really want to remove the c_str as soon as
1475 for (i++; i < 10; ++i) {
1476 // reset the following counters
1477 par->setCounter(i, 0);
1479 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1480 for (i++; i < 10; ++i) {
1481 // reset the following counters
1482 par->setCounter(i, 0);
1484 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1485 par->incCounter(i + par->enumdepth);
1486 int number = par->getCounter(i + par->enumdepth);
1488 std::ostringstream s;
1490 switch (par->enumdepth) {
1492 if (par->isRightToLeftPar(buf->params))
1494 << hebrewCounter(number)
1498 << loweralphaCounter(number)
1502 if (par->isRightToLeftPar(buf->params))
1503 s << '.' << romanCounter(number);
1505 s << romanCounter(number) << '.';
1508 if (par->isRightToLeftPar(buf->params))
1510 << alphaCounter(number);
1512 s << alphaCounter(number)
1516 if (par->isRightToLeftPar(buf->params))
1523 par->params().labelString(s.str().c_str());
1524 // we really want to get rid of that c_str()
1526 for (i += par->enumdepth + 1; i < 10; ++i)
1527 par->setCounter(i, 0); /* reset the following counters */
1530 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1531 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1533 int number = par->getCounter(i);
1535 InsetCommandParams p( "bibitem" );
1536 par->bibkey = new InsetBibKey(p);
1538 par->bibkey->setCounter(number);
1539 par->params().labelString(layout.labelstring());
1541 // In biblio should't be following counters but...
1543 string s = layout.labelstring();
1545 // the caption hack:
1546 if (layout.labeltype == LABEL_SENSITIVE) {
1547 bool isOK (par->InInset() && par->InInset()->owner() &&
1548 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
1551 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
1553 = floatList.getType(tmp->type());
1554 // We should get the correct number here too.
1555 s = fl.name() + " #:";
1557 /* par->SetLayout(0);
1558 s = layout->labelstring; */
1559 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1560 ? " :úåòîùî øñç" : "Senseless: ";
1563 par->params().labelString(s);
1565 /* reset the enumeration counter. They are always resetted
1566 * when there is any other layout between */
1567 for (int i = 6 + par->enumdepth; i < 10; ++i)
1568 par->setCounter(i, 0);
1573 /* Updates all counters BEHIND the row. Changed paragraphs
1574 * with a dynamic left margin will be rebroken. */
1575 void LyXText::updateCounters(BufferView * bview, Row * row) const
1583 par = row->par()->next();
1587 while (row->par() != par)
1590 setCounter(bview->buffer(), par);
1592 /* now check for the headline layouts. remember that they
1593 * have a dynamic left margin */
1594 if ((textclasslist.Style(bview->buffer()->params.textclass,
1595 par->layout).margintype == MARGIN_DYNAMIC
1596 || textclasslist.Style(bview->buffer()->params.textclass,
1597 par->layout).labeltype == LABEL_SENSITIVE)) {
1599 /* Rebreak the paragraph */
1600 removeParagraph(row);
1601 appendParagraph(bview, row);
1608 /* insets an inset. */
1609 void LyXText::insertInset(BufferView * bview, Inset * inset)
1611 if (!cursor.par()->insertInsetAllowed(inset))
1613 setUndo(bview->buffer(), Undo::INSERT,
1614 cursor.par()->previous(),
1615 cursor.par()->next());
1616 cursor.par()->insertInset(cursor.pos(), inset);
1617 insertChar(bview, Paragraph::META_INSET); /* just to rebreak and refresh correctly.
1618 * The character will not be inserted a
1621 // If we enter a highly editable inset the cursor should be to before
1622 // the inset. This couldn't happen before as Undo was not handled inside
1623 // inset now after the Undo LyX tries to call inset->Edit(...) again
1624 // and cannot do this as the cursor is behind the inset and GetInset
1625 // does not return the inset!
1626 if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
1627 cursorLeft(bview, true);
1633 void LyXText::copyEnvironmentType()
1635 copylayouttype = cursor.par()->getLayout();
1639 void LyXText::pasteEnvironmentType(BufferView * bview)
1641 setLayout(bview, copylayouttype);
1645 void LyXText::cutSelection(BufferView * bview, bool doclear)
1647 // Stuff what we got on the clipboard. Even if there is no selection.
1649 // There is a problem with having the stuffing here in that the
1650 // larger the selection the slower LyX will get. This can be
1651 // solved by running the line below only when the selection has
1652 // finished. The solution used currently just works, to make it
1653 // faster we need to be more clever and probably also have more
1654 // calls to stuffClipboard. (Lgb)
1655 bview->stuffClipboard(selectionAsString(bview->buffer()));
1657 // This doesn't make sense, if there is no selection
1658 if (!selection.set())
1661 // OK, we have a selection. This is always between selection.start
1662 // and selection.end
1664 // make sure that the depth behind the selection are restored, too
1665 Paragraph * endpar = selection.end.par()->next();
1666 Paragraph * undoendpar = endpar;
1668 if (endpar && endpar->getDepth()) {
1669 while (endpar && endpar->getDepth()) {
1670 endpar = endpar->next();
1671 undoendpar = endpar;
1673 } else if (endpar) {
1674 endpar = endpar->next(); // because of parindents etc.
1677 setUndo(bview->buffer(), Undo::DELETE,
1678 selection.start.par()->previous(),
1683 // there are two cases: cut only within one paragraph or
1684 // more than one paragraph
1685 if (selection.start.par() == selection.end.par()) {
1686 // only within one paragraph
1687 endpar = selection.end.par();
1688 int pos = selection.end.pos();
1689 cap.cutSelection(selection.start.par(), &endpar,
1690 selection.start.pos(), pos,
1691 bview->buffer()->params.textclass, doclear);
1692 selection.end.pos(pos);
1694 endpar = selection.end.par();
1695 int pos = selection.end.pos();
1696 cap.cutSelection(selection.start.par(), &endpar,
1697 selection.start.pos(), pos,
1698 bview->buffer()->params.textclass, doclear);
1700 selection.end.par(endpar);
1701 selection.end.pos(pos);
1702 cursor.pos(selection.end.pos());
1704 endpar = endpar->next();
1706 // sometimes necessary
1708 selection.start.par()->stripLeadingSpaces(bview->buffer()->params.textclass);
1710 redoParagraphs(bview, selection.start, endpar);
1712 // cutSelection can invalidate the cursor so we need to set
1714 cursor = selection.start;
1716 // need a valid cursor. (Lgb)
1717 clearSelection(bview);
1719 setCursor(bview, cursor.par(), cursor.pos());
1720 selection.cursor = cursor;
1721 updateCounters(bview, cursor.row());
1725 void LyXText::copySelection(BufferView * bview)
1727 // Stuff what we got on the clipboard. Even if there is no selection.
1729 // There is a problem with having the stuffing here in that the
1730 // larger the selection the slower LyX will get. This can be
1731 // solved by running the line below only when the selection has
1732 // finished. The solution used currently just works, to make it
1733 // faster we need to be more clever and probably also have more
1734 // calls to stuffClipboard. (Lgb)
1735 bview->stuffClipboard(selectionAsString(bview->buffer()));
1737 // this doesnt make sense, if there is no selection
1738 if (!selection.set())
1741 // ok we have a selection. This is always between selection.start
1742 // and sel_end cursor
1744 // copy behind a space if there is one
1745 while (selection.start.par()->size() > selection.start.pos()
1746 && selection.start.par()->isLineSeparator(selection.start.pos())
1747 && (selection.start.par() != selection.end.par()
1748 || selection.start.pos() < selection.end.pos()))
1749 selection.start.pos(selection.start.pos() + 1);
1753 cap.copySelection(selection.start.par(), selection.end.par(),
1754 selection.start.pos(), selection.end.pos(),
1755 bview->buffer()->params.textclass);
1759 void LyXText::pasteSelection(BufferView * bview)
1763 // this does not make sense, if there is nothing to paste
1764 if (!cap.checkPastePossible(cursor.par()))
1767 setUndo(bview->buffer(), Undo::INSERT,
1768 cursor.par()->previous(),
1769 cursor.par()->next());
1772 Paragraph * actpar = cursor.par();
1774 int pos = cursor.pos();
1775 cap.pasteSelection(&actpar, &endpar, pos,
1776 bview->buffer()->params.textclass);
1778 redoParagraphs(bview, cursor, endpar);
1780 setCursor(bview, cursor.par(), cursor.pos());
1781 clearSelection(bview);
1783 selection.cursor = cursor;
1784 setCursor(bview, actpar, pos);
1785 setSelection(bview);
1786 updateCounters(bview, cursor.row());
1790 // returns a pointer to the very first Paragraph
1791 Paragraph * LyXText::firstParagraph() const
1793 return ownerParagraph();
1797 // sets the selection over the number of characters of string, no check!!
1798 void LyXText::setSelectionOverString(BufferView * bview, string const & str)
1803 selection.cursor = cursor;
1804 for (string::size_type i = 0; i < str.length(); ++i)
1806 setSelection(bview);
1810 // simple replacing. The font of the first selected character is used
1811 void LyXText::replaceSelectionWithString(BufferView * bview,
1814 setCursorParUndo(bview->buffer());
1817 if (!selection.set()) { // create a dummy selection
1818 selection.end = cursor;
1819 selection.start = cursor;
1822 // Get font setting before we cut
1823 Paragraph::size_type pos = selection.end.pos();
1824 LyXFont const font = selection.start.par()
1825 ->getFontSettings(bview->buffer()->params,
1826 selection.start.pos());
1828 // Insert the new string
1829 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
1830 selection.end.par()->insertChar(pos, (*cit), font);
1834 // Cut the selection
1835 cutSelection(bview);
1841 // needed to insert the selection
1842 void LyXText::insertStringAsLines(BufferView * bview, string const & str)
1844 Paragraph * par = cursor.par();
1845 Paragraph::size_type pos = cursor.pos();
1846 Paragraph * endpar = cursor.par()->next();
1848 setCursorParUndo(bview->buffer());
1850 bool isEnvironment =
1851 textclasslist.Style(bview->buffer()->params.textclass,
1852 cursor.par()->getLayout()).isEnvironment();
1854 textclasslist.Style(bview->buffer()->params.textclass,
1855 cursor.par()->getLayout()).free_spacing;
1857 textclasslist.Style(bview->buffer()->params.textclass,
1858 cursor.par()->getLayout()).keepempty;
1860 // only to be sure, should not be neccessary
1861 clearSelection(bview);
1863 // insert the string, don't insert doublespace
1864 bool space_inserted = true;
1865 for(string::const_iterator cit = str.begin();
1866 cit != str.end(); ++cit) {
1868 if (par->size() || keepempty) {
1869 par->breakParagraph(bview->buffer()->params,
1870 pos, isEnvironment);
1873 space_inserted = true;
1877 // do not insert consecutive spaces if !free_spacing
1878 } else if ((*cit == ' ' || *cit == '\t')
1879 && space_inserted && !free_spacing) {
1881 } else if (*cit == '\t') {
1882 if (!free_spacing) {
1883 // tabs are like spaces here
1884 par->insertChar(pos, ' ',
1887 space_inserted = true;
1889 const Paragraph::value_type nb = 8 - pos % 8;
1890 for (Paragraph::size_type a = 0;
1892 par->insertChar(pos, ' ',
1896 space_inserted = true;
1898 } else if (!IsPrintable(*cit)) {
1899 // Ignore unprintables
1902 // just insert the character
1903 par->insertChar(pos, *cit, current_font);
1905 space_inserted = (*cit == ' ');
1910 redoParagraphs(bview, cursor, endpar);
1911 setCursor(bview, cursor.par(), cursor.pos());
1912 selection.cursor = cursor;
1913 setCursor(bview, par, pos);
1914 setSelection(bview);
1918 /* turns double-CR to single CR, others where converted into one
1919 blank. Then InsertStringAsLines is called */
1920 void LyXText::insertStringAsParagraphs(BufferView * bview, string const & str)
1922 string linestr(str);
1923 bool newline_inserted = false;
1924 for (string::size_type i = 0; i < linestr.length(); ++i) {
1925 if (linestr[i] == '\n') {
1926 if (newline_inserted) {
1927 // we know that \r will be ignored by
1928 // InsertStringA. Of course, it is a dirty
1929 // trick, but it works...
1930 linestr[i - 1] = '\r';
1934 newline_inserted = true;
1936 } else if (IsPrintable(linestr[i])) {
1937 newline_inserted = false;
1940 insertStringAsLines(bview, linestr);
1944 bool LyXText::gotoNextInset(BufferView * bview,
1945 std::vector<Inset::Code> const & codes,
1946 string const & contents) const
1948 LyXCursor res = cursor;
1951 if (res.pos() < res.par()->size() - 1) {
1952 res.pos(res.pos() + 1);
1954 res.par(res.par()->next());
1958 } while (res.par() &&
1959 !(res.par()->getChar(res.pos()) == Paragraph::META_INSET
1960 && (inset = res.par()->getInset(res.pos())) != 0
1961 && find(codes.begin(), codes.end(), inset->LyxCode())
1963 && (contents.empty() ||
1964 static_cast<InsetCommand *>(res.par()->getInset(res.pos()))->getContents()
1968 setCursor(bview, res.par(), res.pos());
1975 void LyXText::checkParagraph(BufferView * bview, Paragraph * par,
1976 Paragraph::size_type pos)
1978 LyXCursor tmpcursor;
1981 Paragraph::size_type z;
1982 Row * row = getRow(par, pos, y);
1984 // is there a break one row above
1985 if (row->previous() && row->previous()->par() == row->par()) {
1986 z = nextBreakPoint(bview, row->previous(), workWidth(bview));
1987 if (z >= row->pos()) {
1988 // set the dimensions of the row above
1989 y -= row->previous()->height();
1991 refresh_row = row->previous();
1992 status = LyXText::NEED_MORE_REFRESH;
1994 breakAgain(bview, row->previous());
1996 // set the cursor again. Otherwise
1997 // dangling pointers are possible
1998 setCursor(bview, cursor.par(), cursor.pos(),
1999 false, cursor.boundary());
2000 selection.cursor = cursor;
2005 int const tmpheight = row->height();
2006 Paragraph::size_type const tmplast = rowLast(row);
2010 breakAgain(bview, row);
2011 if (row->height() == tmpheight && rowLast(row) == tmplast)
2012 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2014 status = LyXText::NEED_MORE_REFRESH;
2016 // check the special right address boxes
2017 if (textclasslist.Style(bview->buffer()->params.textclass,
2018 par->getLayout()).margintype
2019 == MARGIN_RIGHT_ADDRESS_BOX) {
2026 redoDrawingOfParagraph(bview, tmpcursor);
2029 // set the cursor again. Otherwise dangling pointers are possible
2030 // also set the selection
2032 if (selection.set()) {
2034 setCursorIntern(bview, selection.cursor.par(), selection.cursor.pos(),
2035 false, selection.cursor.boundary());
2036 selection.cursor = cursor;
2037 setCursorIntern(bview, selection.start.par(),
2038 selection.start.pos(),
2039 false, selection.start.boundary());
2040 selection.start = cursor;
2041 setCursorIntern(bview, selection.end.par(),
2042 selection.end.pos(),
2043 false, selection.end.boundary());
2044 selection.end = cursor;
2045 setCursorIntern(bview, last_sel_cursor.par(),
2046 last_sel_cursor.pos(),
2047 false, last_sel_cursor.boundary());
2048 last_sel_cursor = cursor;
2051 setCursorIntern(bview, cursor.par(), cursor.pos(),
2052 false, cursor.boundary());
2056 // returns false if inset wasn't found
2057 bool LyXText::updateInset(BufferView * bview, Inset * inset)
2059 // first check the current paragraph
2060 int pos = cursor.par()->getPositionOfInset(inset);
2062 checkParagraph(bview, cursor.par(), pos);
2066 // check every paragraph
2068 Paragraph * par = firstParagraph();
2070 pos = par->getPositionOfInset(inset);
2072 checkParagraph(bview, par, pos);
2082 void LyXText::setCursor(BufferView * bview, Paragraph * par,
2083 Paragraph::size_type pos,
2084 bool setfont, bool boundary) const
2086 LyXCursor old_cursor = cursor;
2087 setCursorIntern(bview, par, pos, setfont, boundary);
2088 deleteEmptyParagraphMechanism(bview, old_cursor);
2092 void LyXText::setCursor(BufferView *bview, LyXCursor & cur, Paragraph * par,
2093 Paragraph::size_type pos, bool boundary) const
2097 cur.boundary(boundary);
2099 /* get the cursor y position in text */
2101 Row * row = getRow(par, pos, y);
2102 /* y is now the beginning of the cursor row */
2103 y += row->baseline();
2104 /* y is now the cursor baseline */
2107 /* now get the cursors x position */
2109 float fill_separator;
2111 float fill_label_hfill;
2112 prepareToPrint(bview, row, x, fill_separator, fill_hfill,
2114 Paragraph::size_type cursor_vpos = 0;
2115 Paragraph::size_type last = rowLastPrintable(row);
2117 if (pos > last + 1) // This shouldn't happen.
2119 else if (pos < row->pos())
2122 if (last < row->pos())
2123 cursor_vpos = row->pos();
2124 else if (pos > last && !boundary)
2125 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2126 ? row->pos() : last + 1;
2127 else if (pos > row->pos() &&
2128 (pos > last || boundary))
2129 /// Place cursor after char at (logical) position pos - 1
2130 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2131 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2133 /// Place cursor before char at (logical) position pos
2134 cursor_vpos = (bidi_level(pos) % 2 == 0)
2135 ? log2vis(pos) : log2vis(pos) + 1;
2137 Paragraph::size_type main_body =
2138 beginningOfMainBody(bview->buffer(), row->par());
2139 if ((main_body > 0) &&
2140 ((main_body-1 > last) ||
2141 !row->par()->isLineSeparator(main_body-1)))
2144 for (Paragraph::size_type vpos = row->pos();
2145 vpos < cursor_vpos; ++vpos) {
2146 pos = vis2log(vpos);
2147 if (main_body > 0 && pos == main_body - 1) {
2148 x += fill_label_hfill +
2149 lyxfont::width(textclasslist.Style(
2150 bview->buffer()->params.textclass,
2151 row->par()->getLayout())
2153 getFont(bview->buffer(), row->par(), -2));
2154 if (row->par()->isLineSeparator(main_body-1))
2155 x -= singleWidth(bview, row->par(),main_body-1);
2157 if (hfillExpansion(bview->buffer(), row, pos)) {
2158 x += singleWidth(bview, row->par(), pos);
2159 if (pos >= main_body)
2162 x += fill_label_hfill;
2163 } else if (row->par()->isSeparator(pos)) {
2164 x += singleWidth(bview, row->par(), pos);
2165 if (pos >= main_body)
2166 x += fill_separator;
2168 x += singleWidth(bview, row->par(), pos);
2177 void LyXText::setCursorIntern(BufferView * bview, Paragraph * par,
2178 Paragraph::size_type pos,
2179 bool setfont, bool boundary) const
2181 setCursor(bview, cursor, par, pos, boundary);
2183 setCurrentFont(bview);
2187 void LyXText::setCurrentFont(BufferView * bview) const
2189 Paragraph::size_type pos = cursor.pos();
2190 if (cursor.boundary() && pos > 0)
2194 if (pos == cursor.par()->size())
2196 else // potentional bug... BUG (Lgb)
2197 if (cursor.par()->isSeparator(pos)) {
2198 if (pos > cursor.row()->pos() &&
2199 bidi_level(pos) % 2 ==
2200 bidi_level(pos - 1) % 2)
2202 else if (pos + 1 < cursor.par()->size())
2208 cursor.par()->getFontSettings(bview->buffer()->params, pos);
2209 real_current_font = getFont(bview->buffer(), cursor.par(), pos);
2211 if (cursor.pos() == cursor.par()->size() &&
2212 isBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2213 !cursor.boundary()) {
2214 Language const * lang =
2215 cursor.par()->getParLanguage(bview->buffer()->params);
2216 current_font.setLanguage(lang);
2217 current_font.setNumber(LyXFont::OFF);
2218 real_current_font.setLanguage(lang);
2219 real_current_font.setNumber(LyXFont::OFF);
2224 void LyXText::setCursorFromCoordinates(BufferView * bview, int x, int y) const
2226 LyXCursor old_cursor = cursor;
2228 /* get the row first */
2230 Row * row = getRowNearY(y);
2231 cursor.par(row->par());
2234 int column = getColumnNearX(bview, row, x, bound);
2235 cursor.pos(row->pos() + column);
2237 cursor.y(y + row->baseline());
2239 cursor.boundary(bound);
2240 setCurrentFont(bview);
2241 deleteEmptyParagraphMechanism(bview, old_cursor);
2245 void LyXText::setCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2248 /* get the row first */
2250 Row * row = getRowNearY(y);
2252 int column = getColumnNearX(bview, row, x, bound);
2254 cur.par(row->par());
2255 cur.pos(row->pos() + column);
2257 cur.y(y + row->baseline());
2259 cur.boundary(bound);
2263 void LyXText::cursorLeft(BufferView * bview, bool internal) const
2265 if (cursor.pos() > 0) {
2266 bool boundary = cursor.boundary();
2267 setCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2268 if (!internal && !boundary &&
2269 isBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2270 setCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2271 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2272 Paragraph * par = cursor.par()->previous();
2273 setCursor(bview, par, par->size());
2278 void LyXText::cursorRight(BufferView * bview, bool internal) const
2280 if (!internal && cursor.boundary() &&
2281 !cursor.par()->isNewline(cursor.pos()))
2282 setCursor(bview, cursor.par(), cursor.pos(), true, false);
2283 else if (cursor.pos() < cursor.par()->size()) {
2284 setCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2286 isBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2287 setCursor(bview, cursor.par(), cursor.pos(), true, true);
2288 } else if (cursor.par()->next())
2289 setCursor(bview, cursor.par()->next(), 0);
2293 void LyXText::cursorUp(BufferView * bview) const
2295 setCursorFromCoordinates(bview, cursor.x_fix(),
2296 cursor.y() - cursor.row()->baseline() - 1);
2300 void LyXText::cursorDown(BufferView * bview) const
2302 setCursorFromCoordinates(bview, cursor.x_fix(),
2303 cursor.y() - cursor.row()->baseline()
2304 + cursor.row()->height() + 1);
2308 void LyXText::cursorUpParagraph(BufferView * bview) const
2310 if (cursor.pos() > 0) {
2311 setCursor(bview, cursor.par(), 0);
2313 else if (cursor.par()->previous()) {
2314 setCursor(bview, cursor.par()->previous(), 0);
2319 void LyXText::cursorDownParagraph(BufferView * bview) const
2321 if (cursor.par()->next()) {
2322 setCursor(bview, cursor.par()->next(), 0);
2324 setCursor(bview, cursor.par(), cursor.par()->size());
2329 void LyXText::deleteEmptyParagraphMechanism(BufferView * bview,
2330 LyXCursor const & old_cursor) const
2332 // Would be wrong to delete anything if we have a selection.
2333 if (selection.set()) return;
2335 // We allow all kinds of "mumbo-jumbo" when freespacing.
2336 if (textclasslist.Style(bview->buffer()->params.textclass,
2337 old_cursor.par()->getLayout()).free_spacing)
2340 bool deleted = false;
2342 /* Ok I'll put some comments here about what is missing.
2343 I have fixed BackSpace (and thus Delete) to not delete
2344 double-spaces automagically. I have also changed Cut,
2345 Copy and Paste to hopefully do some sensible things.
2346 There are still some small problems that can lead to
2347 double spaces stored in the document file or space at
2348 the beginning of paragraphs. This happens if you have
2349 the cursor betwenn to spaces and then save. Or if you
2350 cut and paste and the selection have a space at the
2351 beginning and then save right after the paste. I am
2352 sure none of these are very hard to fix, but I will
2353 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2354 that I can get some feedback. (Lgb)
2357 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2358 // delete the LineSeparator.
2361 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2362 // delete the LineSeparator.
2365 // If the pos around the old_cursor were spaces, delete one of them.
2366 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
2367 // Only if the cursor has really moved
2369 if (old_cursor.pos() > 0
2370 && old_cursor.pos() < old_cursor.par()->size()
2371 && old_cursor.par()->isLineSeparator(old_cursor.pos())
2372 && old_cursor.par()->isLineSeparator(old_cursor.pos() - 1)) {
2373 old_cursor.par()->erase(old_cursor.pos() - 1);
2374 redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2376 if (old_cursor.par() == cursor.par() &&
2377 cursor.pos() > old_cursor.pos()) {
2378 setCursorIntern(bview, cursor.par(),
2381 setCursorIntern(bview, cursor.par(),
2387 // Do not delete empty paragraphs with keepempty set.
2388 if ((textclasslist.Style(bview->buffer()->params.textclass,
2389 old_cursor.par()->getLayout())).keepempty)
2392 LyXCursor tmpcursor;
2394 if (old_cursor.par() != cursor.par()) {
2395 if ((old_cursor.par()->size() == 0
2396 || (old_cursor.par()->size() == 1
2397 && old_cursor.par()->isLineSeparator(0)))) {
2398 // ok, we will delete anything
2400 // make sure that you do not delete any environments
2401 status = LyXText::NEED_MORE_REFRESH;
2404 if (old_cursor.row()->previous()) {
2405 refresh_row = old_cursor.row()->previous();
2406 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2408 cursor = old_cursor; // that undo can restore the right cursor position
2409 Paragraph * endpar = old_cursor.par()->next();
2410 if (endpar && endpar->getDepth()) {
2411 while (endpar && endpar->getDepth()) {
2412 endpar = endpar->next();
2415 setUndo(bview->buffer(), Undo::DELETE,
2416 old_cursor.par()->previous(),
2421 removeRow(old_cursor.row());
2422 if (ownerParagraph() == old_cursor.par()) {
2423 ownerParagraph(ownerParagraph()->next());
2426 delete old_cursor.par();
2428 /* Breakagain the next par. Needed
2429 * because of the parindent that
2430 * can occur or dissappear. The
2431 * next row can change its height,
2432 * if there is another layout before */
2433 if (refresh_row->next()) {
2434 breakAgain(bview, refresh_row->next());
2435 updateCounters(bview, refresh_row);
2437 setHeightOfRow(bview, refresh_row);
2439 refresh_row = old_cursor.row()->next();
2440 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2443 cursor = old_cursor; // that undo can restore the right cursor position
2444 Paragraph * endpar = old_cursor.par()->next();
2445 if (endpar && endpar->getDepth()) {
2446 while (endpar && endpar->getDepth()) {
2447 endpar = endpar->next();
2450 setUndo(bview->buffer(), Undo::DELETE,
2451 old_cursor.par()->previous(),
2456 removeRow(old_cursor.row());
2458 if (ownerParagraph() == old_cursor.par()) {
2459 ownerParagraph(ownerParagraph()->next());
2462 delete old_cursor.par();
2464 /* Breakagain the next par. Needed
2465 because of the parindent that can
2466 occur or dissappear.
2467 The next row can change its height,
2468 if there is another layout before
2471 breakAgain(bview, refresh_row);
2472 updateCounters(bview, refresh_row->previous());
2478 setCursorIntern(bview, cursor.par(), cursor.pos());
2480 if (selection.cursor.par() == old_cursor.par()
2481 && selection.cursor.pos() == selection.cursor.pos()) {
2482 // correct selection
2483 selection.cursor = cursor;
2487 if (old_cursor.par()->stripLeadingSpaces(bview->buffer()->params.textclass)) {
2488 redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2490 setCursorIntern(bview, cursor.par(), cursor.pos());
2491 selection.cursor = cursor;
2498 Paragraph * LyXText::getParFromID(int id)
2500 Paragraph * result = firstParagraph();
2501 while (result && result->id() != id)
2502 result = result->next();
2508 bool LyXText::textUndo(BufferView * bview)
2512 // returns false if no undo possible
2513 Undo * undo = bview->buffer()->undostack.pop();
2517 bview->buffer()->redostack
2518 .push(createUndo(bview->buffer(), undo->kind,
2519 getParFromID(undo->number_of_before_par),
2520 getParFromID(undo->number_of_behind_par)));
2522 return textHandleUndo(bview, undo);
2526 bool LyXText::textRedo(BufferView * bview)
2530 // returns false if no redo possible
2531 Undo * undo = bview->buffer()->redostack.pop();
2535 bview->buffer()->undostack
2536 .push(createUndo(bview->buffer(), undo->kind,
2537 getParFromID(undo->number_of_before_par),
2538 getParFromID(undo->number_of_behind_par)));
2540 return textHandleUndo(bview, undo);
2544 bool LyXText::textHandleUndo(BufferView * bview, Undo * undo)
2548 // returns false if no undo possible
2549 bool result = false;
2551 Paragraph * before =
2552 getParFromID(undo->number_of_before_par);
2553 Paragraph * behind =
2554 getParFromID(undo->number_of_behind_par);
2556 Paragraph * tmppar2;
2558 Paragraph * tmppar5;
2560 // if there's no before take the beginning
2561 // of the document for redoing
2563 setCursorIntern(bview, firstParagraph(), 0);
2565 // replace the paragraphs with the undo informations
2567 Paragraph * tmppar3 = undo->par;
2568 undo->par = 0; // otherwise the undo destructor would delete the paragraph
2569 Paragraph * tmppar4 = tmppar3;
2572 while (tmppar4->next())
2573 tmppar4 = tmppar4->next();
2574 } // get last undo par
2576 // now remove the old text if there is any
2577 if (before != behind || (!behind && !before)) {
2579 tmppar5 = before->next();
2581 tmppar5 = ownerParagraph();
2583 while (tmppar5 && tmppar5 != behind) {
2585 tmppar5 = tmppar5->next();
2586 // a memory optimization for edit: Only layout information
2587 // is stored in the undo. So restore the text informations.
2588 if (undo->kind == Undo::EDIT) {
2589 tmppar2->setContentsFromPar(tmppar);
2590 tmppar->clearContents();
2591 tmppar2 = tmppar2->next();
2596 // put the new stuff in the list if there is one
2599 before->next(tmppar3);
2601 ownerParagraph(tmppar3);
2602 tmppar3->previous(before);
2605 ownerParagraph(behind);
2608 tmppar4->next(behind);
2610 behind->previous(tmppar4);
2614 // Set the cursor for redoing
2616 setCursorIntern(bview, before, 0);
2619 // calculate the endpar for redoing the paragraphs.
2621 endpar = behind->next();
2625 tmppar = getParFromID(undo->number_of_cursor_par);
2626 redoParagraphs(bview, cursor, endpar);
2628 setCursorIntern(bview, tmppar, undo->cursor_pos);
2629 updateCounters(bview, cursor.row());
2639 void LyXText::finishUndo()
2643 // makes sure the next operation will be stored
2644 undo_finished = true;
2648 void LyXText::freezeUndo()
2652 // this is dangerous and for internal use only
2657 void LyXText::unFreezeUndo()
2661 // this is dangerous and for internal use only
2662 undo_frozen = false;
2666 void LyXText::setUndo(Buffer * buf, Undo::undo_kind kind,
2667 Paragraph const * before,
2668 Paragraph const * behind) const
2673 buf->undostack.push(createUndo(buf, kind, before, behind));
2674 buf->redostack.clear();
2678 void LyXText::setRedo(Buffer * buf, Undo::undo_kind kind,
2679 Paragraph const * before, Paragraph const * behind)
2683 buf->redostack.push(createUndo(buf, kind, before, behind));
2687 Undo * LyXText::createUndo(Buffer * buf, Undo::undo_kind kind,
2688 Paragraph const * before,
2689 Paragraph const * behind) const
2694 int before_number = -1;
2695 int behind_number = -1;
2697 before_number = before->id();
2699 behind_number = behind->id();
2700 // Undo::EDIT and Undo::FINISH are
2701 // always finished. (no overlapping there)
2702 // overlapping only with insert and delete inside one paragraph:
2703 // Nobody wants all removed character
2704 // appear one by one when undoing.
2705 // EDIT is special since only layout information, not the
2706 // contents of a paragaph are stored.
2707 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
2708 // check wether storing is needed
2709 if (!buf->undostack.empty() &&
2710 buf->undostack.top()->kind == kind &&
2711 buf->undostack.top()->number_of_before_par == before_number &&
2712 buf->undostack.top()->number_of_behind_par == behind_number ){
2717 // create a new Undo
2718 Paragraph * undopar;
2720 Paragraph * start = 0;
2721 Paragraph * end = 0;
2724 start = const_cast<Paragraph*>(before->next());
2726 start = firstParagraph();
2728 end = const_cast<Paragraph*>(behind->previous());
2730 end = firstParagraph();
2734 if (start && end && (start != end->next()) &&
2735 ((before != behind) || (!before && !behind))) {
2736 Paragraph * tmppar = start;
2737 Paragraph * tmppar2 = new Paragraph(*tmppar);
2738 tmppar2->id(tmppar->id());
2740 // a memory optimization: Just store the layout information
2742 if (kind == Undo::EDIT){
2743 //tmppar2->text.clear();
2744 tmppar2->clearContents();
2749 while (tmppar != end && tmppar->next()) {
2750 tmppar = tmppar->next();
2751 tmppar2->next(new Paragraph(*tmppar));
2752 tmppar2->next()->id(tmppar->id());
2753 // a memory optimization: Just store the layout
2754 // information when only edit
2755 if (kind == Undo::EDIT){
2756 //tmppar2->next->text.clear();
2757 tmppar2->clearContents();
2759 tmppar2->next()->previous(tmppar2);
2760 tmppar2 = tmppar2->next();
2764 undopar = 0; // nothing to replace (undo of delete maybe)
2766 int cursor_par = cursor.par()->id();
2767 int cursor_pos = cursor.pos();
2769 Undo * undo = new Undo(kind,
2770 before_number, behind_number,
2771 cursor_par, cursor_pos,
2774 undo_finished = false;
2779 void LyXText::setCursorParUndo(Buffer * buf)
2783 setUndo(buf, Undo::FINISH,
2784 cursor.par()->previous(),
2785 cursor.par()->next());
2789 void LyXText::toggleAppendix(BufferView * bview)
2791 Paragraph * par = cursor.par();
2792 bool start = !par->params().startOfAppendix();
2794 // ensure that we have only one start_of_appendix in this document
2795 Paragraph * tmp = firstParagraph();
2796 for (; tmp; tmp = tmp->next())
2797 tmp->params().startOfAppendix(false);
2799 par->params().startOfAppendix(start);
2801 // we can set the refreshing parameters now
2802 status = LyXText::NEED_MORE_REFRESH;
2804 refresh_row = 0; // not needed for full update
2805 updateCounters(bview, 0);
2806 setCursor(bview, cursor.par(), cursor.pos());
2810 Paragraph * LyXText::ownerParagraph() const
2813 return inset_owner->par;
2815 return bv_owner->buffer()->paragraph;
2819 Paragraph * LyXText::ownerParagraph(Paragraph * p) const
2822 inset_owner->par = p;
2824 bv_owner->buffer()->paragraph = p;