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 * ====================================================== */
14 #pragma implementation "lyxtext.h"
19 #include "paragraph.h"
20 #include "insets/inseterror.h"
21 #include "insets/insetbib.h"
22 #include "insets/insetspecialchar.h"
23 #include "insets/insettext.h"
24 #include "insets/insetfloat.h"
27 #include "support/textutils.h"
30 #include "bufferparams.h"
31 #include "lyx_gui_misc.h"
33 #include "BufferView.h"
35 #include "CutAndPaste.h"
40 #include "FloatList.h"
42 #include "ParagraphParameters.h"
51 LyXText::LyXText(BufferView * bv)
52 : number_of_rows(0), height(0), width(0), first(0),
53 bv_owner(bv), inset_owner(0), the_locking_inset(0),
54 need_break_row(0), refresh_y(0), status(LyXText::UNCHANGED),
55 undo_finished(true), undo_frozen(false), firstrow(0), lastrow(0),
60 LyXText::LyXText(InsetText * inset)
61 : number_of_rows(0), height(0), width(0), first(0),
62 bv_owner(0), inset_owner(inset), the_locking_inset(0),
63 need_break_row(0), refresh_y(0), status(LyXText::UNCHANGED),
64 undo_finished(true), undo_frozen(false), firstrow(0), lastrow(0),
69 void LyXText::init(BufferView * bview)
74 Paragraph * par = ownerParagraph();
75 current_font = getFont(bview->buffer(), par, 0);
77 insertParagraph(bview, par, lastrow);
80 setCursorIntern(bview, firstrow->par(), 0);
81 selection.cursor = cursor;
87 // Delete all rows, this does not touch the paragraphs!
88 Row * tmprow = firstrow;
90 tmprow = firstrow->next();
97 // Gets the fully instantiated font at a given position in a paragraph
98 // Basically the same routine as Paragraph::getFont() in paragraph.C.
99 // The difference is that this one is used for displaying, and thus we
100 // are allowed to make cosmetic improvements. For instance make footnotes
102 // If position is -1, we get the layout font of the paragraph.
103 // If position is -2, we get the font of the manual label of the paragraph.
104 LyXFont const LyXText::getFont(Buffer const * buf, Paragraph * par,
105 Paragraph::size_type pos) const
107 LyXLayout const & layout =
108 textclasslist.Style(buf->params.textclass, par->getLayout());
110 Paragraph::depth_type par_depth = par->getDepth();
111 // We specialize the 95% common case:
115 if (layout.labeltype == LABEL_MANUAL
116 && pos < beginningOfMainBody(buf, par)) {
118 LyXFont f = par->getFontSettings(buf->params,
120 return f.realize(layout.reslabelfont);
122 LyXFont f = par->getFontSettings(buf->params, pos);
123 return f.realize(layout.resfont);
128 // process layoutfont for pos == -1 and labelfont for pos < -1
130 return layout.resfont;
132 return layout.reslabelfont;
136 // The uncommon case need not be optimized as much
138 LyXFont layoutfont, tmpfont;
142 if (pos < beginningOfMainBody(buf, par)) {
144 layoutfont = layout.labelfont;
147 layoutfont = layout.font;
149 tmpfont = par->getFontSettings(buf->params, pos);
150 tmpfont.realize(layoutfont);
153 // process layoutfont for pos == -1 and labelfont for pos < -1
155 tmpfont = layout.font;
157 tmpfont = layout.labelfont;
160 // Resolve against environment font information
161 while (par && par_depth && !tmpfont.resolved()) {
162 par = par->outerHook();
164 tmpfont.realize(textclasslist.
165 Style(buf->params.textclass,
166 par->getLayout()).font);
167 par_depth = par->getDepth();
171 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
177 void LyXText::setCharFont(BufferView * bv, Paragraph * par,
178 Paragraph::size_type pos, LyXFont const & fnt,
181 Buffer const * buf = bv->buffer();
182 LyXFont font = getFont(buf, par, pos);
183 font.update(fnt, buf->params.language, toggleall);
184 // Let the insets convert their font
185 if (par->getChar(pos) == Paragraph::META_INSET) {
186 Inset * inset = par->getInset(pos);
188 if (inset->editable()==Inset::HIGHLY_EDITABLE) {
189 UpdatableInset * uinset = static_cast<UpdatableInset *>(inset);
190 uinset->setFont(bv, fnt, toggleall, true);
192 font = inset->convertFont(font);
196 LyXLayout const & layout =
197 textclasslist.Style(buf->params.textclass,
200 // Get concrete layout font to reduce against
203 if (pos < beginningOfMainBody(buf, par))
204 layoutfont = layout.labelfont;
206 layoutfont = layout.font;
208 // Realize against environment font information
209 if (par->getDepth()){
210 Paragraph * tp = par;
211 while (!layoutfont.resolved() && tp && tp->getDepth()) {
212 tp = tp->outerHook();
214 layoutfont.realize(textclasslist.
215 Style(buf->params.textclass,
216 tp->getLayout()).font);
220 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
222 // Now, reduce font against full layout font
223 font.reduce(layoutfont);
225 par->setFont(pos, font);
229 void LyXText::setCharFont(Buffer const * buf, Paragraph * par,
230 Paragraph::size_type pos, LyXFont const & fnt)
233 // Let the insets convert their font
234 if (par->getChar(pos) == Paragraph::META_INSET) {
235 font = par->getInset(pos)->convertFont(font);
238 LyXLayout const & layout =
239 textclasslist.Style(buf->params.textclass,
242 // Get concrete layout font to reduce against
245 if (pos < beginningOfMainBody(buf, par))
246 layoutfont = layout.labelfont;
248 layoutfont = layout.font;
250 // Realize against environment font information
251 if (par->getDepth()){
252 Paragraph * tp = par;
253 while (!layoutfont.resolved() && tp && tp->getDepth()) {
254 tp = tp->outerHook();
256 layoutfont.realize(textclasslist.
257 Style(buf->params.textclass,
258 tp->getLayout()).font);
262 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
264 // Now, reduce font against full layout font
265 font.reduce(layoutfont);
267 par->setFont(pos, font);
271 /* inserts a new row behind the specified row, increments
272 * the touched counters */
273 void LyXText::insertRow(Row * row, Paragraph * par,
274 Paragraph::size_type pos) const
276 Row * tmprow = new Row;
279 tmprow->next(firstrow);
282 tmprow->previous(row);
283 tmprow->next(row->next());
288 tmprow->next()->previous(tmprow);
290 if (tmprow->previous())
291 tmprow->previous()->next(tmprow);
299 ++number_of_rows; // one more row
303 // removes the row and reset the touched counters
304 void LyXText::removeRow(Row * row) const
306 /* this must not happen before the currentrow for clear reasons.
307 so the trick is just to set the current row onto the previous
310 getRow(row->par(), row->pos(), unused_y);
313 row->next()->previous(row->previous());
314 if (!row->previous()) {
315 firstrow = row->next();
317 row->previous()->next(row->next());
320 lastrow = row->previous();
322 height -= row->height(); // the text becomes smaller
325 --number_of_rows; // one row less
329 // remove all following rows of the paragraph of the specified row.
330 void LyXText::removeParagraph(Row * row) const
332 Paragraph * tmppar = row->par();
336 while (row && row->par() == tmppar) {
337 tmprow = row->next();
344 // insert the specified paragraph behind the specified row
345 void LyXText::insertParagraph(BufferView * bview, Paragraph * par,
348 insertRow(row, par, 0); /* insert a new row, starting
351 setCounter(bview->buffer(), par); // set the counters
353 // and now append the whole paragraph behind the new row
356 appendParagraph(bview, firstrow);
358 row->next()->height(0);
359 appendParagraph(bview, row->next());
364 /* used in setlayout */
365 // Asger is not sure we want to do this...
366 void LyXText::makeFontEntriesLayoutSpecific(Buffer const * buf,
370 LyXLayout const & layout =
371 textclasslist.Style(buf->params.textclass, par->getLayout());
373 LyXFont layoutfont, tmpfont;
374 for (Paragraph::size_type pos = 0;
375 pos < par->size(); ++pos) {
376 if (pos < beginningOfMainBody(buf, par))
377 layoutfont = layout.labelfont;
379 layoutfont = layout.font;
381 tmpfont = par->getFontSettings(buf->params, pos);
382 tmpfont.reduce(layoutfont);
383 par->setFont(pos, tmpfont);
388 Paragraph * LyXText::setLayout(BufferView * bview,
389 LyXCursor & cur, LyXCursor & sstart_cur,
390 LyXCursor & send_cur,
391 LyXTextClass::size_type layout)
393 Paragraph * endpar = send_cur.par()->next();
394 Paragraph * undoendpar = endpar;
396 if (endpar && endpar->getDepth()) {
397 while (endpar && endpar->getDepth()) {
398 endpar = endpar->next();
402 endpar = endpar->next(); // because of parindents etc.
405 setUndo(bview->buffer(), Undo::EDIT,
406 sstart_cur.par()->previous(),
409 /* ok we have a selection. This is always between sstart_cur
410 * and sel_end cursor */
413 LyXLayout const & lyxlayout =
414 textclasslist.Style(bview->buffer()->params.textclass, layout);
416 while (cur.par() != send_cur.par()) {
417 cur.par()->setLayout(layout);
418 makeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
419 Paragraph * fppar = cur.par();
420 fppar->params().spaceTop(lyxlayout.fill_top ?
421 VSpace(VSpace::VFILL)
422 : VSpace(VSpace::NONE));
423 fppar->params().spaceBottom(lyxlayout.fill_bottom ?
424 VSpace(VSpace::VFILL)
425 : VSpace(VSpace::NONE));
426 if (lyxlayout.margintype == MARGIN_MANUAL)
427 cur.par()->setLabelWidthString(lyxlayout.labelstring());
428 if (lyxlayout.labeltype != LABEL_BIBLIO
430 delete fppar->bibkey;
433 cur.par(cur.par()->next());
435 cur.par()->setLayout(layout);
436 makeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
437 Paragraph * fppar = cur.par();
438 fppar->params().spaceTop(lyxlayout.fill_top ?
439 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
440 fppar->params().spaceBottom(lyxlayout.fill_bottom ?
441 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
442 if (lyxlayout.margintype == MARGIN_MANUAL)
443 cur.par()->setLabelWidthString(lyxlayout.labelstring());
444 if (lyxlayout.labeltype != LABEL_BIBLIO
446 delete fppar->bibkey;
453 // set layout over selection and make a total rebreak of those paragraphs
454 void LyXText::setLayout(BufferView * bview, LyXTextClass::size_type layout)
456 LyXCursor tmpcursor = cursor; /* store the current cursor */
458 // if there is no selection just set the layout
459 // of the current paragraph */
460 if (!selection.set()) {
461 selection.start = cursor; // dummy selection
462 selection.end = cursor;
464 Paragraph * endpar = setLayout(bview, cursor, selection.start,
465 selection.end, layout);
466 redoParagraphs(bview, selection.start, endpar);
468 // we have to reset the selection, because the
469 // geometry could have changed
470 setCursor(bview, selection.start.par(),
471 selection.start.pos(), false);
472 selection.cursor = cursor;
473 setCursor(bview, selection.end.par(), selection.end.pos(),
475 updateCounters(bview, cursor.row());
476 clearSelection(bview);
478 setCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
482 // increment depth over selection and
483 // make a total rebreak of those paragraphs
484 void LyXText::incDepth(BufferView * bview)
486 // If there is no selection, just use the current paragraph
487 if (!selection.set()) {
488 selection.start = cursor; // dummy selection
489 selection.end = cursor;
492 // We end at the next paragraph with depth 0
493 Paragraph * endpar = selection.end.par()->next();
495 Paragraph * undoendpar = endpar;
497 if (endpar && endpar->getDepth()) {
498 while (endpar && endpar->getDepth()) {
499 endpar = endpar->next();
504 endpar = endpar->next(); // because of parindents etc.
507 setUndo(bview->buffer(), Undo::EDIT,
508 selection.start.par()->previous(),
511 LyXCursor tmpcursor = cursor; // store the current cursor
513 // ok we have a selection. This is always between sel_start_cursor
514 // and sel_end cursor
515 cursor = selection.start;
517 bool anything_changed = false;
520 // NOTE: you can't change the depth of a bibliography entry
522 textclasslist.Style(bview->buffer()->params.textclass,
523 cursor.par()->getLayout()
524 ).labeltype != LABEL_BIBLIO) {
525 Paragraph * prev = cursor.par()->previous();
528 && (prev->getDepth() - cursor.par()->getDepth() > 0
529 || (prev->getDepth() == cursor.par()->getDepth()
530 && textclasslist.Style(bview->buffer()->params.textclass,
531 prev->getLayout()).isEnvironment()))) {
532 cursor.par()->params().depth(cursor.par()->params().depth() + 1);
533 anything_changed = true;
536 if (cursor.par() == selection.end.par())
538 cursor.par(cursor.par()->next());
541 // if nothing changed set all depth to 0
542 if (!anything_changed) {
543 cursor = selection.start;
544 while (cursor.par() != selection.end.par()) {
545 cursor.par()->params().depth(0);
546 cursor.par(cursor.par()->next());
548 cursor.par()->params().depth(0);
551 redoParagraphs(bview, selection.start, endpar);
553 // we have to reset the selection, because the
554 // geometry could have changed
555 setCursor(bview, selection.start.par(), selection.start.pos());
556 selection.cursor = cursor;
557 setCursor(bview, selection.end.par(), selection.end.pos());
558 updateCounters(bview, cursor.row());
559 clearSelection(bview);
561 setCursor(bview, tmpcursor.par(), tmpcursor.pos());
565 // decrement depth over selection and
566 // make a total rebreak of those paragraphs
567 void LyXText::decDepth(BufferView * bview)
569 // if there is no selection just set the layout
570 // of the current paragraph
571 if (!selection.set()) {
572 selection.start = cursor; // dummy selection
573 selection.end = cursor;
575 Paragraph * endpar = selection.end.par()->next();
576 Paragraph * undoendpar = endpar;
578 if (endpar && endpar->getDepth()) {
579 while (endpar && endpar->getDepth()) {
580 endpar = endpar->next();
584 endpar = endpar->next(); // because of parindents etc.
587 setUndo(bview->buffer(), Undo::EDIT,
588 selection.start.par()->previous(),
591 LyXCursor tmpcursor = cursor; // store the current cursor
593 // ok we have a selection. This is always between sel_start_cursor
594 // and sel_end cursor
595 cursor = selection.start;
598 if (cursor.par()->params().depth())
599 cursor.par()->params().depth(cursor.par()->params().depth() - 1);
600 if (cursor.par() == selection.end.par())
602 cursor.par(cursor.par()->next());
605 redoParagraphs(bview, selection.start, endpar);
607 // we have to reset the selection, because the
608 // geometry could have changed
609 setCursor(bview, selection.start.par(),
610 selection.start.pos());
611 selection.cursor = cursor;
612 setCursor(bview, selection.end.par(), selection.end.pos());
613 updateCounters(bview, cursor.row());
614 clearSelection(bview);
616 setCursor(bview, tmpcursor.par(), tmpcursor.pos());
620 // set font over selection and make a total rebreak of those paragraphs
621 void LyXText::setFont(BufferView * bview, LyXFont const & font, bool toggleall)
623 // if there is no selection just set the current_font
624 if (!selection.set()) {
625 // Determine basis font
627 if (cursor.pos() < beginningOfMainBody(bview->buffer(),
629 layoutfont = getFont(bview->buffer(), cursor.par(),-2);
631 layoutfont = getFont(bview->buffer(), cursor.par(),-1);
632 // Update current font
633 real_current_font.update(font,
634 bview->buffer()->params.language,
637 // Reduce to implicit settings
638 current_font = real_current_font;
639 current_font.reduce(layoutfont);
640 // And resolve it completely
641 real_current_font.realize(layoutfont);
645 LyXCursor tmpcursor = cursor; // store the current cursor
647 // ok we have a selection. This is always between sel_start_cursor
648 // and sel_end cursor
650 setUndo(bview->buffer(), Undo::EDIT,
651 selection.start.par()->previous(),
652 selection.end.par()->next());
654 cursor = selection.start;
655 while (cursor.par() != selection.end.par() ||
656 (cursor.pos() < selection.end.pos())) {
657 if (cursor.pos() < cursor.par()->size()) {
658 // an open footnote should behave
660 setCharFont(bview, cursor.par(), cursor.pos(), font, toggleall);
661 cursor.pos(cursor.pos() + 1);
664 cursor.par(cursor.par()->next());
669 redoParagraphs(bview, selection.start, selection.end.par()->next());
671 // we have to reset the selection, because the
672 // geometry could have changed
673 setCursor(bview, selection.start.par(), selection.start.pos());
674 selection.cursor = cursor;
675 setCursor(bview, selection.end.par(), selection.end.pos());
676 clearSelection(bview);
678 setCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
679 tmpcursor.boundary());
683 void LyXText::redoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
685 Row * tmprow = cur.row();
686 int y = cur.y() - tmprow->baseline();
688 setHeightOfRow(bview, tmprow);
691 Paragraph * first_phys_par = tmprow->par();
693 // find the first row of the paragraph
694 if (first_phys_par != tmprow->par())
695 while (tmprow->previous()
696 && tmprow->previous()->par() != first_phys_par) {
697 tmprow = tmprow->previous();
698 y -= tmprow->height();
699 setHeightOfRow(bview, tmprow);
701 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
702 tmprow = tmprow->previous();
703 y -= tmprow->height();
704 setHeightOfRow(bview, tmprow);
707 while (tmprow->previous() && tmprow->previous()->par() == tmprow->par()) {
708 tmprow = tmprow->previous();
709 y -= tmprow->height();
710 setHeightOfRow(bview, tmprow);
714 // we can set the refreshing parameters now
715 status = LyXText::NEED_MORE_REFRESH;
717 refresh_row = tmprow;
718 setCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
722 void LyXText::redoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
724 Row * tmprow = cur.row();
726 int y = cur.y() - tmprow->baseline();
727 setHeightOfRow(bview, tmprow);
730 Paragraph * first_phys_par = tmprow->par();
732 // find the first row of the paragraph
733 if (first_phys_par != tmprow->par())
734 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
735 tmprow = tmprow->previous();
736 y -= tmprow->height();
738 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
739 tmprow = tmprow->previous();
740 y -= tmprow->height();
743 while (tmprow->previous() && tmprow->previous()->par() == tmprow->par()) {
744 tmprow = tmprow->previous();
745 y -= tmprow->height();
748 // we can set the refreshing parameters now
749 if (status == LyXText::UNCHANGED || y < refresh_y) {
751 refresh_row = tmprow;
753 status = LyXText::NEED_MORE_REFRESH;
754 setCursor(bview, cur.par(), cur.pos());
758 /* deletes and inserts again all paragaphs between the cursor
759 * and the specified par
760 * This function is needed after SetLayout and SetFont etc. */
761 void LyXText::redoParagraphs(BufferView * bview, LyXCursor const & cur,
762 Paragraph const * endpar) const
765 Paragraph * tmppar = 0;
766 Paragraph * first_phys_par = 0;
768 Row * tmprow = cur.row();
770 int y = cur.y() - tmprow->baseline();
773 if (!tmprow->previous()) {
774 first_phys_par = firstParagraph(); // a trick/hack for UNDO
776 first_phys_par = tmprow->par();
777 // find the first row of the paragraph
778 if (first_phys_par != tmprow->par())
779 while (tmprow->previous() &&
780 (tmprow->previous()->par() != first_phys_par)) {
781 tmprow = tmprow->previous();
782 y -= tmprow->height();
784 while (tmprow->previous()
785 && tmprow->previous()->par() == first_phys_par) {
786 tmprow = tmprow->previous();
787 y -= tmprow->height();
791 if (!tmprow->previous()) {
792 // a trick/hack for UNDO
793 // Can somebody please tell me _why_ this solves
795 first_phys_par = firstParagraph();
797 first_phys_par = tmprow->par();
798 while (tmprow->previous()
799 && tmprow->previous()->par() == first_phys_par) {
800 tmprow = tmprow->previous();
801 y -= tmprow->height();
806 // we can set the refreshing parameters now
807 status = LyXText::NEED_MORE_REFRESH;
809 refresh_row = tmprow->previous(); /* the real refresh row will
810 be deleted, so I store
814 tmppar = tmprow->next()->par();
817 while (tmppar != endpar) {
818 removeRow(tmprow->next());
820 tmppar = tmprow->next()->par();
825 // remove the first one
826 tmprow2 = tmprow; /* this is because tmprow->previous()
828 tmprow = tmprow->previous();
831 tmppar = first_phys_par;
835 insertParagraph(bview, tmppar, tmprow);
838 while (tmprow->next() && tmprow->next()->par() == tmppar)
839 tmprow = tmprow->next();
840 tmppar = tmppar->next();
842 } while (tmppar != endpar);
844 // this is because of layout changes
846 refresh_y -= refresh_row->height();
847 setHeightOfRow(bview, refresh_row);
849 refresh_row = firstrow;
851 setHeightOfRow(bview, refresh_row);
854 if (tmprow && tmprow->next())
855 setHeightOfRow(bview, tmprow->next());
859 bool LyXText::fullRebreak(BufferView * bview)
865 if (need_break_row) {
866 breakAgain(bview, need_break_row);
874 /* important for the screen */
877 /* the cursor set functions have a special mechanism. When they
878 * realize, that you left an empty paragraph, they will delete it.
879 * They also delete the corresponding row */
881 // need the selection cursor:
882 void LyXText::setSelection(BufferView * bview)
884 bool const lsel = selection.set();
886 if (!selection.set()) {
887 last_sel_cursor = selection.cursor;
888 selection.start = selection.cursor;
889 selection.end = selection.cursor;
894 // first the toggling area
895 if (cursor.y() < last_sel_cursor.y()
896 || (cursor.y() == last_sel_cursor.y()
897 && cursor.x() < last_sel_cursor.x())) {
898 toggle_end_cursor = last_sel_cursor;
899 toggle_cursor = cursor;
901 toggle_end_cursor = cursor;
902 toggle_cursor = last_sel_cursor;
905 last_sel_cursor = cursor;
907 // and now the whole selection
909 if (selection.cursor.par() == cursor.par())
910 if (selection.cursor.pos() < cursor.pos()) {
911 selection.end = cursor;
912 selection.start = selection.cursor;
914 selection.end = selection.cursor;
915 selection.start = cursor;
917 else if (selection.cursor.y() < cursor.y() ||
918 (selection.cursor.y() == cursor.y() && selection.cursor.x() < cursor.x())) {
919 selection.end = cursor;
920 selection.start = selection.cursor;
923 selection.end = selection.cursor;
924 selection.start = cursor;
927 // a selection with no contents is not a selection
928 if (selection.start.par() == selection.end.par() &&
929 selection.start.pos() == selection.end.pos())
930 selection.set(false);
932 if (inset_owner && (selection.set() || lsel))
933 inset_owner->setUpdateStatus(bview, InsetText::SELECTION);
937 string const LyXText::selectionAsString(Buffer const * buffer) const
939 if (!selection.set()) return string();
942 // Special handling if the whole selection is within one paragraph
943 if (selection.start.par() == selection.end.par()) {
944 result += selection.start.par()->asString(buffer,
945 selection.start.pos(),
946 selection.end.pos());
950 // The selection spans more than one paragraph
952 // First paragraph in selection
953 result += selection.start.par()->asString(buffer,
954 selection.start.pos(),
955 selection.start.par()->size())
958 // The paragraphs in between (if any)
959 LyXCursor tmpcur(selection.start);
960 tmpcur.par(tmpcur.par()->next());
961 while (tmpcur.par() != selection.end.par()) {
962 result += tmpcur.par()->asString(buffer, 0, tmpcur.par()->size()) + "\n\n";
963 tmpcur.par(tmpcur.par()->next()); // Or NextAfterFootnote??
966 // Last paragraph in selection
967 result += selection.end.par()->asString(buffer, 0, selection.end.pos());
973 void LyXText::clearSelection(BufferView * /*bview*/) const
975 selection.set(false);
976 selection.mark(false);
977 selection.end = selection.start = cursor;
981 void LyXText::cursorHome(BufferView * bview) const
983 setCursor(bview, cursor.par(), cursor.row()->pos());
987 void LyXText::cursorEnd(BufferView * bview) const
989 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
990 setCursor(bview, cursor.par(), rowLast(cursor.row()) + 1);
992 if (cursor.par()->size() &&
993 (cursor.par()->getChar(rowLast(cursor.row())) == ' '
994 || cursor.par()->isNewline(rowLast(cursor.row()))))
995 setCursor(bview, cursor.par(), rowLast(cursor.row()));
997 setCursor(bview,cursor.par(), rowLast(cursor.row()) + 1);
1002 void LyXText::cursorTop(BufferView * bview) const
1004 while (cursor.par()->previous())
1005 cursor.par(cursor.par()->previous());
1006 setCursor(bview, cursor.par(), 0);
1010 void LyXText::cursorBottom(BufferView * bview) const
1012 while (cursor.par()->next())
1013 cursor.par(cursor.par()->next());
1014 setCursor(bview, cursor.par(), cursor.par()->size());
1018 void LyXText::toggleFree(BufferView * bview,
1019 LyXFont const & font, bool toggleall)
1021 // If the mask is completely neutral, tell user
1022 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1023 // Could only happen with user style
1024 bview->owner()->message(_("No font change defined. Use Character under the Layout menu to define font change."));
1028 // Try implicit word selection
1029 // If there is a change in the language the implicit word selection
1031 LyXCursor resetCursor = cursor;
1032 bool implicitSelection = (font.language() == ignore_language
1033 && font.number() == LyXFont::IGNORE)
1034 ? selectWordWhenUnderCursor(bview) : false;
1037 setFont(bview, font, toggleall);
1039 /* Implicit selections are cleared afterwards and cursor is set to the
1040 original position. */
1041 if (implicitSelection) {
1042 clearSelection(bview);
1043 cursor = resetCursor;
1044 setCursor(bview, cursor.par(), cursor.pos());
1045 selection.cursor = cursor;
1048 inset_owner->setUpdateStatus(bview, InsetText::CURSOR_PAR);
1052 Paragraph::size_type
1053 LyXText::beginningOfMainBody(Buffer const * buf,
1054 Paragraph const * par) const
1056 if (textclasslist.Style(buf->params.textclass,
1057 par->getLayout()).labeltype != LABEL_MANUAL)
1060 return par->beginningOfMainBody();
1064 /* the DTP switches for paragraphs. LyX will store them in the
1065 * first physicla paragraph. When a paragraph is broken, the top settings
1066 * rest, the bottom settings are given to the new one. So I can make shure,
1067 * they do not duplicate themself and you cannnot make dirty things with
1070 void LyXText::setParagraph(BufferView * bview,
1071 bool line_top, bool line_bottom,
1072 bool pagebreak_top, bool pagebreak_bottom,
1073 VSpace const & space_top,
1074 VSpace const & space_bottom,
1076 string labelwidthstring,
1079 LyXCursor tmpcursor = cursor;
1080 if (!selection.set()) {
1081 selection.start = cursor;
1082 selection.end = cursor;
1085 // make sure that the depth behind the selection are restored, too
1086 Paragraph * endpar = selection.end.par()->next();
1087 Paragraph * undoendpar = endpar;
1089 if (endpar && endpar->getDepth()) {
1090 while (endpar && endpar->getDepth()) {
1091 endpar = endpar->next();
1092 undoendpar = endpar;
1096 endpar = endpar->next(); // because of parindents etc.
1099 setUndo(bview->buffer(), Undo::EDIT,
1100 selection.start.par()->previous(),
1104 Paragraph * tmppar = selection.end.par();
1105 while (tmppar != selection.start.par()->previous()) {
1106 setCursor(bview, tmppar, 0);
1107 status = LyXText::NEED_MORE_REFRESH;
1108 refresh_row = cursor.row();
1109 refresh_y = cursor.y() - cursor.row()->baseline();
1110 cursor.par()->params().lineTop(line_top);
1111 cursor.par()->params().lineBottom(line_bottom);
1112 cursor.par()->params().pagebreakTop(pagebreak_top);
1113 cursor.par()->params().pagebreakBottom(pagebreak_bottom);
1114 cursor.par()->params().spaceTop(space_top);
1115 cursor.par()->params().spaceBottom(space_bottom);
1116 // does the layout allow the new alignment?
1117 if (align == LYX_ALIGN_LAYOUT)
1118 align = textclasslist
1119 .Style(bview->buffer()->params.textclass,
1120 cursor.par()->getLayout()).align;
1121 if (align & textclasslist
1122 .Style(bview->buffer()->params.textclass,
1123 cursor.par()->getLayout()).alignpossible) {
1124 if (align == textclasslist
1125 .Style(bview->buffer()->params.textclass,
1126 cursor.par()->getLayout()).align)
1127 cursor.par()->params().align(LYX_ALIGN_LAYOUT);
1129 cursor.par()->params().align(align);
1131 cursor.par()->setLabelWidthString(labelwidthstring);
1132 cursor.par()->params().noindent(noindent);
1133 tmppar = cursor.par()->previous();
1136 redoParagraphs(bview, selection.start, endpar);
1138 clearSelection(bview);
1139 setCursor(bview, selection.start.par(), selection.start.pos());
1140 selection.cursor = cursor;
1141 setCursor(bview, selection.end.par(), selection.end.pos());
1142 setSelection(bview);
1143 setCursor(bview, tmpcursor.par(), tmpcursor.pos());
1145 bview->updateInset(inset_owner, true);
1149 char loweralphaCounter(int n)
1151 if (n < 1 || n > 26)
1161 char alphaCounter(int n)
1163 if (n < 1 || n > 26)
1171 char hebrewCounter(int n)
1173 static const char hebrew[22] = {
1174 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1175 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1176 '÷', 'ø', 'ù', 'ú'
1178 if (n < 1 || n > 22)
1186 string const romanCounter(int n)
1188 static char const * roman[20] = {
1189 "i", "ii", "iii", "iv", "v",
1190 "vi", "vii", "viii", "ix", "x",
1191 "xi", "xii", "xiii", "xiv", "xv",
1192 "xvi", "xvii", "xviii", "xix", "xx"
1194 if (n < 1 || n > 20)
1203 // set the counter of a paragraph. This includes the labels
1204 void LyXText::setCounter(Buffer const * buf, Paragraph * par) const
1206 LyXLayout const & layout =
1207 textclasslist.Style(buf->params.textclass,
1210 LyXTextClass const & textclass =
1211 textclasslist.TextClass(buf->params.textclass);
1213 /* copy the prev-counters to this one, unless this is the start of a
1214 footnote or of a bibliography or the very first paragraph */
1216 && !(textclasslist.Style(buf->params.textclass,
1217 par->previous()->getLayout()
1218 ).labeltype != LABEL_BIBLIO
1219 && layout.labeltype == LABEL_BIBLIO)) {
1220 for (int i = 0; i < 10; ++i) {
1221 par->setCounter(i, par->previous()->getFirstCounter(i));
1223 par->params().appendix(par->previous()->params().appendix());
1224 if (!par->params().appendix() && par->params().startOfAppendix()) {
1225 par->params().appendix(true);
1226 for (int i = 0; i < 10; ++i) {
1227 par->setCounter(i, 0);
1230 par->enumdepth = par->previous()->enumdepth;
1231 par->itemdepth = par->previous()->itemdepth;
1233 for (int i = 0; i < 10; ++i) {
1234 par->setCounter(i, 0);
1236 par->params().appendix(par->params().startOfAppendix());
1241 /* Maybe we have to increment the enumeration depth.
1242 * BUT, enumeration in a footnote is considered in isolation from its
1243 * surrounding paragraph so don't increment if this is the
1244 * first line of the footnote
1245 * AND, bibliographies can't have their depth changed ie. they
1246 * are always of depth 0
1249 && par->previous()->getDepth() < par->getDepth()
1250 && textclasslist.Style(buf->params.textclass,
1251 par->previous()->getLayout()
1252 ).labeltype == LABEL_COUNTER_ENUMI
1253 && par->enumdepth < 3
1254 && layout.labeltype != LABEL_BIBLIO) {
1258 /* Maybe we have to decrement the enumeration depth, see note above */
1260 && par->previous()->getDepth() > par->getDepth()
1261 && layout.labeltype != LABEL_BIBLIO) {
1262 par->enumdepth = par->depthHook(par->getDepth())->enumdepth;
1263 par->setCounter(6 + par->enumdepth,
1264 par->depthHook(par->getDepth())->getCounter(6 + par->enumdepth));
1265 /* reset the counters.
1266 * A depth change is like a breaking layout
1268 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1269 par->setCounter(i, 0);
1272 if (!par->params().labelString().empty()) {
1273 par->params().labelString(string());
1276 if (layout.margintype == MARGIN_MANUAL) {
1277 if (par->params().labelWidthString().empty()) {
1278 par->setLabelWidthString(layout.labelstring());
1281 par->setLabelWidthString(string());
1284 /* is it a layout that has an automatic label ? */
1285 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1287 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1288 if (i >= 0 && i<= buf->params.secnumdepth) {
1289 par->incCounter(i); // increment the counter
1291 // Is there a label? Useful for Chapter layout
1292 if (!par->params().appendix()) {
1293 if (!layout.labelstring().empty())
1294 par->params().labelString(layout.labelstring());
1296 par->params().labelString(string());
1298 if (!layout.labelstring_appendix().empty())
1299 par->params().labelString(layout.labelstring_appendix());
1301 par->params().labelString(string());
1304 std::ostringstream s;
1306 if (!par->params().appendix()) {
1307 switch (2 * LABEL_COUNTER_CHAPTER -
1308 textclass.maxcounter() + i) {
1309 case LABEL_COUNTER_CHAPTER:
1310 s << par->getCounter(i);
1312 case LABEL_COUNTER_SECTION:
1313 s << par->getCounter(i - 1) << '.'
1314 << par->getCounter(i);
1316 case LABEL_COUNTER_SUBSECTION:
1317 s << par->getCounter(i - 2) << '.'
1318 << par->getCounter(i - 1) << '.'
1319 << par->getCounter(i);
1321 case LABEL_COUNTER_SUBSUBSECTION:
1322 s << par->getCounter(i - 3) << '.'
1323 << par->getCounter(i - 2) << '.'
1324 << par->getCounter(i - 1) << '.'
1325 << par->getCounter(i);
1328 case LABEL_COUNTER_PARAGRAPH:
1329 s << par->getCounter(i - 4) << '.'
1330 << par->getCounter(i - 3) << '.'
1331 << par->getCounter(i - 2) << '.'
1332 << par->getCounter(i - 1) << '.'
1333 << par->getCounter(i);
1335 case LABEL_COUNTER_SUBPARAGRAPH:
1336 s << par->getCounter(i - 5) << '.'
1337 << par->getCounter(i - 4) << '.'
1338 << par->getCounter(i - 3) << '.'
1339 << par->getCounter(i - 2) << '.'
1340 << par->getCounter(i - 1) << '.'
1341 << par->getCounter(i);
1345 // Can this ever be reached? And in the
1346 // case it is, how can this be correct?
1348 s << par->getCounter(i) << '.';
1351 } else { // appendix
1352 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1353 case LABEL_COUNTER_CHAPTER:
1354 if (par->isRightToLeftPar(buf->params))
1355 s << hebrewCounter(par->getCounter(i));
1357 s << alphaCounter(par->getCounter(i));
1359 case LABEL_COUNTER_SECTION:
1360 if (par->isRightToLeftPar(buf->params))
1361 s << hebrewCounter(par->getCounter(i - 1));
1363 s << alphaCounter(par->getCounter(i - 1));
1366 << par->getCounter(i);
1369 case LABEL_COUNTER_SUBSECTION:
1370 if (par->isRightToLeftPar(buf->params))
1371 s << hebrewCounter(par->getCounter(i - 2));
1373 s << alphaCounter(par->getCounter(i - 2));
1376 << par->getCounter(i-1) << '.'
1377 << par->getCounter(i);
1380 case LABEL_COUNTER_SUBSUBSECTION:
1381 if (par->isRightToLeftPar(buf->params))
1382 s << hebrewCounter(par->getCounter(i-3));
1384 s << alphaCounter(par->getCounter(i-3));
1387 << par->getCounter(i-2) << '.'
1388 << par->getCounter(i-1) << '.'
1389 << par->getCounter(i);
1392 case LABEL_COUNTER_PARAGRAPH:
1393 if (par->isRightToLeftPar(buf->params))
1394 s << hebrewCounter(par->getCounter(i-4));
1396 s << alphaCounter(par->getCounter(i-4));
1399 << par->getCounter(i-3) << '.'
1400 << par->getCounter(i-2) << '.'
1401 << par->getCounter(i-1) << '.'
1402 << par->getCounter(i);
1405 case LABEL_COUNTER_SUBPARAGRAPH:
1406 if (par->isRightToLeftPar(buf->params))
1407 s << hebrewCounter(par->getCounter(i-5));
1409 s << alphaCounter(par->getCounter(i-5));
1412 << par->getCounter(i-4) << '.'
1413 << par->getCounter(i-3) << '.'
1414 << par->getCounter(i-2) << '.'
1415 << par->getCounter(i-1) << '.'
1416 << par->getCounter(i);
1420 // Can this ever be reached? And in the
1421 // case it is, how can this be correct?
1423 s << par->getCounter(i) << '.';
1429 par->params().labelString(par->params().labelString() +s.str().c_str());
1430 // We really want to remove the c_str as soon as
1433 for (i++; i < 10; ++i) {
1434 // reset the following counters
1435 par->setCounter(i, 0);
1437 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1438 for (i++; i < 10; ++i) {
1439 // reset the following counters
1440 par->setCounter(i, 0);
1442 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1443 par->incCounter(i + par->enumdepth);
1444 int number = par->getCounter(i + par->enumdepth);
1446 std::ostringstream s;
1448 switch (par->enumdepth) {
1450 if (par->isRightToLeftPar(buf->params))
1452 << hebrewCounter(number)
1456 << loweralphaCounter(number)
1460 if (par->isRightToLeftPar(buf->params))
1461 s << '.' << romanCounter(number);
1463 s << romanCounter(number) << '.';
1466 if (par->isRightToLeftPar(buf->params))
1468 << alphaCounter(number);
1470 s << alphaCounter(number)
1474 if (par->isRightToLeftPar(buf->params))
1481 par->params().labelString(s.str().c_str());
1482 // we really want to get rid of that c_str()
1484 for (i += par->enumdepth + 1; i < 10; ++i)
1485 par->setCounter(i, 0); /* reset the following counters */
1488 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1489 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1491 int number = par->getCounter(i);
1493 InsetCommandParams p( "bibitem" );
1494 par->bibkey = new InsetBibKey(p);
1496 par->bibkey->setCounter(number);
1497 par->params().labelString(layout.labelstring());
1499 // In biblio should't be following counters but...
1501 string s = layout.labelstring();
1503 // the caption hack:
1504 if (layout.labeltype == LABEL_SENSITIVE) {
1505 bool isOK (par->InInset() && par->InInset()->owner() &&
1506 (par->InInset()->owner()->lyxCode() == Inset::FLOAT_CODE));
1509 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
1511 = floatList.getType(tmp->type());
1512 // We should get the correct number here too.
1513 s = fl.name() + " #:";
1515 /* par->SetLayout(0);
1516 s = layout->labelstring; */
1517 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1518 ? " :úåòîùî øñç" : "Senseless: ";
1521 par->params().labelString(s);
1523 /* reset the enumeration counter. They are always resetted
1524 * when there is any other layout between */
1525 for (int i = 6 + par->enumdepth; i < 10; ++i)
1526 par->setCounter(i, 0);
1531 /* Updates all counters BEHIND the row. Changed paragraphs
1532 * with a dynamic left margin will be rebroken. */
1533 void LyXText::updateCounters(BufferView * bview, Row * row) const
1541 par = row->par()->next();
1545 while (row->par() != par)
1548 setCounter(bview->buffer(), par);
1550 /* now check for the headline layouts. remember that they
1551 * have a dynamic left margin */
1552 if ((textclasslist.Style(bview->buffer()->params.textclass,
1553 par->layout).margintype == MARGIN_DYNAMIC
1554 || textclasslist.Style(bview->buffer()->params.textclass,
1555 par->layout).labeltype == LABEL_SENSITIVE)) {
1557 /* Rebreak the paragraph */
1558 removeParagraph(row);
1559 appendParagraph(bview, row);
1566 /* insets an inset. */
1567 void LyXText::insertInset(BufferView * bview, Inset * inset)
1569 if (!cursor.par()->insertInsetAllowed(inset))
1571 setUndo(bview->buffer(), Undo::INSERT,
1572 cursor.par()->previous(),
1573 cursor.par()->next());
1574 cursor.par()->insertInset(cursor.pos(), inset);
1575 insertChar(bview, Paragraph::META_INSET); /* just to rebreak and refresh correctly.
1576 * The character will not be inserted a
1579 // If we enter a highly editable inset the cursor should be to before
1580 // the inset. This couldn't happen before as Undo was not handled inside
1581 // inset now after the Undo LyX tries to call inset->Edit(...) again
1582 // and cannot do this as the cursor is behind the inset and GetInset
1583 // does not return the inset!
1584 if (inset->editable() == Inset::HIGHLY_EDITABLE) {
1585 cursorLeft(bview, true);
1591 void LyXText::copyEnvironmentType()
1593 copylayouttype = cursor.par()->getLayout();
1597 void LyXText::pasteEnvironmentType(BufferView * bview)
1599 setLayout(bview, copylayouttype);
1603 void LyXText::cutSelection(BufferView * bview, bool doclear)
1605 // Stuff what we got on the clipboard. Even if there is no selection.
1607 // There is a problem with having the stuffing here in that the
1608 // larger the selection the slower LyX will get. This can be
1609 // solved by running the line below only when the selection has
1610 // finished. The solution used currently just works, to make it
1611 // faster we need to be more clever and probably also have more
1612 // calls to stuffClipboard. (Lgb)
1613 bview->stuffClipboard(selectionAsString(bview->buffer()));
1615 // This doesn't make sense, if there is no selection
1616 if (!selection.set())
1619 // OK, we have a selection. This is always between selection.start
1620 // and selection.end
1622 // make sure that the depth behind the selection are restored, too
1623 Paragraph * endpar = selection.end.par()->next();
1624 Paragraph * undoendpar = endpar;
1626 if (endpar && endpar->getDepth()) {
1627 while (endpar && endpar->getDepth()) {
1628 endpar = endpar->next();
1629 undoendpar = endpar;
1631 } else if (endpar) {
1632 endpar = endpar->next(); // because of parindents etc.
1635 setUndo(bview->buffer(), Undo::DELETE,
1636 selection.start.par()->previous(),
1639 // there are two cases: cut only within one paragraph or
1640 // more than one paragraph
1641 if (selection.start.par() == selection.end.par()) {
1642 // only within one paragraph
1643 endpar = selection.end.par();
1644 int pos = selection.end.pos();
1645 CutAndPaste::cutSelection(selection.start.par(), &endpar,
1646 selection.start.pos(), pos,
1647 bview->buffer()->params.textclass, doclear);
1648 selection.end.pos(pos);
1650 endpar = selection.end.par();
1651 int pos = selection.end.pos();
1652 CutAndPaste::cutSelection(selection.start.par(), &endpar,
1653 selection.start.pos(), pos,
1654 bview->buffer()->params.textclass, doclear);
1656 selection.end.par(endpar);
1657 selection.end.pos(pos);
1658 cursor.pos(selection.end.pos());
1660 endpar = endpar->next();
1662 // sometimes necessary
1664 selection.start.par()->stripLeadingSpaces(bview->buffer()->params.textclass);
1666 redoParagraphs(bview, selection.start, endpar);
1668 // cutSelection can invalidate the cursor so we need to set
1670 cursor = selection.start;
1672 // need a valid cursor. (Lgb)
1673 clearSelection(bview);
1675 setCursor(bview, cursor.par(), cursor.pos());
1676 selection.cursor = cursor;
1677 updateCounters(bview, cursor.row());
1681 void LyXText::copySelection(BufferView * bview)
1683 // Stuff what we got on the clipboard. Even if there is no selection.
1685 // There is a problem with having the stuffing here in that the
1686 // larger the selection the slower LyX will get. This can be
1687 // solved by running the line below only when the selection has
1688 // finished. The solution used currently just works, to make it
1689 // faster we need to be more clever and probably also have more
1690 // calls to stuffClipboard. (Lgb)
1691 bview->stuffClipboard(selectionAsString(bview->buffer()));
1693 // this doesnt make sense, if there is no selection
1694 if (!selection.set())
1697 // ok we have a selection. This is always between selection.start
1698 // and sel_end cursor
1700 // copy behind a space if there is one
1701 while (selection.start.par()->size() > selection.start.pos()
1702 && selection.start.par()->isLineSeparator(selection.start.pos())
1703 && (selection.start.par() != selection.end.par()
1704 || selection.start.pos() < selection.end.pos()))
1705 selection.start.pos(selection.start.pos() + 1);
1707 CutAndPaste::copySelection(selection.start.par(), selection.end.par(),
1708 selection.start.pos(), selection.end.pos(),
1709 bview->buffer()->params.textclass);
1713 void LyXText::pasteSelection(BufferView * bview)
1715 // this does not make sense, if there is nothing to paste
1716 if (!CutAndPaste::checkPastePossible(cursor.par()))
1719 setUndo(bview->buffer(), Undo::INSERT,
1720 cursor.par()->previous(),
1721 cursor.par()->next());
1724 Paragraph * actpar = cursor.par();
1726 int pos = cursor.pos();
1727 CutAndPaste::pasteSelection(&actpar, &endpar, pos,
1728 bview->buffer()->params.textclass);
1730 redoParagraphs(bview, cursor, endpar);
1732 setCursor(bview, cursor.par(), cursor.pos());
1733 clearSelection(bview);
1735 selection.cursor = cursor;
1736 setCursor(bview, actpar, pos);
1737 setSelection(bview);
1738 updateCounters(bview, cursor.row());
1742 // returns a pointer to the very first Paragraph
1743 Paragraph * LyXText::firstParagraph() const
1745 return ownerParagraph();
1749 // sets the selection over the number of characters of string, no check!!
1750 void LyXText::setSelectionOverString(BufferView * bview, string const & str)
1755 selection.cursor = cursor;
1756 for (string::size_type i = 0; i < str.length(); ++i)
1758 setSelection(bview);
1762 // simple replacing. The font of the first selected character is used
1763 void LyXText::replaceSelectionWithString(BufferView * bview,
1766 setCursorParUndo(bview->buffer());
1769 if (!selection.set()) { // create a dummy selection
1770 selection.end = cursor;
1771 selection.start = cursor;
1774 // Get font setting before we cut
1775 Paragraph::size_type pos = selection.end.pos();
1776 LyXFont const font = selection.start.par()
1777 ->getFontSettings(bview->buffer()->params,
1778 selection.start.pos());
1780 // Insert the new string
1781 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
1782 selection.end.par()->insertChar(pos, (*cit), font);
1786 // Cut the selection
1787 cutSelection(bview);
1793 // needed to insert the selection
1794 void LyXText::insertStringAsLines(BufferView * bview, string const & str)
1796 Paragraph * par = cursor.par();
1797 Paragraph::size_type pos = cursor.pos();
1798 Paragraph * endpar = cursor.par()->next();
1800 setCursorParUndo(bview->buffer());
1802 bool isEnvironment =
1803 textclasslist.Style(bview->buffer()->params.textclass,
1804 cursor.par()->getLayout()).isEnvironment();
1806 textclasslist.Style(bview->buffer()->params.textclass,
1807 cursor.par()->getLayout()).free_spacing;
1809 textclasslist.Style(bview->buffer()->params.textclass,
1810 cursor.par()->getLayout()).keepempty;
1812 // only to be sure, should not be neccessary
1813 clearSelection(bview);
1815 // insert the string, don't insert doublespace
1816 bool space_inserted = true;
1817 for(string::const_iterator cit = str.begin();
1818 cit != str.end(); ++cit) {
1820 if (par->size() || keepempty) {
1821 par->breakParagraph(bview->buffer()->params,
1822 pos, isEnvironment);
1825 space_inserted = true;
1829 // do not insert consecutive spaces if !free_spacing
1830 } else if ((*cit == ' ' || *cit == '\t')
1831 && space_inserted && !free_spacing) {
1833 } else if (*cit == '\t') {
1834 if (!free_spacing) {
1835 // tabs are like spaces here
1836 par->insertChar(pos, ' ',
1839 space_inserted = true;
1841 const Paragraph::value_type nb = 8 - pos % 8;
1842 for (Paragraph::size_type a = 0;
1844 par->insertChar(pos, ' ',
1848 space_inserted = true;
1850 } else if (!IsPrintable(*cit)) {
1851 // Ignore unprintables
1854 // just insert the character
1855 par->insertChar(pos, *cit, current_font);
1857 space_inserted = (*cit == ' ');
1862 redoParagraphs(bview, cursor, endpar);
1863 setCursor(bview, cursor.par(), cursor.pos());
1864 selection.cursor = cursor;
1865 setCursor(bview, par, pos);
1866 setSelection(bview);
1870 /* turns double-CR to single CR, others where converted into one
1871 blank. Then InsertStringAsLines is called */
1872 void LyXText::insertStringAsParagraphs(BufferView * bview, string const & str)
1874 string linestr(str);
1875 bool newline_inserted = false;
1876 for (string::size_type i = 0; i < linestr.length(); ++i) {
1877 if (linestr[i] == '\n') {
1878 if (newline_inserted) {
1879 // we know that \r will be ignored by
1880 // InsertStringA. Of course, it is a dirty
1881 // trick, but it works...
1882 linestr[i - 1] = '\r';
1886 newline_inserted = true;
1888 } else if (IsPrintable(linestr[i])) {
1889 newline_inserted = false;
1892 insertStringAsLines(bview, linestr);
1896 bool LyXText::gotoNextInset(BufferView * bview,
1897 std::vector<Inset::Code> const & codes,
1898 string const & contents) const
1900 LyXCursor res = cursor;
1903 if (res.pos() < res.par()->size() - 1) {
1904 res.pos(res.pos() + 1);
1906 res.par(res.par()->next());
1910 } while (res.par() &&
1911 !(res.par()->getChar(res.pos()) == Paragraph::META_INSET
1912 && (inset = res.par()->getInset(res.pos())) != 0
1913 && find(codes.begin(), codes.end(), inset->lyxCode())
1915 && (contents.empty() ||
1916 static_cast<InsetCommand *>(res.par()->getInset(res.pos()))->getContents()
1920 setCursor(bview, res.par(), res.pos());
1927 void LyXText::checkParagraph(BufferView * bview, Paragraph * par,
1928 Paragraph::size_type pos)
1930 LyXCursor tmpcursor;
1933 Paragraph::size_type z;
1934 Row * row = getRow(par, pos, y);
1936 // is there a break one row above
1937 if (row->previous() && row->previous()->par() == row->par()) {
1938 z = nextBreakPoint(bview, row->previous(), workWidth(bview));
1939 if (z >= row->pos()) {
1940 // set the dimensions of the row above
1941 y -= row->previous()->height();
1943 refresh_row = row->previous();
1944 status = LyXText::NEED_MORE_REFRESH;
1946 breakAgain(bview, row->previous());
1948 // set the cursor again. Otherwise
1949 // dangling pointers are possible
1950 setCursor(bview, cursor.par(), cursor.pos(),
1951 false, cursor.boundary());
1952 selection.cursor = cursor;
1957 int const tmpheight = row->height();
1958 Paragraph::size_type const tmplast = rowLast(row);
1962 breakAgain(bview, row);
1963 if (row->height() == tmpheight && rowLast(row) == tmplast)
1964 status = LyXText::NEED_VERY_LITTLE_REFRESH;
1966 status = LyXText::NEED_MORE_REFRESH;
1968 // check the special right address boxes
1969 if (textclasslist.Style(bview->buffer()->params.textclass,
1970 par->getLayout()).margintype
1971 == MARGIN_RIGHT_ADDRESS_BOX) {
1978 redoDrawingOfParagraph(bview, tmpcursor);
1981 // set the cursor again. Otherwise dangling pointers are possible
1982 // also set the selection
1984 if (selection.set()) {
1986 setCursorIntern(bview, selection.cursor.par(), selection.cursor.pos(),
1987 false, selection.cursor.boundary());
1988 selection.cursor = cursor;
1989 setCursorIntern(bview, selection.start.par(),
1990 selection.start.pos(),
1991 false, selection.start.boundary());
1992 selection.start = cursor;
1993 setCursorIntern(bview, selection.end.par(),
1994 selection.end.pos(),
1995 false, selection.end.boundary());
1996 selection.end = cursor;
1997 setCursorIntern(bview, last_sel_cursor.par(),
1998 last_sel_cursor.pos(),
1999 false, last_sel_cursor.boundary());
2000 last_sel_cursor = cursor;
2003 setCursorIntern(bview, cursor.par(), cursor.pos(),
2004 false, cursor.boundary());
2008 // returns false if inset wasn't found
2009 bool LyXText::updateInset(BufferView * bview, Inset * inset)
2011 // first check the current paragraph
2012 int pos = cursor.par()->getPositionOfInset(inset);
2014 checkParagraph(bview, cursor.par(), pos);
2018 // check every paragraph
2020 Paragraph * par = firstParagraph();
2022 pos = par->getPositionOfInset(inset);
2024 checkParagraph(bview, par, pos);
2034 void LyXText::setCursor(BufferView * bview, Paragraph * par,
2035 Paragraph::size_type pos,
2036 bool setfont, bool boundary) const
2038 LyXCursor old_cursor = cursor;
2039 setCursorIntern(bview, par, pos, setfont, boundary);
2040 deleteEmptyParagraphMechanism(bview, old_cursor);
2044 void LyXText::setCursor(BufferView *bview, LyXCursor & cur, Paragraph * par,
2045 Paragraph::size_type pos, bool boundary) const
2049 cur.boundary(boundary);
2051 /* get the cursor y position in text */
2053 Row * row = getRow(par, pos, y);
2054 /* y is now the beginning of the cursor row */
2055 y += row->baseline();
2056 /* y is now the cursor baseline */
2059 /* now get the cursors x position */
2061 float fill_separator;
2063 float fill_label_hfill;
2064 prepareToPrint(bview, row, x, fill_separator, fill_hfill,
2066 Paragraph::size_type cursor_vpos = 0;
2067 Paragraph::size_type last = rowLastPrintable(row);
2069 if (pos > last + 1) // This shouldn't happen.
2071 else if (pos < row->pos())
2074 if (last < row->pos())
2075 cursor_vpos = row->pos();
2076 else if (pos > last && !boundary)
2077 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2078 ? row->pos() : last + 1;
2079 else if (pos > row->pos() &&
2080 (pos > last || boundary))
2081 /// Place cursor after char at (logical) position pos - 1
2082 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2083 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2085 /// Place cursor before char at (logical) position pos
2086 cursor_vpos = (bidi_level(pos) % 2 == 0)
2087 ? log2vis(pos) : log2vis(pos) + 1;
2089 Paragraph::size_type main_body =
2090 beginningOfMainBody(bview->buffer(), row->par());
2091 if ((main_body > 0) &&
2092 ((main_body-1 > last) ||
2093 !row->par()->isLineSeparator(main_body-1)))
2096 for (Paragraph::size_type vpos = row->pos();
2097 vpos < cursor_vpos; ++vpos) {
2098 pos = vis2log(vpos);
2099 if (main_body > 0 && pos == main_body - 1) {
2100 x += fill_label_hfill +
2101 lyxfont::width(textclasslist.Style(
2102 bview->buffer()->params.textclass,
2103 row->par()->getLayout())
2105 getFont(bview->buffer(), row->par(), -2));
2106 if (row->par()->isLineSeparator(main_body-1))
2107 x -= singleWidth(bview, row->par(),main_body-1);
2109 if (hfillExpansion(bview->buffer(), row, pos)) {
2110 x += singleWidth(bview, row->par(), pos);
2111 if (pos >= main_body)
2114 x += fill_label_hfill;
2115 } else if (row->par()->isSeparator(pos)) {
2116 x += singleWidth(bview, row->par(), pos);
2117 if (pos >= main_body)
2118 x += fill_separator;
2120 x += singleWidth(bview, row->par(), pos);
2129 void LyXText::setCursorIntern(BufferView * bview, Paragraph * par,
2130 Paragraph::size_type pos,
2131 bool setfont, bool boundary) const
2133 setCursor(bview, cursor, par, pos, boundary);
2135 setCurrentFont(bview);
2139 void LyXText::setCurrentFont(BufferView * bview) const
2141 Paragraph::size_type pos = cursor.pos();
2142 if (cursor.boundary() && pos > 0)
2146 if (pos == cursor.par()->size())
2148 else // potentional bug... BUG (Lgb)
2149 if (cursor.par()->isSeparator(pos)) {
2150 if (pos > cursor.row()->pos() &&
2151 bidi_level(pos) % 2 ==
2152 bidi_level(pos - 1) % 2)
2154 else if (pos + 1 < cursor.par()->size())
2160 cursor.par()->getFontSettings(bview->buffer()->params, pos);
2161 real_current_font = getFont(bview->buffer(), cursor.par(), pos);
2163 if (cursor.pos() == cursor.par()->size() &&
2164 isBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2165 !cursor.boundary()) {
2166 Language const * lang =
2167 cursor.par()->getParLanguage(bview->buffer()->params);
2168 current_font.setLanguage(lang);
2169 current_font.setNumber(LyXFont::OFF);
2170 real_current_font.setLanguage(lang);
2171 real_current_font.setNumber(LyXFont::OFF);
2176 void LyXText::setCursorFromCoordinates(BufferView * bview, int x, int y) const
2178 LyXCursor old_cursor = cursor;
2180 /* get the row first */
2182 Row * row = getRowNearY(y);
2183 cursor.par(row->par());
2186 int column = getColumnNearX(bview, row, x, bound);
2187 cursor.pos(row->pos() + column);
2189 cursor.y(y + row->baseline());
2191 cursor.boundary(bound);
2192 setCurrentFont(bview);
2193 deleteEmptyParagraphMechanism(bview, old_cursor);
2197 void LyXText::setCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2200 /* get the row first */
2202 Row * row = getRowNearY(y);
2204 int column = getColumnNearX(bview, row, x, bound);
2206 cur.par(row->par());
2207 cur.pos(row->pos() + column);
2209 cur.y(y + row->baseline());
2211 cur.boundary(bound);
2215 void LyXText::cursorLeft(BufferView * bview, bool internal) const
2217 if (cursor.pos() > 0) {
2218 bool boundary = cursor.boundary();
2219 setCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2220 if (!internal && !boundary &&
2221 isBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2222 setCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2223 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2224 Paragraph * par = cursor.par()->previous();
2225 setCursor(bview, par, par->size());
2230 void LyXText::cursorRight(BufferView * bview, bool internal) const
2232 if (!internal && cursor.boundary() &&
2233 !cursor.par()->isNewline(cursor.pos()))
2234 setCursor(bview, cursor.par(), cursor.pos(), true, false);
2235 else if (cursor.pos() < cursor.par()->size()) {
2236 setCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2238 isBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2239 setCursor(bview, cursor.par(), cursor.pos(), true, true);
2240 } else if (cursor.par()->next())
2241 setCursor(bview, cursor.par()->next(), 0);
2245 void LyXText::cursorUp(BufferView * bview) const
2247 setCursorFromCoordinates(bview, cursor.x_fix(),
2248 cursor.y() - cursor.row()->baseline() - 1);
2252 void LyXText::cursorDown(BufferView * bview) const
2254 setCursorFromCoordinates(bview, cursor.x_fix(),
2255 cursor.y() - cursor.row()->baseline()
2256 + cursor.row()->height() + 1);
2260 void LyXText::cursorUpParagraph(BufferView * bview) const
2262 if (cursor.pos() > 0) {
2263 setCursor(bview, cursor.par(), 0);
2265 else if (cursor.par()->previous()) {
2266 setCursor(bview, cursor.par()->previous(), 0);
2271 void LyXText::cursorDownParagraph(BufferView * bview) const
2273 if (cursor.par()->next()) {
2274 setCursor(bview, cursor.par()->next(), 0);
2276 setCursor(bview, cursor.par(), cursor.par()->size());
2281 void LyXText::deleteEmptyParagraphMechanism(BufferView * bview,
2282 LyXCursor const & old_cursor) const
2284 // Would be wrong to delete anything if we have a selection.
2285 if (selection.set()) return;
2287 // We allow all kinds of "mumbo-jumbo" when freespacing.
2288 if (textclasslist.Style(bview->buffer()->params.textclass,
2289 old_cursor.par()->getLayout()).free_spacing)
2292 bool deleted = false;
2294 /* Ok I'll put some comments here about what is missing.
2295 I have fixed BackSpace (and thus Delete) to not delete
2296 double-spaces automagically. I have also changed Cut,
2297 Copy and Paste to hopefully do some sensible things.
2298 There are still some small problems that can lead to
2299 double spaces stored in the document file or space at
2300 the beginning of paragraphs. This happens if you have
2301 the cursor betwenn to spaces and then save. Or if you
2302 cut and paste and the selection have a space at the
2303 beginning and then save right after the paste. I am
2304 sure none of these are very hard to fix, but I will
2305 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2306 that I can get some feedback. (Lgb)
2309 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2310 // delete the LineSeparator.
2313 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2314 // delete the LineSeparator.
2317 // If the pos around the old_cursor were spaces, delete one of them.
2318 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
2319 // Only if the cursor has really moved
2321 if (old_cursor.pos() > 0
2322 && old_cursor.pos() < old_cursor.par()->size()
2323 && old_cursor.par()->isLineSeparator(old_cursor.pos())
2324 && old_cursor.par()->isLineSeparator(old_cursor.pos() - 1)) {
2325 old_cursor.par()->erase(old_cursor.pos() - 1);
2326 redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2328 if (old_cursor.par() == cursor.par() &&
2329 cursor.pos() > old_cursor.pos()) {
2330 setCursorIntern(bview, cursor.par(),
2333 setCursorIntern(bview, cursor.par(),
2339 // Do not delete empty paragraphs with keepempty set.
2340 if ((textclasslist.Style(bview->buffer()->params.textclass,
2341 old_cursor.par()->getLayout())).keepempty)
2344 LyXCursor tmpcursor;
2346 if (old_cursor.par() != cursor.par()) {
2347 if ((old_cursor.par()->size() == 0
2348 || (old_cursor.par()->size() == 1
2349 && old_cursor.par()->isLineSeparator(0)))) {
2350 // ok, we will delete anything
2352 // make sure that you do not delete any environments
2353 status = LyXText::NEED_MORE_REFRESH;
2356 if (old_cursor.row()->previous()) {
2357 refresh_row = old_cursor.row()->previous();
2358 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2360 cursor = old_cursor; // that undo can restore the right cursor position
2361 Paragraph * endpar = old_cursor.par()->next();
2362 if (endpar && endpar->getDepth()) {
2363 while (endpar && endpar->getDepth()) {
2364 endpar = endpar->next();
2367 setUndo(bview->buffer(), Undo::DELETE,
2368 old_cursor.par()->previous(),
2373 removeRow(old_cursor.row());
2374 if (ownerParagraph() == old_cursor.par()) {
2375 ownerParagraph(ownerParagraph()->next());
2378 delete old_cursor.par();
2380 /* Breakagain the next par. Needed
2381 * because of the parindent that
2382 * can occur or dissappear. The
2383 * next row can change its height,
2384 * if there is another layout before */
2385 if (refresh_row->next()) {
2386 breakAgain(bview, refresh_row->next());
2387 updateCounters(bview, refresh_row);
2389 setHeightOfRow(bview, refresh_row);
2391 refresh_row = old_cursor.row()->next();
2392 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2395 cursor = old_cursor; // that undo can restore the right cursor position
2396 Paragraph * endpar = old_cursor.par()->next();
2397 if (endpar && endpar->getDepth()) {
2398 while (endpar && endpar->getDepth()) {
2399 endpar = endpar->next();
2402 setUndo(bview->buffer(), Undo::DELETE,
2403 old_cursor.par()->previous(),
2408 removeRow(old_cursor.row());
2410 if (ownerParagraph() == old_cursor.par()) {
2411 ownerParagraph(ownerParagraph()->next());
2414 delete old_cursor.par();
2416 /* Breakagain the next par. Needed
2417 because of the parindent that can
2418 occur or dissappear.
2419 The next row can change its height,
2420 if there is another layout before
2423 breakAgain(bview, refresh_row);
2424 updateCounters(bview, refresh_row->previous());
2430 setCursorIntern(bview, cursor.par(), cursor.pos());
2432 if (selection.cursor.par() == old_cursor.par()
2433 && selection.cursor.pos() == selection.cursor.pos()) {
2434 // correct selection
2435 selection.cursor = cursor;
2439 if (old_cursor.par()->stripLeadingSpaces(bview->buffer()->params.textclass)) {
2440 redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2442 setCursorIntern(bview, cursor.par(), cursor.pos());
2443 selection.cursor = cursor;
2450 Paragraph * LyXText::getParFromID(int id)
2452 Paragraph * result = firstParagraph();
2453 while (result && result->id() != id)
2454 result = result->next();
2460 bool LyXText::textUndo(BufferView * bview)
2464 // returns false if no undo possible
2465 Undo * undo = bview->buffer()->undostack.pop();
2469 bview->buffer()->redostack
2470 .push(createUndo(bview->buffer(), undo->kind,
2471 getParFromID(undo->number_of_before_par),
2472 getParFromID(undo->number_of_behind_par)));
2474 return textHandleUndo(bview, undo);
2478 bool LyXText::textRedo(BufferView * bview)
2482 // returns false if no redo possible
2483 Undo * undo = bview->buffer()->redostack.pop();
2487 bview->buffer()->undostack
2488 .push(createUndo(bview->buffer(), undo->kind,
2489 getParFromID(undo->number_of_before_par),
2490 getParFromID(undo->number_of_behind_par)));
2492 return textHandleUndo(bview, undo);
2496 bool LyXText::textHandleUndo(BufferView * bview, Undo * undo)
2500 // returns false if no undo possible
2501 bool result = false;
2503 Paragraph * before =
2504 getParFromID(undo->number_of_before_par);
2505 Paragraph * behind =
2506 getParFromID(undo->number_of_behind_par);
2508 Paragraph * tmppar2;
2510 Paragraph * tmppar5;
2512 // if there's no before take the beginning
2513 // of the document for redoing
2515 setCursorIntern(bview, firstParagraph(), 0);
2517 // replace the paragraphs with the undo informations
2519 Paragraph * tmppar3 = undo->par;
2520 undo->par = 0; // otherwise the undo destructor would delete the paragraph
2521 Paragraph * tmppar4 = tmppar3;
2524 while (tmppar4->next())
2525 tmppar4 = tmppar4->next();
2526 } // get last undo par
2528 // now remove the old text if there is any
2529 if (before != behind || (!behind && !before)) {
2531 tmppar5 = before->next();
2533 tmppar5 = ownerParagraph();
2535 while (tmppar5 && tmppar5 != behind) {
2537 tmppar5 = tmppar5->next();
2538 // a memory optimization for edit: Only layout information
2539 // is stored in the undo. So restore the text informations.
2540 if (undo->kind == Undo::EDIT) {
2541 tmppar2->setContentsFromPar(tmppar);
2542 tmppar->clearContents();
2543 tmppar2 = tmppar2->next();
2548 // put the new stuff in the list if there is one
2551 before->next(tmppar3);
2553 ownerParagraph(tmppar3);
2554 tmppar3->previous(before);
2557 ownerParagraph(behind);
2560 tmppar4->next(behind);
2562 behind->previous(tmppar4);
2566 // Set the cursor for redoing
2568 setCursorIntern(bview, before, 0);
2571 // calculate the endpar for redoing the paragraphs.
2573 endpar = behind->next();
2577 tmppar = getParFromID(undo->number_of_cursor_par);
2578 redoParagraphs(bview, cursor, endpar);
2580 setCursorIntern(bview, tmppar, undo->cursor_pos);
2581 updateCounters(bview, cursor.row());
2591 void LyXText::finishUndo()
2595 // makes sure the next operation will be stored
2596 undo_finished = true;
2600 void LyXText::freezeUndo()
2604 // this is dangerous and for internal use only
2609 void LyXText::unFreezeUndo()
2613 // this is dangerous and for internal use only
2614 undo_frozen = false;
2618 void LyXText::setUndo(Buffer * buf, Undo::undo_kind kind,
2619 Paragraph const * before,
2620 Paragraph const * behind) const
2625 buf->undostack.push(createUndo(buf, kind, before, behind));
2626 buf->redostack.clear();
2630 void LyXText::setRedo(Buffer * buf, Undo::undo_kind kind,
2631 Paragraph const * before, Paragraph const * behind)
2635 buf->redostack.push(createUndo(buf, kind, before, behind));
2639 Undo * LyXText::createUndo(Buffer * buf, Undo::undo_kind kind,
2640 Paragraph const * before,
2641 Paragraph const * behind) const
2646 int before_number = -1;
2647 int behind_number = -1;
2649 before_number = before->id();
2651 behind_number = behind->id();
2652 // Undo::EDIT and Undo::FINISH are
2653 // always finished. (no overlapping there)
2654 // overlapping only with insert and delete inside one paragraph:
2655 // Nobody wants all removed character
2656 // appear one by one when undoing.
2657 // EDIT is special since only layout information, not the
2658 // contents of a paragaph are stored.
2659 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
2660 // check wether storing is needed
2661 if (!buf->undostack.empty() &&
2662 buf->undostack.top()->kind == kind &&
2663 buf->undostack.top()->number_of_before_par == before_number &&
2664 buf->undostack.top()->number_of_behind_par == behind_number ){
2669 // create a new Undo
2670 Paragraph * undopar;
2672 Paragraph * start = 0;
2673 Paragraph * end = 0;
2676 start = const_cast<Paragraph*>(before->next());
2678 start = firstParagraph();
2680 end = const_cast<Paragraph*>(behind->previous());
2682 end = firstParagraph();
2686 if (start && end && (start != end->next()) &&
2687 ((before != behind) || (!before && !behind))) {
2688 Paragraph * tmppar = start;
2689 Paragraph * tmppar2 = new Paragraph(*tmppar);
2690 tmppar2->id(tmppar->id());
2692 // a memory optimization: Just store the layout information
2694 if (kind == Undo::EDIT){
2695 //tmppar2->text.clear();
2696 tmppar2->clearContents();
2701 while (tmppar != end && tmppar->next()) {
2702 tmppar = tmppar->next();
2703 tmppar2->next(new Paragraph(*tmppar));
2704 tmppar2->next()->id(tmppar->id());
2705 // a memory optimization: Just store the layout
2706 // information when only edit
2707 if (kind == Undo::EDIT){
2708 //tmppar2->next->text.clear();
2709 tmppar2->clearContents();
2711 tmppar2->next()->previous(tmppar2);
2712 tmppar2 = tmppar2->next();
2716 undopar = 0; // nothing to replace (undo of delete maybe)
2718 int cursor_par = cursor.par()->id();
2719 int cursor_pos = cursor.pos();
2721 Undo * undo = new Undo(kind,
2722 before_number, behind_number,
2723 cursor_par, cursor_pos,
2726 undo_finished = false;
2731 void LyXText::setCursorParUndo(Buffer * buf)
2735 setUndo(buf, Undo::FINISH,
2736 cursor.par()->previous(),
2737 cursor.par()->next());
2741 void LyXText::toggleAppendix(BufferView * bview)
2743 Paragraph * par = cursor.par();
2744 bool start = !par->params().startOfAppendix();
2746 // ensure that we have only one start_of_appendix in this document
2747 Paragraph * tmp = firstParagraph();
2748 for (; tmp; tmp = tmp->next())
2749 tmp->params().startOfAppendix(false);
2751 par->params().startOfAppendix(start);
2753 // we can set the refreshing parameters now
2754 status = LyXText::NEED_MORE_REFRESH;
2756 refresh_row = 0; // not needed for full update
2757 updateCounters(bview, 0);
2758 setCursor(bview, cursor.par(), cursor.pos());
2762 Paragraph * LyXText::ownerParagraph() const
2765 return inset_owner->par;
2767 return bv_owner->buffer()->paragraph;
2771 Paragraph * LyXText::ownerParagraph(Paragraph * p) const
2774 inset_owner->par = p;
2776 bv_owner->buffer()->paragraph = p;