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)
59 LyXText::LyXText(InsetText * inset)
69 the_locking_inset = 0;
77 status = LyXText::UNCHANGED;
79 // set cursor at the very top position
80 selection.set(true); /* these setting is necessary
81 because of the delete-empty-
82 paragraph mechanism in
85 Paragraph * par = ownerParagraph();
86 current_font = getFont(bv_owner->buffer(), par, 0);
88 insertParagraph(bv_owner, par, lastrow);
91 setCursor(bv_owner, firstrow->par(), 0);
93 current_font = LyXFont(LyXFont::ALL_SANE);
95 selection.cursor = cursor;
97 selection.mark(false);
99 // no rebreak necessary
102 undo_finished = true;
105 // Default layouttype for copy environment type
109 // Dump all rowinformation:
110 Row * tmprow = firstrow;
111 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
113 lyxerr << tmprow->baseline() << '\t'
114 << tmprow->par << '\t'
115 << tmprow->pos() << '\t'
116 << tmprow->height << '\t'
117 << tmprow->ascent_of_text << '\t'
118 << tmprow->fill << '\n';
119 tmprow = tmprow->next();
126 void LyXText::init(BufferView * bview)
131 Paragraph * par = ownerParagraph();
132 current_font = getFont(bview->buffer(), par, 0);
134 insertParagraph(bview, par, lastrow);
137 setCursorIntern(bview, firstrow->par(), 0);
138 selection.cursor = cursor;
140 printf("TP = %x\n",inset_owner->owner());
141 // Dump all rowinformation:
142 Row * tmprow = firstrow;
143 lyxerr << "Width = " << width << endl;
144 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
146 lyxerr << tmprow->baseline() << '\t'
147 << tmprow->par() << '\t'
148 << tmprow->pos() << '\t'
149 << tmprow->height() << '\t'
150 << tmprow->ascent_of_text() << '\t'
151 << tmprow->fill() << '\n';
152 tmprow = tmprow->next();
160 // Delete all rows, this does not touch the paragraphs!
161 Row * tmprow = firstrow;
163 tmprow = firstrow->next();
170 // Gets the fully instantiated font at a given position in a paragraph
171 // Basically the same routine as Paragraph::getFont() in paragraph.C.
172 // The difference is that this one is used for displaying, and thus we
173 // are allowed to make cosmetic improvements. For instance make footnotes
175 // If position is -1, we get the layout font of the paragraph.
176 // If position is -2, we get the font of the manual label of the paragraph.
177 LyXFont const LyXText::getFont(Buffer const * buf, Paragraph * par,
178 Paragraph::size_type pos) const
180 LyXLayout const & layout =
181 textclasslist.Style(buf->params.textclass, par->getLayout());
183 Paragraph::depth_type par_depth = par->getDepth();
184 // We specialize the 95% common case:
188 if (layout.labeltype == LABEL_MANUAL
189 && pos < beginningOfMainBody(buf, par)) {
191 LyXFont f = par->getFontSettings(buf->params,
193 return f.realize(layout.reslabelfont);
195 LyXFont f = par->getFontSettings(buf->params, pos);
196 return f.realize(layout.resfont);
201 // process layoutfont for pos == -1 and labelfont for pos < -1
203 return layout.resfont;
205 return layout.reslabelfont;
209 // The uncommon case need not be optimized as much
211 LyXFont layoutfont, tmpfont;
215 if (pos < beginningOfMainBody(buf, par)) {
217 layoutfont = layout.labelfont;
220 layoutfont = layout.font;
222 tmpfont = par->getFontSettings(buf->params, pos);
223 tmpfont.realize(layoutfont);
226 // process layoutfont for pos == -1 and labelfont for pos < -1
228 tmpfont = layout.font;
230 tmpfont = layout.labelfont;
233 // Resolve against environment font information
234 while (par && par_depth && !tmpfont.resolved()) {
235 par = par->outerHook();
237 tmpfont.realize(textclasslist.
238 Style(buf->params.textclass,
239 par->getLayout()).font);
240 par_depth = par->getDepth();
244 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
250 void LyXText::setCharFont(BufferView * bv, Paragraph * par,
251 Paragraph::size_type pos, LyXFont const & fnt,
254 Buffer const * buf = bv->buffer();
255 LyXFont font = getFont(buf, par, pos);
256 font.update(fnt, buf->params.language, toggleall);
257 // Let the insets convert their font
258 if (par->getChar(pos) == Paragraph::META_INSET) {
259 Inset * inset = par->getInset(pos);
261 if (inset->editable()==Inset::HIGHLY_EDITABLE) {
262 UpdatableInset * uinset = static_cast<UpdatableInset *>(inset);
263 uinset->setFont(bv, fnt, toggleall, true);
265 font = inset->convertFont(font);
269 LyXLayout const & layout =
270 textclasslist.Style(buf->params.textclass,
273 // Get concrete layout font to reduce against
276 if (pos < beginningOfMainBody(buf, par))
277 layoutfont = layout.labelfont;
279 layoutfont = layout.font;
281 // Realize against environment font information
282 if (par->getDepth()){
283 Paragraph * tp = par;
284 while (!layoutfont.resolved() && tp && tp->getDepth()) {
285 tp = tp->outerHook();
287 layoutfont.realize(textclasslist.
288 Style(buf->params.textclass,
289 tp->getLayout()).font);
293 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
295 // Now, reduce font against full layout font
296 font.reduce(layoutfont);
298 par->setFont(pos, font);
301 void LyXText::setCharFont(Buffer const * buf, Paragraph * par,
302 Paragraph::size_type pos, LyXFont const & fnt)
305 // Let the insets convert their font
306 if (par->getChar(pos) == Paragraph::META_INSET) {
307 font = par->getInset(pos)->convertFont(font);
310 LyXLayout const & layout =
311 textclasslist.Style(buf->params.textclass,
314 // Get concrete layout font to reduce against
317 if (pos < beginningOfMainBody(buf, par))
318 layoutfont = layout.labelfont;
320 layoutfont = layout.font;
322 // Realize against environment font information
323 if (par->getDepth()){
324 Paragraph * tp = par;
325 while (!layoutfont.resolved() && tp && tp->getDepth()) {
326 tp = tp->outerHook();
328 layoutfont.realize(textclasslist.
329 Style(buf->params.textclass,
330 tp->getLayout()).font);
334 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
336 // Now, reduce font against full layout font
337 font.reduce(layoutfont);
339 par->setFont(pos, font);
343 /* inserts a new row behind the specified row, increments
344 * the touched counters */
345 void LyXText::insertRow(Row * row, Paragraph * par,
346 Paragraph::size_type pos) const
348 Row * tmprow = new Row;
351 tmprow->next(firstrow);
354 tmprow->previous(row);
355 tmprow->next(row->next());
360 tmprow->next()->previous(tmprow);
362 if (tmprow->previous())
363 tmprow->previous()->next(tmprow);
371 ++number_of_rows; // one more row
375 // removes the row and reset the touched counters
376 void LyXText::removeRow(Row * row) const
378 /* this must not happen before the currentrow for clear reasons.
379 so the trick is just to set the current row onto the previous
382 getRow(row->par(), row->pos(), unused_y);
385 row->next()->previous(row->previous());
386 if (!row->previous()) {
387 firstrow = row->next();
389 row->previous()->next(row->next());
392 lastrow = row->previous();
394 height -= row->height(); // the text becomes smaller
397 --number_of_rows; // one row less
401 // remove all following rows of the paragraph of the specified row.
402 void LyXText::removeParagraph(Row * row) const
404 Paragraph * tmppar = row->par();
408 while (row && row->par() == tmppar) {
409 tmprow = row->next();
416 // insert the specified paragraph behind the specified row
417 void LyXText::insertParagraph(BufferView * bview, Paragraph * par,
420 insertRow(row, par, 0); /* insert a new row, starting
423 setCounter(bview->buffer(), par); // set the counters
425 // and now append the whole paragraph behind the new row
428 appendParagraph(bview, firstrow);
430 row->next()->height(0);
431 appendParagraph(bview, row->next());
436 /* used in setlayout */
437 // Asger is not sure we want to do this...
438 void LyXText::makeFontEntriesLayoutSpecific(Buffer const * buf,
442 LyXLayout const & layout =
443 textclasslist.Style(buf->params.textclass, par->getLayout());
445 LyXFont layoutfont, tmpfont;
446 for (Paragraph::size_type pos = 0;
447 pos < par->size(); ++pos) {
448 if (pos < beginningOfMainBody(buf, par))
449 layoutfont = layout.labelfont;
451 layoutfont = layout.font;
453 tmpfont = par->getFontSettings(buf->params, pos);
454 tmpfont.reduce(layoutfont);
455 par->setFont(pos, tmpfont);
460 Paragraph * LyXText::setLayout(BufferView * bview,
461 LyXCursor & cur, LyXCursor & sstart_cur,
462 LyXCursor & send_cur,
463 LyXTextClass::size_type layout)
465 Paragraph * endpar = send_cur.par()->next();
466 Paragraph * undoendpar = endpar;
468 if (endpar && endpar->getDepth()) {
469 while (endpar && endpar->getDepth()) {
470 endpar = endpar->next();
474 endpar = endpar->next(); // because of parindents etc.
477 setUndo(bview->buffer(), Undo::EDIT,
478 sstart_cur.par()->previous(),
481 /* ok we have a selection. This is always between sstart_cur
482 * and sel_end cursor */
485 LyXLayout const & lyxlayout =
486 textclasslist.Style(bview->buffer()->params.textclass, layout);
488 while (cur.par() != send_cur.par()) {
489 cur.par()->setLayout(layout);
490 makeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
491 Paragraph * fppar = cur.par();
492 fppar->params().spaceTop(lyxlayout.fill_top ?
493 VSpace(VSpace::VFILL)
494 : VSpace(VSpace::NONE));
495 fppar->params().spaceBottom(lyxlayout.fill_bottom ?
496 VSpace(VSpace::VFILL)
497 : VSpace(VSpace::NONE));
498 if (lyxlayout.margintype == MARGIN_MANUAL)
499 cur.par()->setLabelWidthString(lyxlayout.labelstring());
500 if (lyxlayout.labeltype != LABEL_BIBLIO
502 delete fppar->bibkey;
505 cur.par(cur.par()->next());
507 cur.par()->setLayout(layout);
508 makeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
509 Paragraph * fppar = cur.par();
510 fppar->params().spaceTop(lyxlayout.fill_top ?
511 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
512 fppar->params().spaceBottom(lyxlayout.fill_bottom ?
513 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
514 if (lyxlayout.margintype == MARGIN_MANUAL)
515 cur.par()->setLabelWidthString(lyxlayout.labelstring());
516 if (lyxlayout.labeltype != LABEL_BIBLIO
518 delete fppar->bibkey;
525 // set layout over selection and make a total rebreak of those paragraphs
526 void LyXText::setLayout(BufferView * bview, LyXTextClass::size_type layout)
528 LyXCursor tmpcursor = cursor; /* store the current cursor */
530 // if there is no selection just set the layout
531 // of the current paragraph */
532 if (!selection.set()) {
533 selection.start = cursor; // dummy selection
534 selection.end = cursor;
536 Paragraph * endpar = setLayout(bview, cursor, selection.start,
537 selection.end, layout);
538 redoParagraphs(bview, selection.start, endpar);
540 // we have to reset the selection, because the
541 // geometry could have changed
542 setCursor(bview, selection.start.par(),
543 selection.start.pos(), false);
544 selection.cursor = cursor;
545 setCursor(bview, selection.end.par(), selection.end.pos(),
547 updateCounters(bview, cursor.row());
548 clearSelection(bview);
550 setCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
554 // increment depth over selection and
555 // make a total rebreak of those paragraphs
556 void LyXText::incDepth(BufferView * bview)
558 // If there is no selection, just use the current paragraph
559 if (!selection.set()) {
560 selection.start = cursor; // dummy selection
561 selection.end = cursor;
564 // We end at the next paragraph with depth 0
565 Paragraph * endpar = selection.end.par()->next();
567 Paragraph * undoendpar = endpar;
569 if (endpar && endpar->getDepth()) {
570 while (endpar && endpar->getDepth()) {
571 endpar = endpar->next();
576 endpar = endpar->next(); // because of parindents etc.
579 setUndo(bview->buffer(), Undo::EDIT,
580 selection.start.par()->previous(),
583 LyXCursor tmpcursor = cursor; // store the current cursor
585 // ok we have a selection. This is always between sel_start_cursor
586 // and sel_end cursor
587 cursor = selection.start;
589 bool anything_changed = false;
592 // NOTE: you can't change the depth of a bibliography entry
594 textclasslist.Style(bview->buffer()->params.textclass,
595 cursor.par()->getLayout()
596 ).labeltype != LABEL_BIBLIO) {
597 Paragraph * prev = cursor.par()->previous();
600 && (prev->getDepth() - cursor.par()->getDepth() > 0
601 || (prev->getDepth() == cursor.par()->getDepth()
602 && textclasslist.Style(bview->buffer()->params.textclass,
603 prev->getLayout()).isEnvironment()))) {
604 cursor.par()->params().depth(cursor.par()->params().depth() + 1);
605 anything_changed = true;
608 if (cursor.par() == selection.end.par())
610 cursor.par(cursor.par()->next());
613 // if nothing changed set all depth to 0
614 if (!anything_changed) {
615 cursor = selection.start;
616 while (cursor.par() != selection.end.par()) {
617 cursor.par()->params().depth(0);
618 cursor.par(cursor.par()->next());
620 cursor.par()->params().depth(0);
623 redoParagraphs(bview, selection.start, endpar);
625 // we have to reset the selection, because the
626 // geometry could have changed
627 setCursor(bview, selection.start.par(), selection.start.pos());
628 selection.cursor = cursor;
629 setCursor(bview, selection.end.par(), selection.end.pos());
630 updateCounters(bview, cursor.row());
631 clearSelection(bview);
633 setCursor(bview, tmpcursor.par(), tmpcursor.pos());
637 // decrement depth over selection and
638 // make a total rebreak of those paragraphs
639 void LyXText::decDepth(BufferView * bview)
641 // if there is no selection just set the layout
642 // of the current paragraph
643 if (!selection.set()) {
644 selection.start = cursor; // dummy selection
645 selection.end = cursor;
647 Paragraph * endpar = selection.end.par()->next();
648 Paragraph * undoendpar = endpar;
650 if (endpar && endpar->getDepth()) {
651 while (endpar && endpar->getDepth()) {
652 endpar = endpar->next();
656 endpar = endpar->next(); // because of parindents etc.
659 setUndo(bview->buffer(), Undo::EDIT,
660 selection.start.par()->previous(),
663 LyXCursor tmpcursor = cursor; // store the current cursor
665 // ok we have a selection. This is always between sel_start_cursor
666 // and sel_end cursor
667 cursor = selection.start;
670 if (cursor.par()->params().depth())
671 cursor.par()->params().depth(cursor.par()->params().depth() - 1);
672 if (cursor.par() == selection.end.par())
674 cursor.par(cursor.par()->next());
677 redoParagraphs(bview, selection.start, endpar);
679 // we have to reset the selection, because the
680 // geometry could have changed
681 setCursor(bview, selection.start.par(),
682 selection.start.pos());
683 selection.cursor = cursor;
684 setCursor(bview, selection.end.par(), selection.end.pos());
685 updateCounters(bview, cursor.row());
686 clearSelection(bview);
688 setCursor(bview, tmpcursor.par(), tmpcursor.pos());
692 // set font over selection and make a total rebreak of those paragraphs
693 void LyXText::setFont(BufferView * bview, LyXFont const & font, bool toggleall)
695 // if there is no selection just set the current_font
696 if (!selection.set()) {
697 // Determine basis font
699 if (cursor.pos() < beginningOfMainBody(bview->buffer(),
701 layoutfont = getFont(bview->buffer(), cursor.par(),-2);
703 layoutfont = getFont(bview->buffer(), cursor.par(),-1);
704 // Update current font
705 real_current_font.update(font,
706 bview->buffer()->params.language,
709 // Reduce to implicit settings
710 current_font = real_current_font;
711 current_font.reduce(layoutfont);
712 // And resolve it completely
713 real_current_font.realize(layoutfont);
717 LyXCursor tmpcursor = cursor; // store the current cursor
719 // ok we have a selection. This is always between sel_start_cursor
720 // and sel_end cursor
722 setUndo(bview->buffer(), Undo::EDIT,
723 selection.start.par()->previous(),
724 selection.end.par()->next());
726 cursor = selection.start;
727 while (cursor.par() != selection.end.par() ||
728 (cursor.pos() < selection.end.pos())) {
729 if (cursor.pos() < cursor.par()->size()) {
730 // an open footnote should behave
732 setCharFont(bview, cursor.par(), cursor.pos(), font, toggleall);
733 cursor.pos(cursor.pos() + 1);
736 cursor.par(cursor.par()->next());
741 redoParagraphs(bview, selection.start, selection.end.par()->next());
743 // we have to reset the selection, because the
744 // geometry could have changed
745 setCursor(bview, selection.start.par(), selection.start.pos());
746 selection.cursor = cursor;
747 setCursor(bview, selection.end.par(), selection.end.pos());
748 clearSelection(bview);
750 setCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
751 tmpcursor.boundary());
755 void LyXText::redoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
757 Row * tmprow = cur.row();
758 int y = cur.y() - tmprow->baseline();
760 setHeightOfRow(bview, tmprow);
761 Paragraph * first_phys_par = tmprow->par();
763 // find the first row of the paragraph
764 if (first_phys_par != tmprow->par())
765 while (tmprow->previous()
766 && tmprow->previous()->par() != first_phys_par) {
767 tmprow = tmprow->previous();
768 y -= tmprow->height();
769 setHeightOfRow(bview, tmprow);
771 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
772 tmprow = tmprow->previous();
773 y -= tmprow->height();
774 setHeightOfRow(bview, tmprow);
777 // we can set the refreshing parameters now
778 status = LyXText::NEED_MORE_REFRESH;
780 refresh_row = tmprow;
781 setCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
785 void LyXText::redoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
787 Row * tmprow = cur.row();
789 int y = cur.y() - tmprow->baseline();
790 setHeightOfRow(bview, tmprow);
791 Paragraph * first_phys_par = tmprow->par();
793 // find the first row of the paragraph
794 if (first_phys_par != tmprow->par())
795 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
796 tmprow = tmprow->previous();
797 y -= tmprow->height();
799 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
800 tmprow = tmprow->previous();
801 y -= tmprow->height();
804 // we can set the refreshing parameters now
805 if (status == LyXText::UNCHANGED || y < refresh_y) {
807 refresh_row = tmprow;
809 status = LyXText::NEED_MORE_REFRESH;
810 setCursor(bview, cur.par(), cur.pos());
814 /* deletes and inserts again all paragaphs between the cursor
815 * and the specified par
816 * This function is needed after SetLayout and SetFont etc. */
817 void LyXText::redoParagraphs(BufferView * bview, LyXCursor const & cur,
818 Paragraph const * endpar) const
821 Paragraph * tmppar = 0, * first_phys_par = 0;
823 Row * tmprow = cur.row();
825 int y = cur.y() - tmprow->baseline();
827 if (!tmprow->previous()){
828 first_phys_par = firstParagraph(); // a trick/hack for UNDO
830 first_phys_par = tmprow->par();
831 // find the first row of the paragraph
832 if (first_phys_par != tmprow->par())
833 while (tmprow->previous() &&
834 (tmprow->previous()->par() != first_phys_par)) {
835 tmprow = tmprow->previous();
836 y -= tmprow->height();
838 while (tmprow->previous()
839 && tmprow->previous()->par() == first_phys_par) {
840 tmprow = tmprow->previous();
841 y -= tmprow->height();
845 // we can set the refreshing parameters now
846 status = LyXText::NEED_MORE_REFRESH;
848 refresh_row = tmprow->previous(); /* the real refresh row will
849 be deleted, so I store
853 tmppar = tmprow->next()->par();
856 while (tmppar != endpar) {
857 removeRow(tmprow->next());
859 tmppar = tmprow->next()->par();
864 // remove the first one
865 tmprow2 = tmprow; /* this is because tmprow->previous()
867 tmprow = tmprow->previous();
870 tmppar = first_phys_par;
874 insertParagraph(bview, tmppar, tmprow);
877 while (tmprow->next() && tmprow->next()->par() == tmppar)
878 tmprow = tmprow->next();
879 tmppar = tmppar->next();
881 } while (tmppar != endpar);
883 // this is because of layout changes
885 refresh_y -= refresh_row->height();
886 setHeightOfRow(bview, refresh_row);
888 refresh_row = firstrow;
890 setHeightOfRow(bview, refresh_row);
893 if (tmprow && tmprow->next())
894 setHeightOfRow(bview, tmprow->next());
898 bool LyXText::fullRebreak(BufferView * bview)
904 if (need_break_row) {
905 breakAgain(bview, need_break_row);
913 /* important for the screen */
916 /* the cursor set functions have a special mechanism. When they
917 * realize, that you left an empty paragraph, they will delete it.
918 * They also delete the corresponding row */
920 // need the selection cursor:
921 void LyXText::setSelection(BufferView * bview)
923 bool const lsel = selection.set();
925 if (!selection.set()) {
926 last_sel_cursor = selection.cursor;
927 selection.start = selection.cursor;
928 selection.end = selection.cursor;
933 // first the toggling area
934 if (cursor.y() < last_sel_cursor.y()
935 || (cursor.y() == last_sel_cursor.y()
936 && cursor.x() < last_sel_cursor.x())) {
937 toggle_end_cursor = last_sel_cursor;
938 toggle_cursor = cursor;
940 toggle_end_cursor = cursor;
941 toggle_cursor = last_sel_cursor;
944 last_sel_cursor = cursor;
946 // and now the whole selection
948 if (selection.cursor.par() == cursor.par())
949 if (selection.cursor.pos() < cursor.pos()) {
950 selection.end = cursor;
951 selection.start = selection.cursor;
953 selection.end = selection.cursor;
954 selection.start = cursor;
956 else if (selection.cursor.y() < cursor.y() ||
957 (selection.cursor.y() == cursor.y() && selection.cursor.x() < cursor.x())) {
958 selection.end = cursor;
959 selection.start = selection.cursor;
962 selection.end = selection.cursor;
963 selection.start = cursor;
966 // a selection with no contents is not a selection
967 if (selection.start.par() == selection.end.par() &&
968 selection.start.pos() == selection.end.pos())
969 selection.set(false);
971 if (inset_owner && (selection.set() || lsel))
972 inset_owner->setUpdateStatus(bview, InsetText::SELECTION);
976 string const LyXText::selectionAsString(Buffer const * buffer) const
978 if (!selection.set()) return string();
981 // Special handling if the whole selection is within one paragraph
982 if (selection.start.par() == selection.end.par()) {
983 result += selection.start.par()->asString(buffer,
984 selection.start.pos(),
985 selection.end.pos());
989 // The selection spans more than one paragraph
991 // First paragraph in selection
992 result += selection.start.par()->asString(buffer,
993 selection.start.pos(),
994 selection.start.par()->size())
997 // The paragraphs in between (if any)
998 LyXCursor tmpcur(selection.start);
999 tmpcur.par(tmpcur.par()->next());
1000 while (tmpcur.par() != selection.end.par()) {
1001 result += tmpcur.par()->asString(buffer, 0, tmpcur.par()->size()) + "\n\n";
1002 tmpcur.par(tmpcur.par()->next()); // Or NextAfterFootnote??
1005 // Last paragraph in selection
1006 result += selection.end.par()->asString(buffer, 0, selection.end.pos());
1012 void LyXText::clearSelection(BufferView * /*bview*/) const
1014 selection.set(false);
1015 selection.mark(false);
1016 selection.end = selection.start = cursor;
1020 void LyXText::cursorHome(BufferView * bview) const
1022 setCursor(bview, cursor.par(), cursor.row()->pos());
1026 void LyXText::cursorEnd(BufferView * bview) const
1028 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1029 setCursor(bview, cursor.par(), rowLast(cursor.row()) + 1);
1031 if (cursor.par()->size() &&
1032 (cursor.par()->getChar(rowLast(cursor.row())) == ' '
1033 || cursor.par()->isNewline(rowLast(cursor.row()))))
1034 setCursor(bview, cursor.par(), rowLast(cursor.row()));
1036 setCursor(bview,cursor.par(), rowLast(cursor.row()) + 1);
1041 void LyXText::cursorTop(BufferView * bview) const
1043 while (cursor.par()->previous())
1044 cursor.par(cursor.par()->previous());
1045 setCursor(bview, cursor.par(), 0);
1049 void LyXText::cursorBottom(BufferView * bview) const
1051 while (cursor.par()->next())
1052 cursor.par(cursor.par()->next());
1053 setCursor(bview, cursor.par(), cursor.par()->size());
1057 void LyXText::toggleFree(BufferView * bview,
1058 LyXFont const & font, bool toggleall)
1060 // If the mask is completely neutral, tell user
1061 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1062 // Could only happen with user style
1063 bview->owner()->message(_("No font change defined. Use Character under the Layout menu to define font change."));
1067 // Try implicit word selection
1068 // If there is a change in the language the implicit word selection
1070 LyXCursor resetCursor = cursor;
1071 bool implicitSelection = (font.language() == ignore_language
1072 && font.number() == LyXFont::IGNORE)
1073 ? selectWordWhenUnderCursor(bview) : false;
1076 setFont(bview, font, toggleall);
1078 /* Implicit selections are cleared afterwards and cursor is set to the
1079 original position. */
1080 if (implicitSelection) {
1081 clearSelection(bview);
1082 cursor = resetCursor;
1083 setCursor(bview, cursor.par(), cursor.pos());
1084 selection.cursor = cursor;
1087 inset_owner->setUpdateStatus(bview, InsetText::CURSOR_PAR);
1091 Paragraph::size_type
1092 LyXText::beginningOfMainBody(Buffer const * buf,
1093 Paragraph const * par) const
1095 if (textclasslist.Style(buf->params.textclass,
1096 par->getLayout()).labeltype != LABEL_MANUAL)
1099 return par->beginningOfMainBody();
1103 /* the DTP switches for paragraphs. LyX will store them in the
1104 * first physicla paragraph. When a paragraph is broken, the top settings
1105 * rest, the bottom settings are given to the new one. So I can make shure,
1106 * they do not duplicate themself and you cannnot make dirty things with
1109 void LyXText::setParagraph(BufferView * bview,
1110 bool line_top, bool line_bottom,
1111 bool pagebreak_top, bool pagebreak_bottom,
1112 VSpace const & space_top,
1113 VSpace const & space_bottom,
1115 string labelwidthstring,
1118 LyXCursor tmpcursor = cursor;
1119 if (!selection.set()) {
1120 selection.start = cursor;
1121 selection.end = cursor;
1124 // make sure that the depth behind the selection are restored, too
1125 Paragraph * endpar = selection.end.par()->next();
1126 Paragraph * undoendpar = endpar;
1128 if (endpar && endpar->getDepth()) {
1129 while (endpar && endpar->getDepth()) {
1130 endpar = endpar->next();
1131 undoendpar = endpar;
1135 endpar = endpar->next(); // because of parindents etc.
1138 setUndo(bview->buffer(), Undo::EDIT,
1139 selection.start.par()->previous(),
1143 Paragraph * tmppar = selection.end.par();
1144 while (tmppar != selection.start.par()->previous()) {
1145 setCursor(bview, tmppar, 0);
1146 status = LyXText::NEED_MORE_REFRESH;
1147 refresh_row = cursor.row();
1148 refresh_y = cursor.y() - cursor.row()->baseline();
1149 cursor.par()->params().lineTop(line_top);
1150 cursor.par()->params().lineBottom(line_bottom);
1151 cursor.par()->params().pagebreakTop(pagebreak_top);
1152 cursor.par()->params().pagebreakBottom(pagebreak_bottom);
1153 cursor.par()->params().spaceTop(space_top);
1154 cursor.par()->params().spaceBottom(space_bottom);
1155 // does the layout allow the new alignment?
1156 if (align == LYX_ALIGN_LAYOUT)
1157 align = textclasslist
1158 .Style(bview->buffer()->params.textclass,
1159 cursor.par()->getLayout()).align;
1160 if (align & textclasslist
1161 .Style(bview->buffer()->params.textclass,
1162 cursor.par()->getLayout()).alignpossible) {
1163 if (align == textclasslist
1164 .Style(bview->buffer()->params.textclass,
1165 cursor.par()->getLayout()).align)
1166 cursor.par()->params().align(LYX_ALIGN_LAYOUT);
1168 cursor.par()->params().align(align);
1170 cursor.par()->setLabelWidthString(labelwidthstring);
1171 cursor.par()->params().noindent(noindent);
1172 tmppar = cursor.par()->previous();
1175 redoParagraphs(bview, selection.start, endpar);
1177 clearSelection(bview);
1178 setCursor(bview, selection.start.par(), selection.start.pos());
1179 selection.cursor = cursor;
1180 setCursor(bview, selection.end.par(), selection.end.pos());
1181 setSelection(bview);
1182 setCursor(bview, tmpcursor.par(), tmpcursor.pos());
1184 bview->updateInset(inset_owner, true);
1188 char loweralphaCounter(int n)
1190 if (n < 1 || n > 26)
1200 char alphaCounter(int n)
1202 if (n < 1 || n > 26)
1210 char hebrewCounter(int n)
1212 static const char hebrew[22] = {
1213 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1214 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1215 '÷', 'ø', 'ù', 'ú'
1217 if (n < 1 || n > 22)
1225 string const romanCounter(int n)
1227 static char const * roman[20] = {
1228 "i", "ii", "iii", "iv", "v",
1229 "vi", "vii", "viii", "ix", "x",
1230 "xi", "xii", "xiii", "xiv", "xv",
1231 "xvi", "xvii", "xviii", "xix", "xx"
1233 if (n < 1 || n > 20)
1242 // set the counter of a paragraph. This includes the labels
1243 void LyXText::setCounter(Buffer const * buf, Paragraph * par) const
1245 LyXLayout const & layout =
1246 textclasslist.Style(buf->params.textclass,
1249 LyXTextClass const & textclass =
1250 textclasslist.TextClass(buf->params.textclass);
1252 /* copy the prev-counters to this one, unless this is the start of a
1253 footnote or of a bibliography or the very first paragraph */
1255 && !(textclasslist.Style(buf->params.textclass,
1256 par->previous()->getLayout()
1257 ).labeltype != LABEL_BIBLIO
1258 && layout.labeltype == LABEL_BIBLIO)) {
1259 for (int i = 0; i < 10; ++i) {
1260 par->setCounter(i, par->previous()->getFirstCounter(i));
1262 par->params().appendix(par->previous()->params().appendix());
1263 if (!par->params().appendix() && par->params().startOfAppendix()) {
1264 par->params().appendix(true);
1265 for (int i = 0; i < 10; ++i) {
1266 par->setCounter(i, 0);
1269 par->enumdepth = par->previous()->enumdepth;
1270 par->itemdepth = par->previous()->itemdepth;
1272 for (int i = 0; i < 10; ++i) {
1273 par->setCounter(i, 0);
1275 par->params().appendix(par->params().startOfAppendix());
1280 /* Maybe we have to increment the enumeration depth.
1281 * BUT, enumeration in a footnote is considered in isolation from its
1282 * surrounding paragraph so don't increment if this is the
1283 * first line of the footnote
1284 * AND, bibliographies can't have their depth changed ie. they
1285 * are always of depth 0
1288 && par->previous()->getDepth() < par->getDepth()
1289 && textclasslist.Style(buf->params.textclass,
1290 par->previous()->getLayout()
1291 ).labeltype == LABEL_COUNTER_ENUMI
1292 && par->enumdepth < 3
1293 && layout.labeltype != LABEL_BIBLIO) {
1297 /* Maybe we have to decrement the enumeration depth, see note above */
1299 && par->previous()->getDepth() > par->getDepth()
1300 && layout.labeltype != LABEL_BIBLIO) {
1301 par->enumdepth = par->depthHook(par->getDepth())->enumdepth;
1302 par->setCounter(6 + par->enumdepth,
1303 par->depthHook(par->getDepth())->getCounter(6 + par->enumdepth));
1304 /* reset the counters.
1305 * A depth change is like a breaking layout
1307 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1308 par->setCounter(i, 0);
1311 if (!par->params().labelString().empty()) {
1312 par->params().labelString(string());
1315 if (layout.margintype == MARGIN_MANUAL) {
1316 if (par->params().labelWidthString().empty()) {
1317 par->setLabelWidthString(layout.labelstring());
1320 par->setLabelWidthString(string());
1323 /* is it a layout that has an automatic label ? */
1324 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1326 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1327 if (i >= 0 && i<= buf->params.secnumdepth) {
1328 par->incCounter(i); // increment the counter
1330 // Is there a label? Useful for Chapter layout
1331 if (!par->params().appendix()) {
1332 if (!layout.labelstring().empty())
1333 par->params().labelString(layout.labelstring());
1335 par->params().labelString(string());
1337 if (!layout.labelstring_appendix().empty())
1338 par->params().labelString(layout.labelstring_appendix());
1340 par->params().labelString(string());
1343 std::ostringstream s;
1345 if (!par->params().appendix()) {
1346 switch (2 * LABEL_COUNTER_CHAPTER -
1347 textclass.maxcounter() + i) {
1348 case LABEL_COUNTER_CHAPTER:
1349 s << par->getCounter(i);
1351 case LABEL_COUNTER_SECTION:
1352 s << par->getCounter(i - 1) << '.'
1353 << par->getCounter(i);
1355 case LABEL_COUNTER_SUBSECTION:
1356 s << par->getCounter(i - 2) << '.'
1357 << par->getCounter(i - 1) << '.'
1358 << par->getCounter(i);
1360 case LABEL_COUNTER_SUBSUBSECTION:
1361 s << par->getCounter(i - 3) << '.'
1362 << par->getCounter(i - 2) << '.'
1363 << par->getCounter(i - 1) << '.'
1364 << par->getCounter(i);
1367 case LABEL_COUNTER_PARAGRAPH:
1368 s << par->getCounter(i - 4) << '.'
1369 << par->getCounter(i - 3) << '.'
1370 << par->getCounter(i - 2) << '.'
1371 << par->getCounter(i - 1) << '.'
1372 << par->getCounter(i);
1374 case LABEL_COUNTER_SUBPARAGRAPH:
1375 s << par->getCounter(i - 5) << '.'
1376 << par->getCounter(i - 4) << '.'
1377 << par->getCounter(i - 3) << '.'
1378 << par->getCounter(i - 2) << '.'
1379 << par->getCounter(i - 1) << '.'
1380 << par->getCounter(i);
1384 // Can this ever be reached? And in the
1385 // case it is, how can this be correct?
1387 s << par->getCounter(i) << '.';
1390 } else { // appendix
1391 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1392 case LABEL_COUNTER_CHAPTER:
1393 if (par->isRightToLeftPar(buf->params))
1394 s << hebrewCounter(par->getCounter(i));
1396 s << alphaCounter(par->getCounter(i));
1398 case LABEL_COUNTER_SECTION:
1399 if (par->isRightToLeftPar(buf->params))
1400 s << hebrewCounter(par->getCounter(i - 1));
1402 s << alphaCounter(par->getCounter(i - 1));
1405 << par->getCounter(i);
1408 case LABEL_COUNTER_SUBSECTION:
1409 if (par->isRightToLeftPar(buf->params))
1410 s << hebrewCounter(par->getCounter(i - 2));
1412 s << alphaCounter(par->getCounter(i - 2));
1415 << par->getCounter(i-1) << '.'
1416 << par->getCounter(i);
1419 case LABEL_COUNTER_SUBSUBSECTION:
1420 if (par->isRightToLeftPar(buf->params))
1421 s << hebrewCounter(par->getCounter(i-3));
1423 s << alphaCounter(par->getCounter(i-3));
1426 << par->getCounter(i-2) << '.'
1427 << par->getCounter(i-1) << '.'
1428 << par->getCounter(i);
1431 case LABEL_COUNTER_PARAGRAPH:
1432 if (par->isRightToLeftPar(buf->params))
1433 s << hebrewCounter(par->getCounter(i-4));
1435 s << alphaCounter(par->getCounter(i-4));
1438 << par->getCounter(i-3) << '.'
1439 << par->getCounter(i-2) << '.'
1440 << par->getCounter(i-1) << '.'
1441 << par->getCounter(i);
1444 case LABEL_COUNTER_SUBPARAGRAPH:
1445 if (par->isRightToLeftPar(buf->params))
1446 s << hebrewCounter(par->getCounter(i-5));
1448 s << alphaCounter(par->getCounter(i-5));
1451 << par->getCounter(i-4) << '.'
1452 << par->getCounter(i-3) << '.'
1453 << par->getCounter(i-2) << '.'
1454 << par->getCounter(i-1) << '.'
1455 << par->getCounter(i);
1459 // Can this ever be reached? And in the
1460 // case it is, how can this be correct?
1462 s << par->getCounter(i) << '.';
1468 par->params().labelString(par->params().labelString() +s.str().c_str());
1469 // We really want to remove the c_str as soon as
1472 for (i++; i < 10; ++i) {
1473 // reset the following counters
1474 par->setCounter(i, 0);
1476 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1477 for (i++; i < 10; ++i) {
1478 // reset the following counters
1479 par->setCounter(i, 0);
1481 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1482 par->incCounter(i + par->enumdepth);
1483 int number = par->getCounter(i + par->enumdepth);
1485 std::ostringstream s;
1487 switch (par->enumdepth) {
1489 if (par->isRightToLeftPar(buf->params))
1491 << hebrewCounter(number)
1495 << loweralphaCounter(number)
1499 if (par->isRightToLeftPar(buf->params))
1500 s << '.' << romanCounter(number);
1502 s << romanCounter(number) << '.';
1505 if (par->isRightToLeftPar(buf->params))
1507 << alphaCounter(number);
1509 s << alphaCounter(number)
1513 if (par->isRightToLeftPar(buf->params))
1520 par->params().labelString(s.str().c_str());
1521 // we really want to get rid of that c_str()
1523 for (i += par->enumdepth + 1; i < 10; ++i)
1524 par->setCounter(i, 0); /* reset the following counters */
1527 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1528 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1530 int number = par->getCounter(i);
1532 InsetCommandParams p( "bibitem" );
1533 par->bibkey = new InsetBibKey(p);
1535 par->bibkey->setCounter(number);
1536 par->params().labelString(layout.labelstring());
1538 // In biblio should't be following counters but...
1540 string s = layout.labelstring();
1542 // the caption hack:
1543 if (layout.labeltype == LABEL_SENSITIVE) {
1544 bool isOK (par->InInset() && par->InInset()->owner() &&
1545 (par->InInset()->owner()->lyxCode() == Inset::FLOAT_CODE));
1548 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
1550 = floatList.getType(tmp->type());
1551 // We should get the correct number here too.
1552 s = fl.name() + " #:";
1554 /* par->SetLayout(0);
1555 s = layout->labelstring; */
1556 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1557 ? " :úåòîùî øñç" : "Senseless: ";
1560 par->params().labelString(s);
1562 /* reset the enumeration counter. They are always resetted
1563 * when there is any other layout between */
1564 for (int i = 6 + par->enumdepth; i < 10; ++i)
1565 par->setCounter(i, 0);
1570 /* Updates all counters BEHIND the row. Changed paragraphs
1571 * with a dynamic left margin will be rebroken. */
1572 void LyXText::updateCounters(BufferView * bview, Row * row) const
1580 par = row->par()->next();
1584 while (row->par() != par)
1587 setCounter(bview->buffer(), par);
1589 /* now check for the headline layouts. remember that they
1590 * have a dynamic left margin */
1591 if ((textclasslist.Style(bview->buffer()->params.textclass,
1592 par->layout).margintype == MARGIN_DYNAMIC
1593 || textclasslist.Style(bview->buffer()->params.textclass,
1594 par->layout).labeltype == LABEL_SENSITIVE)) {
1596 /* Rebreak the paragraph */
1597 removeParagraph(row);
1598 appendParagraph(bview, row);
1605 /* insets an inset. */
1606 void LyXText::insertInset(BufferView * bview, Inset * inset)
1608 if (!cursor.par()->insertInsetAllowed(inset))
1610 setUndo(bview->buffer(), Undo::INSERT,
1611 cursor.par()->previous(),
1612 cursor.par()->next());
1613 cursor.par()->insertInset(cursor.pos(), inset);
1614 insertChar(bview, Paragraph::META_INSET); /* just to rebreak and refresh correctly.
1615 * The character will not be inserted a
1618 // If we enter a highly editable inset the cursor should be to before
1619 // the inset. This couldn't happen before as Undo was not handled inside
1620 // inset now after the Undo LyX tries to call inset->Edit(...) again
1621 // and cannot do this as the cursor is behind the inset and GetInset
1622 // does not return the inset!
1623 if (inset->editable() == Inset::HIGHLY_EDITABLE) {
1624 cursorLeft(bview, true);
1630 void LyXText::copyEnvironmentType()
1632 copylayouttype = cursor.par()->getLayout();
1636 void LyXText::pasteEnvironmentType(BufferView * bview)
1638 setLayout(bview, copylayouttype);
1642 void LyXText::cutSelection(BufferView * bview, bool doclear)
1644 // Stuff what we got on the clipboard. Even if there is no selection.
1646 // There is a problem with having the stuffing here in that the
1647 // larger the selection the slower LyX will get. This can be
1648 // solved by running the line below only when the selection has
1649 // finished. The solution used currently just works, to make it
1650 // faster we need to be more clever and probably also have more
1651 // calls to stuffClipboard. (Lgb)
1652 bview->stuffClipboard(selectionAsString(bview->buffer()));
1654 // This doesn't make sense, if there is no selection
1655 if (!selection.set())
1658 // OK, we have a selection. This is always between selection.start
1659 // and selection.end
1661 // make sure that the depth behind the selection are restored, too
1662 Paragraph * endpar = selection.end.par()->next();
1663 Paragraph * undoendpar = endpar;
1665 if (endpar && endpar->getDepth()) {
1666 while (endpar && endpar->getDepth()) {
1667 endpar = endpar->next();
1668 undoendpar = endpar;
1670 } else if (endpar) {
1671 endpar = endpar->next(); // because of parindents etc.
1674 setUndo(bview->buffer(), Undo::DELETE,
1675 selection.start.par()->previous(),
1680 // there are two cases: cut only within one paragraph or
1681 // more than one paragraph
1682 if (selection.start.par() == selection.end.par()) {
1683 // only within one paragraph
1684 endpar = selection.end.par();
1685 int pos = selection.end.pos();
1686 cap.cutSelection(selection.start.par(), &endpar,
1687 selection.start.pos(), pos,
1688 bview->buffer()->params.textclass, doclear);
1689 selection.end.pos(pos);
1691 endpar = selection.end.par();
1692 int pos = selection.end.pos();
1693 cap.cutSelection(selection.start.par(), &endpar,
1694 selection.start.pos(), pos,
1695 bview->buffer()->params.textclass, doclear);
1697 selection.end.par(endpar);
1698 selection.end.pos(pos);
1699 cursor.pos(selection.end.pos());
1701 endpar = endpar->next();
1703 // sometimes necessary
1705 selection.start.par()->stripLeadingSpaces(bview->buffer()->params.textclass);
1707 redoParagraphs(bview, selection.start, endpar);
1709 // cutSelection can invalidate the cursor so we need to set
1711 cursor = selection.start;
1713 // need a valid cursor. (Lgb)
1714 clearSelection(bview);
1716 setCursor(bview, cursor.par(), cursor.pos());
1717 selection.cursor = cursor;
1718 updateCounters(bview, cursor.row());
1722 void LyXText::copySelection(BufferView * bview)
1724 // Stuff what we got on the clipboard. Even if there is no selection.
1726 // There is a problem with having the stuffing here in that the
1727 // larger the selection the slower LyX will get. This can be
1728 // solved by running the line below only when the selection has
1729 // finished. The solution used currently just works, to make it
1730 // faster we need to be more clever and probably also have more
1731 // calls to stuffClipboard. (Lgb)
1732 bview->stuffClipboard(selectionAsString(bview->buffer()));
1734 // this doesnt make sense, if there is no selection
1735 if (!selection.set())
1738 // ok we have a selection. This is always between selection.start
1739 // and sel_end cursor
1741 // copy behind a space if there is one
1742 while (selection.start.par()->size() > selection.start.pos()
1743 && selection.start.par()->isLineSeparator(selection.start.pos())
1744 && (selection.start.par() != selection.end.par()
1745 || selection.start.pos() < selection.end.pos()))
1746 selection.start.pos(selection.start.pos() + 1);
1750 cap.copySelection(selection.start.par(), selection.end.par(),
1751 selection.start.pos(), selection.end.pos(),
1752 bview->buffer()->params.textclass);
1756 void LyXText::pasteSelection(BufferView * bview)
1760 // this does not make sense, if there is nothing to paste
1761 if (!cap.checkPastePossible(cursor.par()))
1764 setUndo(bview->buffer(), Undo::INSERT,
1765 cursor.par()->previous(),
1766 cursor.par()->next());
1769 Paragraph * actpar = cursor.par();
1771 int pos = cursor.pos();
1772 cap.pasteSelection(&actpar, &endpar, pos,
1773 bview->buffer()->params.textclass);
1775 redoParagraphs(bview, cursor, endpar);
1777 setCursor(bview, cursor.par(), cursor.pos());
1778 clearSelection(bview);
1780 selection.cursor = cursor;
1781 setCursor(bview, actpar, pos);
1782 setSelection(bview);
1783 updateCounters(bview, cursor.row());
1787 // returns a pointer to the very first Paragraph
1788 Paragraph * LyXText::firstParagraph() const
1790 return ownerParagraph();
1794 // sets the selection over the number of characters of string, no check!!
1795 void LyXText::setSelectionOverString(BufferView * bview, string const & str)
1800 selection.cursor = cursor;
1801 for (string::size_type i = 0; i < str.length(); ++i)
1803 setSelection(bview);
1807 // simple replacing. The font of the first selected character is used
1808 void LyXText::replaceSelectionWithString(BufferView * bview,
1811 setCursorParUndo(bview->buffer());
1814 if (!selection.set()) { // create a dummy selection
1815 selection.end = cursor;
1816 selection.start = cursor;
1819 // Get font setting before we cut
1820 Paragraph::size_type pos = selection.end.pos();
1821 LyXFont const font = selection.start.par()
1822 ->getFontSettings(bview->buffer()->params,
1823 selection.start.pos());
1825 // Insert the new string
1826 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
1827 selection.end.par()->insertChar(pos, (*cit), font);
1831 // Cut the selection
1832 cutSelection(bview);
1838 // needed to insert the selection
1839 void LyXText::insertStringAsLines(BufferView * bview, string const & str)
1841 Paragraph * par = cursor.par();
1842 Paragraph::size_type pos = cursor.pos();
1843 Paragraph * endpar = cursor.par()->next();
1845 setCursorParUndo(bview->buffer());
1847 bool isEnvironment =
1848 textclasslist.Style(bview->buffer()->params.textclass,
1849 cursor.par()->getLayout()).isEnvironment();
1851 textclasslist.Style(bview->buffer()->params.textclass,
1852 cursor.par()->getLayout()).free_spacing;
1854 textclasslist.Style(bview->buffer()->params.textclass,
1855 cursor.par()->getLayout()).keepempty;
1857 // only to be sure, should not be neccessary
1858 clearSelection(bview);
1860 // insert the string, don't insert doublespace
1861 bool space_inserted = true;
1862 for(string::const_iterator cit = str.begin();
1863 cit != str.end(); ++cit) {
1865 if (par->size() || keepempty) {
1866 par->breakParagraph(bview->buffer()->params,
1867 pos, isEnvironment);
1870 space_inserted = true;
1874 // do not insert consecutive spaces if !free_spacing
1875 } else if ((*cit == ' ' || *cit == '\t')
1876 && space_inserted && !free_spacing) {
1878 } else if (*cit == '\t') {
1879 if (!free_spacing) {
1880 // tabs are like spaces here
1881 par->insertChar(pos, ' ',
1884 space_inserted = true;
1886 const Paragraph::value_type nb = 8 - pos % 8;
1887 for (Paragraph::size_type a = 0;
1889 par->insertChar(pos, ' ',
1893 space_inserted = true;
1895 } else if (!IsPrintable(*cit)) {
1896 // Ignore unprintables
1899 // just insert the character
1900 par->insertChar(pos, *cit, current_font);
1902 space_inserted = (*cit == ' ');
1907 redoParagraphs(bview, cursor, endpar);
1908 setCursor(bview, cursor.par(), cursor.pos());
1909 selection.cursor = cursor;
1910 setCursor(bview, par, pos);
1911 setSelection(bview);
1915 /* turns double-CR to single CR, others where converted into one
1916 blank. Then InsertStringAsLines is called */
1917 void LyXText::insertStringAsParagraphs(BufferView * bview, string const & str)
1919 string linestr(str);
1920 bool newline_inserted = false;
1921 for (string::size_type i = 0; i < linestr.length(); ++i) {
1922 if (linestr[i] == '\n') {
1923 if (newline_inserted) {
1924 // we know that \r will be ignored by
1925 // InsertStringA. Of course, it is a dirty
1926 // trick, but it works...
1927 linestr[i - 1] = '\r';
1931 newline_inserted = true;
1933 } else if (IsPrintable(linestr[i])) {
1934 newline_inserted = false;
1937 insertStringAsLines(bview, linestr);
1941 bool LyXText::gotoNextInset(BufferView * bview,
1942 std::vector<Inset::Code> const & codes,
1943 string const & contents) const
1945 LyXCursor res = cursor;
1948 if (res.pos() < res.par()->size() - 1) {
1949 res.pos(res.pos() + 1);
1951 res.par(res.par()->next());
1955 } while (res.par() &&
1956 !(res.par()->getChar(res.pos()) == Paragraph::META_INSET
1957 && (inset = res.par()->getInset(res.pos())) != 0
1958 && find(codes.begin(), codes.end(), inset->lyxCode())
1960 && (contents.empty() ||
1961 static_cast<InsetCommand *>(res.par()->getInset(res.pos()))->getContents()
1965 setCursor(bview, res.par(), res.pos());
1972 void LyXText::checkParagraph(BufferView * bview, Paragraph * par,
1973 Paragraph::size_type pos)
1975 LyXCursor tmpcursor;
1978 Paragraph::size_type z;
1979 Row * row = getRow(par, pos, y);
1981 // is there a break one row above
1982 if (row->previous() && row->previous()->par() == row->par()) {
1983 z = nextBreakPoint(bview, row->previous(), workWidth(bview));
1984 if (z >= row->pos()) {
1985 // set the dimensions of the row above
1986 y -= row->previous()->height();
1988 refresh_row = row->previous();
1989 status = LyXText::NEED_MORE_REFRESH;
1991 breakAgain(bview, row->previous());
1993 // set the cursor again. Otherwise
1994 // dangling pointers are possible
1995 setCursor(bview, cursor.par(), cursor.pos(),
1996 false, cursor.boundary());
1997 selection.cursor = cursor;
2002 int const tmpheight = row->height();
2003 Paragraph::size_type const tmplast = rowLast(row);
2007 breakAgain(bview, row);
2008 if (row->height() == tmpheight && rowLast(row) == tmplast)
2009 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2011 status = LyXText::NEED_MORE_REFRESH;
2013 // check the special right address boxes
2014 if (textclasslist.Style(bview->buffer()->params.textclass,
2015 par->getLayout()).margintype
2016 == MARGIN_RIGHT_ADDRESS_BOX) {
2023 redoDrawingOfParagraph(bview, tmpcursor);
2026 // set the cursor again. Otherwise dangling pointers are possible
2027 // also set the selection
2029 if (selection.set()) {
2031 setCursorIntern(bview, selection.cursor.par(), selection.cursor.pos(),
2032 false, selection.cursor.boundary());
2033 selection.cursor = cursor;
2034 setCursorIntern(bview, selection.start.par(),
2035 selection.start.pos(),
2036 false, selection.start.boundary());
2037 selection.start = cursor;
2038 setCursorIntern(bview, selection.end.par(),
2039 selection.end.pos(),
2040 false, selection.end.boundary());
2041 selection.end = cursor;
2042 setCursorIntern(bview, last_sel_cursor.par(),
2043 last_sel_cursor.pos(),
2044 false, last_sel_cursor.boundary());
2045 last_sel_cursor = cursor;
2048 setCursorIntern(bview, cursor.par(), cursor.pos(),
2049 false, cursor.boundary());
2053 // returns false if inset wasn't found
2054 bool LyXText::updateInset(BufferView * bview, Inset * inset)
2056 // first check the current paragraph
2057 int pos = cursor.par()->getPositionOfInset(inset);
2059 checkParagraph(bview, cursor.par(), pos);
2063 // check every paragraph
2065 Paragraph * par = firstParagraph();
2067 pos = par->getPositionOfInset(inset);
2069 checkParagraph(bview, par, pos);
2079 void LyXText::setCursor(BufferView * bview, Paragraph * par,
2080 Paragraph::size_type pos,
2081 bool setfont, bool boundary) const
2083 LyXCursor old_cursor = cursor;
2084 setCursorIntern(bview, par, pos, setfont, boundary);
2085 deleteEmptyParagraphMechanism(bview, old_cursor);
2089 void LyXText::setCursor(BufferView *bview, LyXCursor & cur, Paragraph * par,
2090 Paragraph::size_type pos, bool boundary) const
2094 cur.boundary(boundary);
2096 /* get the cursor y position in text */
2098 Row * row = getRow(par, pos, y);
2099 /* y is now the beginning of the cursor row */
2100 y += row->baseline();
2101 /* y is now the cursor baseline */
2104 /* now get the cursors x position */
2106 float fill_separator;
2108 float fill_label_hfill;
2109 prepareToPrint(bview, row, x, fill_separator, fill_hfill,
2111 Paragraph::size_type cursor_vpos = 0;
2112 Paragraph::size_type last = rowLastPrintable(row);
2114 if (pos > last + 1) // This shouldn't happen.
2116 else if (pos < row->pos())
2119 if (last < row->pos())
2120 cursor_vpos = row->pos();
2121 else if (pos > last && !boundary)
2122 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2123 ? row->pos() : last + 1;
2124 else if (pos > row->pos() &&
2125 (pos > last || boundary))
2126 /// Place cursor after char at (logical) position pos - 1
2127 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2128 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2130 /// Place cursor before char at (logical) position pos
2131 cursor_vpos = (bidi_level(pos) % 2 == 0)
2132 ? log2vis(pos) : log2vis(pos) + 1;
2134 Paragraph::size_type main_body =
2135 beginningOfMainBody(bview->buffer(), row->par());
2136 if ((main_body > 0) &&
2137 ((main_body-1 > last) ||
2138 !row->par()->isLineSeparator(main_body-1)))
2141 for (Paragraph::size_type vpos = row->pos();
2142 vpos < cursor_vpos; ++vpos) {
2143 pos = vis2log(vpos);
2144 if (main_body > 0 && pos == main_body - 1) {
2145 x += fill_label_hfill +
2146 lyxfont::width(textclasslist.Style(
2147 bview->buffer()->params.textclass,
2148 row->par()->getLayout())
2150 getFont(bview->buffer(), row->par(), -2));
2151 if (row->par()->isLineSeparator(main_body-1))
2152 x -= singleWidth(bview, row->par(),main_body-1);
2154 if (hfillExpansion(bview->buffer(), row, pos)) {
2155 x += singleWidth(bview, row->par(), pos);
2156 if (pos >= main_body)
2159 x += fill_label_hfill;
2160 } else if (row->par()->isSeparator(pos)) {
2161 x += singleWidth(bview, row->par(), pos);
2162 if (pos >= main_body)
2163 x += fill_separator;
2165 x += singleWidth(bview, row->par(), pos);
2174 void LyXText::setCursorIntern(BufferView * bview, Paragraph * par,
2175 Paragraph::size_type pos,
2176 bool setfont, bool boundary) const
2178 setCursor(bview, cursor, par, pos, boundary);
2180 setCurrentFont(bview);
2184 void LyXText::setCurrentFont(BufferView * bview) const
2186 Paragraph::size_type pos = cursor.pos();
2187 if (cursor.boundary() && pos > 0)
2191 if (pos == cursor.par()->size())
2193 else // potentional bug... BUG (Lgb)
2194 if (cursor.par()->isSeparator(pos)) {
2195 if (pos > cursor.row()->pos() &&
2196 bidi_level(pos) % 2 ==
2197 bidi_level(pos - 1) % 2)
2199 else if (pos + 1 < cursor.par()->size())
2205 cursor.par()->getFontSettings(bview->buffer()->params, pos);
2206 real_current_font = getFont(bview->buffer(), cursor.par(), pos);
2208 if (cursor.pos() == cursor.par()->size() &&
2209 isBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2210 !cursor.boundary()) {
2211 Language const * lang =
2212 cursor.par()->getParLanguage(bview->buffer()->params);
2213 current_font.setLanguage(lang);
2214 current_font.setNumber(LyXFont::OFF);
2215 real_current_font.setLanguage(lang);
2216 real_current_font.setNumber(LyXFont::OFF);
2221 void LyXText::setCursorFromCoordinates(BufferView * bview, int x, int y) const
2223 LyXCursor old_cursor = cursor;
2225 /* get the row first */
2227 Row * row = getRowNearY(y);
2228 cursor.par(row->par());
2231 int column = getColumnNearX(bview, row, x, bound);
2232 cursor.pos(row->pos() + column);
2234 cursor.y(y + row->baseline());
2236 cursor.boundary(bound);
2237 setCurrentFont(bview);
2238 deleteEmptyParagraphMechanism(bview, old_cursor);
2242 void LyXText::setCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2245 /* get the row first */
2247 Row * row = getRowNearY(y);
2249 int column = getColumnNearX(bview, row, x, bound);
2251 cur.par(row->par());
2252 cur.pos(row->pos() + column);
2254 cur.y(y + row->baseline());
2256 cur.boundary(bound);
2260 void LyXText::cursorLeft(BufferView * bview, bool internal) const
2262 if (cursor.pos() > 0) {
2263 bool boundary = cursor.boundary();
2264 setCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2265 if (!internal && !boundary &&
2266 isBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2267 setCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2268 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2269 Paragraph * par = cursor.par()->previous();
2270 setCursor(bview, par, par->size());
2275 void LyXText::cursorRight(BufferView * bview, bool internal) const
2277 if (!internal && cursor.boundary() &&
2278 !cursor.par()->isNewline(cursor.pos()))
2279 setCursor(bview, cursor.par(), cursor.pos(), true, false);
2280 else if (cursor.pos() < cursor.par()->size()) {
2281 setCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2283 isBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2284 setCursor(bview, cursor.par(), cursor.pos(), true, true);
2285 } else if (cursor.par()->next())
2286 setCursor(bview, cursor.par()->next(), 0);
2290 void LyXText::cursorUp(BufferView * bview) const
2292 setCursorFromCoordinates(bview, cursor.x_fix(),
2293 cursor.y() - cursor.row()->baseline() - 1);
2297 void LyXText::cursorDown(BufferView * bview) const
2299 setCursorFromCoordinates(bview, cursor.x_fix(),
2300 cursor.y() - cursor.row()->baseline()
2301 + cursor.row()->height() + 1);
2305 void LyXText::cursorUpParagraph(BufferView * bview) const
2307 if (cursor.pos() > 0) {
2308 setCursor(bview, cursor.par(), 0);
2310 else if (cursor.par()->previous()) {
2311 setCursor(bview, cursor.par()->previous(), 0);
2316 void LyXText::cursorDownParagraph(BufferView * bview) const
2318 if (cursor.par()->next()) {
2319 setCursor(bview, cursor.par()->next(), 0);
2321 setCursor(bview, cursor.par(), cursor.par()->size());
2326 void LyXText::deleteEmptyParagraphMechanism(BufferView * bview,
2327 LyXCursor const & old_cursor) const
2329 // Would be wrong to delete anything if we have a selection.
2330 if (selection.set()) return;
2332 // We allow all kinds of "mumbo-jumbo" when freespacing.
2333 if (textclasslist.Style(bview->buffer()->params.textclass,
2334 old_cursor.par()->getLayout()).free_spacing)
2337 bool deleted = false;
2339 /* Ok I'll put some comments here about what is missing.
2340 I have fixed BackSpace (and thus Delete) to not delete
2341 double-spaces automagically. I have also changed Cut,
2342 Copy and Paste to hopefully do some sensible things.
2343 There are still some small problems that can lead to
2344 double spaces stored in the document file or space at
2345 the beginning of paragraphs. This happens if you have
2346 the cursor betwenn to spaces and then save. Or if you
2347 cut and paste and the selection have a space at the
2348 beginning and then save right after the paste. I am
2349 sure none of these are very hard to fix, but I will
2350 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2351 that I can get some feedback. (Lgb)
2354 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2355 // delete the LineSeparator.
2358 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2359 // delete the LineSeparator.
2362 // If the pos around the old_cursor were spaces, delete one of them.
2363 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
2364 // Only if the cursor has really moved
2366 if (old_cursor.pos() > 0
2367 && old_cursor.pos() < old_cursor.par()->size()
2368 && old_cursor.par()->isLineSeparator(old_cursor.pos())
2369 && old_cursor.par()->isLineSeparator(old_cursor.pos() - 1)) {
2370 old_cursor.par()->erase(old_cursor.pos() - 1);
2371 redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2373 if (old_cursor.par() == cursor.par() &&
2374 cursor.pos() > old_cursor.pos()) {
2375 setCursorIntern(bview, cursor.par(),
2378 setCursorIntern(bview, cursor.par(),
2384 // Do not delete empty paragraphs with keepempty set.
2385 if ((textclasslist.Style(bview->buffer()->params.textclass,
2386 old_cursor.par()->getLayout())).keepempty)
2389 LyXCursor tmpcursor;
2391 if (old_cursor.par() != cursor.par()) {
2392 if ((old_cursor.par()->size() == 0
2393 || (old_cursor.par()->size() == 1
2394 && old_cursor.par()->isLineSeparator(0)))) {
2395 // ok, we will delete anything
2397 // make sure that you do not delete any environments
2398 status = LyXText::NEED_MORE_REFRESH;
2401 if (old_cursor.row()->previous()) {
2402 refresh_row = old_cursor.row()->previous();
2403 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2405 cursor = old_cursor; // that undo can restore the right cursor position
2406 Paragraph * endpar = old_cursor.par()->next();
2407 if (endpar && endpar->getDepth()) {
2408 while (endpar && endpar->getDepth()) {
2409 endpar = endpar->next();
2412 setUndo(bview->buffer(), Undo::DELETE,
2413 old_cursor.par()->previous(),
2418 removeRow(old_cursor.row());
2419 if (ownerParagraph() == old_cursor.par()) {
2420 ownerParagraph(ownerParagraph()->next());
2423 delete old_cursor.par();
2425 /* Breakagain the next par. Needed
2426 * because of the parindent that
2427 * can occur or dissappear. The
2428 * next row can change its height,
2429 * if there is another layout before */
2430 if (refresh_row->next()) {
2431 breakAgain(bview, refresh_row->next());
2432 updateCounters(bview, refresh_row);
2434 setHeightOfRow(bview, refresh_row);
2436 refresh_row = old_cursor.row()->next();
2437 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2440 cursor = old_cursor; // that undo can restore the right cursor position
2441 Paragraph * endpar = old_cursor.par()->next();
2442 if (endpar && endpar->getDepth()) {
2443 while (endpar && endpar->getDepth()) {
2444 endpar = endpar->next();
2447 setUndo(bview->buffer(), Undo::DELETE,
2448 old_cursor.par()->previous(),
2453 removeRow(old_cursor.row());
2455 if (ownerParagraph() == old_cursor.par()) {
2456 ownerParagraph(ownerParagraph()->next());
2459 delete old_cursor.par();
2461 /* Breakagain the next par. Needed
2462 because of the parindent that can
2463 occur or dissappear.
2464 The next row can change its height,
2465 if there is another layout before
2468 breakAgain(bview, refresh_row);
2469 updateCounters(bview, refresh_row->previous());
2475 setCursorIntern(bview, cursor.par(), cursor.pos());
2477 if (selection.cursor.par() == old_cursor.par()
2478 && selection.cursor.pos() == selection.cursor.pos()) {
2479 // correct selection
2480 selection.cursor = cursor;
2484 if (old_cursor.par()->stripLeadingSpaces(bview->buffer()->params.textclass)) {
2485 redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2487 setCursorIntern(bview, cursor.par(), cursor.pos());
2488 selection.cursor = cursor;
2495 Paragraph * LyXText::getParFromID(int id)
2497 Paragraph * result = firstParagraph();
2498 while (result && result->id() != id)
2499 result = result->next();
2505 bool LyXText::textUndo(BufferView * bview)
2509 // returns false if no undo possible
2510 Undo * undo = bview->buffer()->undostack.pop();
2514 bview->buffer()->redostack
2515 .push(createUndo(bview->buffer(), undo->kind,
2516 getParFromID(undo->number_of_before_par),
2517 getParFromID(undo->number_of_behind_par)));
2519 return textHandleUndo(bview, undo);
2523 bool LyXText::textRedo(BufferView * bview)
2527 // returns false if no redo possible
2528 Undo * undo = bview->buffer()->redostack.pop();
2532 bview->buffer()->undostack
2533 .push(createUndo(bview->buffer(), undo->kind,
2534 getParFromID(undo->number_of_before_par),
2535 getParFromID(undo->number_of_behind_par)));
2537 return textHandleUndo(bview, undo);
2541 bool LyXText::textHandleUndo(BufferView * bview, Undo * undo)
2545 // returns false if no undo possible
2546 bool result = false;
2548 Paragraph * before =
2549 getParFromID(undo->number_of_before_par);
2550 Paragraph * behind =
2551 getParFromID(undo->number_of_behind_par);
2553 Paragraph * tmppar2;
2555 Paragraph * tmppar5;
2557 // if there's no before take the beginning
2558 // of the document for redoing
2560 setCursorIntern(bview, firstParagraph(), 0);
2562 // replace the paragraphs with the undo informations
2564 Paragraph * tmppar3 = undo->par;
2565 undo->par = 0; // otherwise the undo destructor would delete the paragraph
2566 Paragraph * tmppar4 = tmppar3;
2569 while (tmppar4->next())
2570 tmppar4 = tmppar4->next();
2571 } // get last undo par
2573 // now remove the old text if there is any
2574 if (before != behind || (!behind && !before)) {
2576 tmppar5 = before->next();
2578 tmppar5 = ownerParagraph();
2580 while (tmppar5 && tmppar5 != behind) {
2582 tmppar5 = tmppar5->next();
2583 // a memory optimization for edit: Only layout information
2584 // is stored in the undo. So restore the text informations.
2585 if (undo->kind == Undo::EDIT) {
2586 tmppar2->setContentsFromPar(tmppar);
2587 tmppar->clearContents();
2588 tmppar2 = tmppar2->next();
2593 // put the new stuff in the list if there is one
2596 before->next(tmppar3);
2598 ownerParagraph(tmppar3);
2599 tmppar3->previous(before);
2602 ownerParagraph(behind);
2605 tmppar4->next(behind);
2607 behind->previous(tmppar4);
2611 // Set the cursor for redoing
2613 setCursorIntern(bview, before, 0);
2616 // calculate the endpar for redoing the paragraphs.
2618 endpar = behind->next();
2622 tmppar = getParFromID(undo->number_of_cursor_par);
2623 redoParagraphs(bview, cursor, endpar);
2625 setCursorIntern(bview, tmppar, undo->cursor_pos);
2626 updateCounters(bview, cursor.row());
2636 void LyXText::finishUndo()
2640 // makes sure the next operation will be stored
2641 undo_finished = true;
2645 void LyXText::freezeUndo()
2649 // this is dangerous and for internal use only
2654 void LyXText::unFreezeUndo()
2658 // this is dangerous and for internal use only
2659 undo_frozen = false;
2663 void LyXText::setUndo(Buffer * buf, Undo::undo_kind kind,
2664 Paragraph const * before,
2665 Paragraph const * behind) const
2670 buf->undostack.push(createUndo(buf, kind, before, behind));
2671 buf->redostack.clear();
2675 void LyXText::setRedo(Buffer * buf, Undo::undo_kind kind,
2676 Paragraph const * before, Paragraph const * behind)
2680 buf->redostack.push(createUndo(buf, kind, before, behind));
2684 Undo * LyXText::createUndo(Buffer * buf, Undo::undo_kind kind,
2685 Paragraph const * before,
2686 Paragraph const * behind) const
2691 int before_number = -1;
2692 int behind_number = -1;
2694 before_number = before->id();
2696 behind_number = behind->id();
2697 // Undo::EDIT and Undo::FINISH are
2698 // always finished. (no overlapping there)
2699 // overlapping only with insert and delete inside one paragraph:
2700 // Nobody wants all removed character
2701 // appear one by one when undoing.
2702 // EDIT is special since only layout information, not the
2703 // contents of a paragaph are stored.
2704 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
2705 // check wether storing is needed
2706 if (!buf->undostack.empty() &&
2707 buf->undostack.top()->kind == kind &&
2708 buf->undostack.top()->number_of_before_par == before_number &&
2709 buf->undostack.top()->number_of_behind_par == behind_number ){
2714 // create a new Undo
2715 Paragraph * undopar;
2717 Paragraph * start = 0;
2718 Paragraph * end = 0;
2721 start = const_cast<Paragraph*>(before->next());
2723 start = firstParagraph();
2725 end = const_cast<Paragraph*>(behind->previous());
2727 end = firstParagraph();
2731 if (start && end && (start != end->next()) &&
2732 ((before != behind) || (!before && !behind))) {
2733 Paragraph * tmppar = start;
2734 Paragraph * tmppar2 = new Paragraph(*tmppar);
2735 tmppar2->id(tmppar->id());
2737 // a memory optimization: Just store the layout information
2739 if (kind == Undo::EDIT){
2740 //tmppar2->text.clear();
2741 tmppar2->clearContents();
2746 while (tmppar != end && tmppar->next()) {
2747 tmppar = tmppar->next();
2748 tmppar2->next(new Paragraph(*tmppar));
2749 tmppar2->next()->id(tmppar->id());
2750 // a memory optimization: Just store the layout
2751 // information when only edit
2752 if (kind == Undo::EDIT){
2753 //tmppar2->next->text.clear();
2754 tmppar2->clearContents();
2756 tmppar2->next()->previous(tmppar2);
2757 tmppar2 = tmppar2->next();
2761 undopar = 0; // nothing to replace (undo of delete maybe)
2763 int cursor_par = cursor.par()->id();
2764 int cursor_pos = cursor.pos();
2766 Undo * undo = new Undo(kind,
2767 before_number, behind_number,
2768 cursor_par, cursor_pos,
2771 undo_finished = false;
2776 void LyXText::setCursorParUndo(Buffer * buf)
2780 setUndo(buf, Undo::FINISH,
2781 cursor.par()->previous(),
2782 cursor.par()->next());
2786 void LyXText::toggleAppendix(BufferView * bview)
2788 Paragraph * par = cursor.par();
2789 bool start = !par->params().startOfAppendix();
2791 // ensure that we have only one start_of_appendix in this document
2792 Paragraph * tmp = firstParagraph();
2793 for (; tmp; tmp = tmp->next())
2794 tmp->params().startOfAppendix(false);
2796 par->params().startOfAppendix(start);
2798 // we can set the refreshing parameters now
2799 status = LyXText::NEED_MORE_REFRESH;
2801 refresh_row = 0; // not needed for full update
2802 updateCounters(bview, 0);
2803 setCursor(bview, cursor.par(), cursor.pos());
2807 Paragraph * LyXText::ownerParagraph() const
2810 return inset_owner->par;
2812 return bv_owner->buffer()->paragraph;
2816 Paragraph * LyXText::ownerParagraph(Paragraph * p) const
2819 inset_owner->par = p;
2821 bv_owner->buffer()->paragraph = p;