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);
763 Paragraph * first_phys_par = tmprow->par();
765 // find the first row of the paragraph
766 if (first_phys_par != tmprow->par())
767 while (tmprow->previous()
768 && tmprow->previous()->par() != first_phys_par) {
769 tmprow = tmprow->previous();
770 y -= tmprow->height();
771 setHeightOfRow(bview, tmprow);
773 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
774 tmprow = tmprow->previous();
775 y -= tmprow->height();
776 setHeightOfRow(bview, tmprow);
779 while (tmprow->previous() && tmprow->previous()->par() == tmprow->par()) {
780 tmprow = tmprow->previous();
781 y -= tmprow->height();
782 setHeightOfRow(bview, tmprow);
786 // we can set the refreshing parameters now
787 status = LyXText::NEED_MORE_REFRESH;
789 refresh_row = tmprow;
790 setCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
794 void LyXText::redoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
796 Row * tmprow = cur.row();
798 int y = cur.y() - tmprow->baseline();
799 setHeightOfRow(bview, tmprow);
802 Paragraph * first_phys_par = tmprow->par();
804 // find the first row of the paragraph
805 if (first_phys_par != tmprow->par())
806 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
807 tmprow = tmprow->previous();
808 y -= tmprow->height();
810 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
811 tmprow = tmprow->previous();
812 y -= tmprow->height();
815 while (tmprow->previous() && tmprow->previous()->par() == tmprow->par()) {
816 tmprow = tmprow->previous();
817 y -= tmprow->height();
820 // we can set the refreshing parameters now
821 if (status == LyXText::UNCHANGED || y < refresh_y) {
823 refresh_row = tmprow;
825 status = LyXText::NEED_MORE_REFRESH;
826 setCursor(bview, cur.par(), cur.pos());
830 /* deletes and inserts again all paragaphs between the cursor
831 * and the specified par
832 * This function is needed after SetLayout and SetFont etc. */
833 void LyXText::redoParagraphs(BufferView * bview, LyXCursor const & cur,
834 Paragraph const * endpar) const
837 Paragraph * tmppar = 0;
838 Paragraph * first_phys_par = 0;
840 Row * tmprow = cur.row();
842 int y = cur.y() - tmprow->baseline();
845 if (!tmprow->previous()) {
846 first_phys_par = firstParagraph(); // a trick/hack for UNDO
848 first_phys_par = tmprow->par();
849 // find the first row of the paragraph
850 if (first_phys_par != tmprow->par())
851 while (tmprow->previous() &&
852 (tmprow->previous()->par() != first_phys_par)) {
853 tmprow = tmprow->previous();
854 y -= tmprow->height();
856 while (tmprow->previous()
857 && tmprow->previous()->par() == first_phys_par) {
858 tmprow = tmprow->previous();
859 y -= tmprow->height();
863 if (!tmprow->previous()) {
864 // a trick/hack for UNDO
865 // Can somebody please tell me _why_ this solves
867 first_phys_par = firstParagraph();
869 first_phys_par = tmprow->par();
870 while (tmprow->previous()
871 && tmprow->previous()->par() == first_phys_par) {
872 tmprow = tmprow->previous();
873 y -= tmprow->height();
878 // we can set the refreshing parameters now
879 status = LyXText::NEED_MORE_REFRESH;
881 refresh_row = tmprow->previous(); /* the real refresh row will
882 be deleted, so I store
886 tmppar = tmprow->next()->par();
889 while (tmppar != endpar) {
890 removeRow(tmprow->next());
892 tmppar = tmprow->next()->par();
897 // remove the first one
898 tmprow2 = tmprow; /* this is because tmprow->previous()
900 tmprow = tmprow->previous();
903 tmppar = first_phys_par;
907 insertParagraph(bview, tmppar, tmprow);
910 while (tmprow->next() && tmprow->next()->par() == tmppar)
911 tmprow = tmprow->next();
912 tmppar = tmppar->next();
914 } while (tmppar != endpar);
916 // this is because of layout changes
918 refresh_y -= refresh_row->height();
919 setHeightOfRow(bview, refresh_row);
921 refresh_row = firstrow;
923 setHeightOfRow(bview, refresh_row);
926 if (tmprow && tmprow->next())
927 setHeightOfRow(bview, tmprow->next());
931 bool LyXText::fullRebreak(BufferView * bview)
937 if (need_break_row) {
938 breakAgain(bview, need_break_row);
946 /* important for the screen */
949 /* the cursor set functions have a special mechanism. When they
950 * realize, that you left an empty paragraph, they will delete it.
951 * They also delete the corresponding row */
953 // need the selection cursor:
954 void LyXText::setSelection(BufferView * bview)
956 bool const lsel = selection.set();
958 if (!selection.set()) {
959 last_sel_cursor = selection.cursor;
960 selection.start = selection.cursor;
961 selection.end = selection.cursor;
966 // first the toggling area
967 if (cursor.y() < last_sel_cursor.y()
968 || (cursor.y() == last_sel_cursor.y()
969 && cursor.x() < last_sel_cursor.x())) {
970 toggle_end_cursor = last_sel_cursor;
971 toggle_cursor = cursor;
973 toggle_end_cursor = cursor;
974 toggle_cursor = last_sel_cursor;
977 last_sel_cursor = cursor;
979 // and now the whole selection
981 if (selection.cursor.par() == cursor.par())
982 if (selection.cursor.pos() < cursor.pos()) {
983 selection.end = cursor;
984 selection.start = selection.cursor;
986 selection.end = selection.cursor;
987 selection.start = cursor;
989 else if (selection.cursor.y() < cursor.y() ||
990 (selection.cursor.y() == cursor.y() && selection.cursor.x() < cursor.x())) {
991 selection.end = cursor;
992 selection.start = selection.cursor;
995 selection.end = selection.cursor;
996 selection.start = cursor;
999 // a selection with no contents is not a selection
1000 if (selection.start.par() == selection.end.par() &&
1001 selection.start.pos() == selection.end.pos())
1002 selection.set(false);
1004 if (inset_owner && (selection.set() || lsel))
1005 inset_owner->setUpdateStatus(bview, InsetText::SELECTION);
1009 string const LyXText::selectionAsString(Buffer const * buffer) const
1011 if (!selection.set()) return string();
1014 // Special handling if the whole selection is within one paragraph
1015 if (selection.start.par() == selection.end.par()) {
1016 result += selection.start.par()->asString(buffer,
1017 selection.start.pos(),
1018 selection.end.pos());
1022 // The selection spans more than one paragraph
1024 // First paragraph in selection
1025 result += selection.start.par()->asString(buffer,
1026 selection.start.pos(),
1027 selection.start.par()->size())
1030 // The paragraphs in between (if any)
1031 LyXCursor tmpcur(selection.start);
1032 tmpcur.par(tmpcur.par()->next());
1033 while (tmpcur.par() != selection.end.par()) {
1034 result += tmpcur.par()->asString(buffer, 0, tmpcur.par()->size()) + "\n\n";
1035 tmpcur.par(tmpcur.par()->next()); // Or NextAfterFootnote??
1038 // Last paragraph in selection
1039 result += selection.end.par()->asString(buffer, 0, selection.end.pos());
1045 void LyXText::clearSelection(BufferView * /*bview*/) const
1047 selection.set(false);
1048 selection.mark(false);
1049 selection.end = selection.start = cursor;
1053 void LyXText::cursorHome(BufferView * bview) const
1055 setCursor(bview, cursor.par(), cursor.row()->pos());
1059 void LyXText::cursorEnd(BufferView * bview) const
1061 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1062 setCursor(bview, cursor.par(), rowLast(cursor.row()) + 1);
1064 if (cursor.par()->size() &&
1065 (cursor.par()->getChar(rowLast(cursor.row())) == ' '
1066 || cursor.par()->isNewline(rowLast(cursor.row()))))
1067 setCursor(bview, cursor.par(), rowLast(cursor.row()));
1069 setCursor(bview,cursor.par(), rowLast(cursor.row()) + 1);
1074 void LyXText::cursorTop(BufferView * bview) const
1076 while (cursor.par()->previous())
1077 cursor.par(cursor.par()->previous());
1078 setCursor(bview, cursor.par(), 0);
1082 void LyXText::cursorBottom(BufferView * bview) const
1084 while (cursor.par()->next())
1085 cursor.par(cursor.par()->next());
1086 setCursor(bview, cursor.par(), cursor.par()->size());
1090 void LyXText::toggleFree(BufferView * bview,
1091 LyXFont const & font, bool toggleall)
1093 // If the mask is completely neutral, tell user
1094 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1095 // Could only happen with user style
1096 bview->owner()->message(_("No font change defined. Use Character under the Layout menu to define font change."));
1100 // Try implicit word selection
1101 // If there is a change in the language the implicit word selection
1103 LyXCursor resetCursor = cursor;
1104 bool implicitSelection = (font.language() == ignore_language
1105 && font.number() == LyXFont::IGNORE)
1106 ? selectWordWhenUnderCursor(bview) : false;
1109 setFont(bview, font, toggleall);
1111 /* Implicit selections are cleared afterwards and cursor is set to the
1112 original position. */
1113 if (implicitSelection) {
1114 clearSelection(bview);
1115 cursor = resetCursor;
1116 setCursor(bview, cursor.par(), cursor.pos());
1117 selection.cursor = cursor;
1120 inset_owner->setUpdateStatus(bview, InsetText::CURSOR_PAR);
1124 Paragraph::size_type
1125 LyXText::beginningOfMainBody(Buffer const * buf,
1126 Paragraph const * par) const
1128 if (textclasslist.Style(buf->params.textclass,
1129 par->getLayout()).labeltype != LABEL_MANUAL)
1132 return par->beginningOfMainBody();
1136 /* the DTP switches for paragraphs. LyX will store them in the
1137 * first physicla paragraph. When a paragraph is broken, the top settings
1138 * rest, the bottom settings are given to the new one. So I can make shure,
1139 * they do not duplicate themself and you cannnot make dirty things with
1142 void LyXText::setParagraph(BufferView * bview,
1143 bool line_top, bool line_bottom,
1144 bool pagebreak_top, bool pagebreak_bottom,
1145 VSpace const & space_top,
1146 VSpace const & space_bottom,
1148 string labelwidthstring,
1151 LyXCursor tmpcursor = cursor;
1152 if (!selection.set()) {
1153 selection.start = cursor;
1154 selection.end = cursor;
1157 // make sure that the depth behind the selection are restored, too
1158 Paragraph * endpar = selection.end.par()->next();
1159 Paragraph * undoendpar = endpar;
1161 if (endpar && endpar->getDepth()) {
1162 while (endpar && endpar->getDepth()) {
1163 endpar = endpar->next();
1164 undoendpar = endpar;
1168 endpar = endpar->next(); // because of parindents etc.
1171 setUndo(bview->buffer(), Undo::EDIT,
1172 selection.start.par()->previous(),
1176 Paragraph * tmppar = selection.end.par();
1177 while (tmppar != selection.start.par()->previous()) {
1178 setCursor(bview, tmppar, 0);
1179 status = LyXText::NEED_MORE_REFRESH;
1180 refresh_row = cursor.row();
1181 refresh_y = cursor.y() - cursor.row()->baseline();
1182 cursor.par()->params().lineTop(line_top);
1183 cursor.par()->params().lineBottom(line_bottom);
1184 cursor.par()->params().pagebreakTop(pagebreak_top);
1185 cursor.par()->params().pagebreakBottom(pagebreak_bottom);
1186 cursor.par()->params().spaceTop(space_top);
1187 cursor.par()->params().spaceBottom(space_bottom);
1188 // does the layout allow the new alignment?
1189 if (align == LYX_ALIGN_LAYOUT)
1190 align = textclasslist
1191 .Style(bview->buffer()->params.textclass,
1192 cursor.par()->getLayout()).align;
1193 if (align & textclasslist
1194 .Style(bview->buffer()->params.textclass,
1195 cursor.par()->getLayout()).alignpossible) {
1196 if (align == textclasslist
1197 .Style(bview->buffer()->params.textclass,
1198 cursor.par()->getLayout()).align)
1199 cursor.par()->params().align(LYX_ALIGN_LAYOUT);
1201 cursor.par()->params().align(align);
1203 cursor.par()->setLabelWidthString(labelwidthstring);
1204 cursor.par()->params().noindent(noindent);
1205 tmppar = cursor.par()->previous();
1208 redoParagraphs(bview, selection.start, endpar);
1210 clearSelection(bview);
1211 setCursor(bview, selection.start.par(), selection.start.pos());
1212 selection.cursor = cursor;
1213 setCursor(bview, selection.end.par(), selection.end.pos());
1214 setSelection(bview);
1215 setCursor(bview, tmpcursor.par(), tmpcursor.pos());
1217 bview->updateInset(inset_owner, true);
1221 char loweralphaCounter(int n)
1223 if (n < 1 || n > 26)
1233 char alphaCounter(int n)
1235 if (n < 1 || n > 26)
1243 char hebrewCounter(int n)
1245 static const char hebrew[22] = {
1246 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1247 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1248 '÷', 'ø', 'ù', 'ú'
1250 if (n < 1 || n > 22)
1258 string const romanCounter(int n)
1260 static char const * roman[20] = {
1261 "i", "ii", "iii", "iv", "v",
1262 "vi", "vii", "viii", "ix", "x",
1263 "xi", "xii", "xiii", "xiv", "xv",
1264 "xvi", "xvii", "xviii", "xix", "xx"
1266 if (n < 1 || n > 20)
1275 // set the counter of a paragraph. This includes the labels
1276 void LyXText::setCounter(Buffer const * buf, Paragraph * par) const
1278 LyXLayout const & layout =
1279 textclasslist.Style(buf->params.textclass,
1282 LyXTextClass const & textclass =
1283 textclasslist.TextClass(buf->params.textclass);
1285 /* copy the prev-counters to this one, unless this is the start of a
1286 footnote or of a bibliography or the very first paragraph */
1288 && !(textclasslist.Style(buf->params.textclass,
1289 par->previous()->getLayout()
1290 ).labeltype != LABEL_BIBLIO
1291 && layout.labeltype == LABEL_BIBLIO)) {
1292 for (int i = 0; i < 10; ++i) {
1293 par->setCounter(i, par->previous()->getFirstCounter(i));
1295 par->params().appendix(par->previous()->params().appendix());
1296 if (!par->params().appendix() && par->params().startOfAppendix()) {
1297 par->params().appendix(true);
1298 for (int i = 0; i < 10; ++i) {
1299 par->setCounter(i, 0);
1302 par->enumdepth = par->previous()->enumdepth;
1303 par->itemdepth = par->previous()->itemdepth;
1305 for (int i = 0; i < 10; ++i) {
1306 par->setCounter(i, 0);
1308 par->params().appendix(par->params().startOfAppendix());
1313 /* Maybe we have to increment the enumeration depth.
1314 * BUT, enumeration in a footnote is considered in isolation from its
1315 * surrounding paragraph so don't increment if this is the
1316 * first line of the footnote
1317 * AND, bibliographies can't have their depth changed ie. they
1318 * are always of depth 0
1321 && par->previous()->getDepth() < par->getDepth()
1322 && textclasslist.Style(buf->params.textclass,
1323 par->previous()->getLayout()
1324 ).labeltype == LABEL_COUNTER_ENUMI
1325 && par->enumdepth < 3
1326 && layout.labeltype != LABEL_BIBLIO) {
1330 /* Maybe we have to decrement the enumeration depth, see note above */
1332 && par->previous()->getDepth() > par->getDepth()
1333 && layout.labeltype != LABEL_BIBLIO) {
1334 par->enumdepth = par->depthHook(par->getDepth())->enumdepth;
1335 par->setCounter(6 + par->enumdepth,
1336 par->depthHook(par->getDepth())->getCounter(6 + par->enumdepth));
1337 /* reset the counters.
1338 * A depth change is like a breaking layout
1340 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1341 par->setCounter(i, 0);
1344 if (!par->params().labelString().empty()) {
1345 par->params().labelString(string());
1348 if (layout.margintype == MARGIN_MANUAL) {
1349 if (par->params().labelWidthString().empty()) {
1350 par->setLabelWidthString(layout.labelstring());
1353 par->setLabelWidthString(string());
1356 /* is it a layout that has an automatic label ? */
1357 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1359 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1360 if (i >= 0 && i<= buf->params.secnumdepth) {
1361 par->incCounter(i); // increment the counter
1363 // Is there a label? Useful for Chapter layout
1364 if (!par->params().appendix()) {
1365 if (!layout.labelstring().empty())
1366 par->params().labelString(layout.labelstring());
1368 par->params().labelString(string());
1370 if (!layout.labelstring_appendix().empty())
1371 par->params().labelString(layout.labelstring_appendix());
1373 par->params().labelString(string());
1376 std::ostringstream s;
1378 if (!par->params().appendix()) {
1379 switch (2 * LABEL_COUNTER_CHAPTER -
1380 textclass.maxcounter() + i) {
1381 case LABEL_COUNTER_CHAPTER:
1382 s << par->getCounter(i);
1384 case LABEL_COUNTER_SECTION:
1385 s << par->getCounter(i - 1) << '.'
1386 << par->getCounter(i);
1388 case LABEL_COUNTER_SUBSECTION:
1389 s << par->getCounter(i - 2) << '.'
1390 << par->getCounter(i - 1) << '.'
1391 << par->getCounter(i);
1393 case LABEL_COUNTER_SUBSUBSECTION:
1394 s << par->getCounter(i - 3) << '.'
1395 << par->getCounter(i - 2) << '.'
1396 << par->getCounter(i - 1) << '.'
1397 << par->getCounter(i);
1400 case LABEL_COUNTER_PARAGRAPH:
1401 s << par->getCounter(i - 4) << '.'
1402 << par->getCounter(i - 3) << '.'
1403 << par->getCounter(i - 2) << '.'
1404 << par->getCounter(i - 1) << '.'
1405 << par->getCounter(i);
1407 case LABEL_COUNTER_SUBPARAGRAPH:
1408 s << par->getCounter(i - 5) << '.'
1409 << par->getCounter(i - 4) << '.'
1410 << par->getCounter(i - 3) << '.'
1411 << par->getCounter(i - 2) << '.'
1412 << par->getCounter(i - 1) << '.'
1413 << par->getCounter(i);
1417 // Can this ever be reached? And in the
1418 // case it is, how can this be correct?
1420 s << par->getCounter(i) << '.';
1423 } else { // appendix
1424 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1425 case LABEL_COUNTER_CHAPTER:
1426 if (par->isRightToLeftPar(buf->params))
1427 s << hebrewCounter(par->getCounter(i));
1429 s << alphaCounter(par->getCounter(i));
1431 case LABEL_COUNTER_SECTION:
1432 if (par->isRightToLeftPar(buf->params))
1433 s << hebrewCounter(par->getCounter(i - 1));
1435 s << alphaCounter(par->getCounter(i - 1));
1438 << par->getCounter(i);
1441 case LABEL_COUNTER_SUBSECTION:
1442 if (par->isRightToLeftPar(buf->params))
1443 s << hebrewCounter(par->getCounter(i - 2));
1445 s << alphaCounter(par->getCounter(i - 2));
1448 << par->getCounter(i-1) << '.'
1449 << par->getCounter(i);
1452 case LABEL_COUNTER_SUBSUBSECTION:
1453 if (par->isRightToLeftPar(buf->params))
1454 s << hebrewCounter(par->getCounter(i-3));
1456 s << alphaCounter(par->getCounter(i-3));
1459 << par->getCounter(i-2) << '.'
1460 << par->getCounter(i-1) << '.'
1461 << par->getCounter(i);
1464 case LABEL_COUNTER_PARAGRAPH:
1465 if (par->isRightToLeftPar(buf->params))
1466 s << hebrewCounter(par->getCounter(i-4));
1468 s << alphaCounter(par->getCounter(i-4));
1471 << par->getCounter(i-3) << '.'
1472 << par->getCounter(i-2) << '.'
1473 << par->getCounter(i-1) << '.'
1474 << par->getCounter(i);
1477 case LABEL_COUNTER_SUBPARAGRAPH:
1478 if (par->isRightToLeftPar(buf->params))
1479 s << hebrewCounter(par->getCounter(i-5));
1481 s << alphaCounter(par->getCounter(i-5));
1484 << par->getCounter(i-4) << '.'
1485 << par->getCounter(i-3) << '.'
1486 << par->getCounter(i-2) << '.'
1487 << par->getCounter(i-1) << '.'
1488 << par->getCounter(i);
1492 // Can this ever be reached? And in the
1493 // case it is, how can this be correct?
1495 s << par->getCounter(i) << '.';
1501 par->params().labelString(par->params().labelString() +s.str().c_str());
1502 // We really want to remove the c_str as soon as
1505 for (i++; i < 10; ++i) {
1506 // reset the following counters
1507 par->setCounter(i, 0);
1509 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1510 for (i++; i < 10; ++i) {
1511 // reset the following counters
1512 par->setCounter(i, 0);
1514 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1515 par->incCounter(i + par->enumdepth);
1516 int number = par->getCounter(i + par->enumdepth);
1518 std::ostringstream s;
1520 switch (par->enumdepth) {
1522 if (par->isRightToLeftPar(buf->params))
1524 << hebrewCounter(number)
1528 << loweralphaCounter(number)
1532 if (par->isRightToLeftPar(buf->params))
1533 s << '.' << romanCounter(number);
1535 s << romanCounter(number) << '.';
1538 if (par->isRightToLeftPar(buf->params))
1540 << alphaCounter(number);
1542 s << alphaCounter(number)
1546 if (par->isRightToLeftPar(buf->params))
1553 par->params().labelString(s.str().c_str());
1554 // we really want to get rid of that c_str()
1556 for (i += par->enumdepth + 1; i < 10; ++i)
1557 par->setCounter(i, 0); /* reset the following counters */
1560 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1561 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1563 int number = par->getCounter(i);
1565 InsetCommandParams p( "bibitem" );
1566 par->bibkey = new InsetBibKey(p);
1568 par->bibkey->setCounter(number);
1569 par->params().labelString(layout.labelstring());
1571 // In biblio should't be following counters but...
1573 string s = layout.labelstring();
1575 // the caption hack:
1576 if (layout.labeltype == LABEL_SENSITIVE) {
1577 bool isOK (par->InInset() && par->InInset()->owner() &&
1578 (par->InInset()->owner()->lyxCode() == Inset::FLOAT_CODE));
1581 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
1583 = floatList.getType(tmp->type());
1584 // We should get the correct number here too.
1585 s = fl.name() + " #:";
1587 /* par->SetLayout(0);
1588 s = layout->labelstring; */
1589 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1590 ? " :úåòîùî øñç" : "Senseless: ";
1593 par->params().labelString(s);
1595 /* reset the enumeration counter. They are always resetted
1596 * when there is any other layout between */
1597 for (int i = 6 + par->enumdepth; i < 10; ++i)
1598 par->setCounter(i, 0);
1603 /* Updates all counters BEHIND the row. Changed paragraphs
1604 * with a dynamic left margin will be rebroken. */
1605 void LyXText::updateCounters(BufferView * bview, Row * row) const
1613 par = row->par()->next();
1617 while (row->par() != par)
1620 setCounter(bview->buffer(), par);
1622 /* now check for the headline layouts. remember that they
1623 * have a dynamic left margin */
1624 if ((textclasslist.Style(bview->buffer()->params.textclass,
1625 par->layout).margintype == MARGIN_DYNAMIC
1626 || textclasslist.Style(bview->buffer()->params.textclass,
1627 par->layout).labeltype == LABEL_SENSITIVE)) {
1629 /* Rebreak the paragraph */
1630 removeParagraph(row);
1631 appendParagraph(bview, row);
1638 /* insets an inset. */
1639 void LyXText::insertInset(BufferView * bview, Inset * inset)
1641 if (!cursor.par()->insertInsetAllowed(inset))
1643 setUndo(bview->buffer(), Undo::INSERT,
1644 cursor.par()->previous(),
1645 cursor.par()->next());
1646 cursor.par()->insertInset(cursor.pos(), inset);
1647 insertChar(bview, Paragraph::META_INSET); /* just to rebreak and refresh correctly.
1648 * The character will not be inserted a
1651 // If we enter a highly editable inset the cursor should be to before
1652 // the inset. This couldn't happen before as Undo was not handled inside
1653 // inset now after the Undo LyX tries to call inset->Edit(...) again
1654 // and cannot do this as the cursor is behind the inset and GetInset
1655 // does not return the inset!
1656 if (inset->editable() == Inset::HIGHLY_EDITABLE) {
1657 cursorLeft(bview, true);
1663 void LyXText::copyEnvironmentType()
1665 copylayouttype = cursor.par()->getLayout();
1669 void LyXText::pasteEnvironmentType(BufferView * bview)
1671 setLayout(bview, copylayouttype);
1675 void LyXText::cutSelection(BufferView * bview, bool doclear)
1677 // Stuff what we got on the clipboard. Even if there is no selection.
1679 // There is a problem with having the stuffing here in that the
1680 // larger the selection the slower LyX will get. This can be
1681 // solved by running the line below only when the selection has
1682 // finished. The solution used currently just works, to make it
1683 // faster we need to be more clever and probably also have more
1684 // calls to stuffClipboard. (Lgb)
1685 bview->stuffClipboard(selectionAsString(bview->buffer()));
1687 // This doesn't make sense, if there is no selection
1688 if (!selection.set())
1691 // OK, we have a selection. This is always between selection.start
1692 // and selection.end
1694 // make sure that the depth behind the selection are restored, too
1695 Paragraph * endpar = selection.end.par()->next();
1696 Paragraph * undoendpar = endpar;
1698 if (endpar && endpar->getDepth()) {
1699 while (endpar && endpar->getDepth()) {
1700 endpar = endpar->next();
1701 undoendpar = endpar;
1703 } else if (endpar) {
1704 endpar = endpar->next(); // because of parindents etc.
1707 setUndo(bview->buffer(), Undo::DELETE,
1708 selection.start.par()->previous(),
1711 // there are two cases: cut only within one paragraph or
1712 // more than one paragraph
1713 if (selection.start.par() == selection.end.par()) {
1714 // only within one paragraph
1715 endpar = selection.end.par();
1716 int pos = selection.end.pos();
1717 CutAndPaste::cutSelection(selection.start.par(), &endpar,
1718 selection.start.pos(), pos,
1719 bview->buffer()->params.textclass, doclear);
1720 selection.end.pos(pos);
1722 endpar = selection.end.par();
1723 int pos = selection.end.pos();
1724 CutAndPaste::cutSelection(selection.start.par(), &endpar,
1725 selection.start.pos(), pos,
1726 bview->buffer()->params.textclass, doclear);
1728 selection.end.par(endpar);
1729 selection.end.pos(pos);
1730 cursor.pos(selection.end.pos());
1732 endpar = endpar->next();
1734 // sometimes necessary
1736 selection.start.par()->stripLeadingSpaces(bview->buffer()->params.textclass);
1738 redoParagraphs(bview, selection.start, endpar);
1740 // cutSelection can invalidate the cursor so we need to set
1742 cursor = selection.start;
1744 // need a valid cursor. (Lgb)
1745 clearSelection(bview);
1747 setCursor(bview, cursor.par(), cursor.pos());
1748 selection.cursor = cursor;
1749 updateCounters(bview, cursor.row());
1753 void LyXText::copySelection(BufferView * bview)
1755 // Stuff what we got on the clipboard. Even if there is no selection.
1757 // There is a problem with having the stuffing here in that the
1758 // larger the selection the slower LyX will get. This can be
1759 // solved by running the line below only when the selection has
1760 // finished. The solution used currently just works, to make it
1761 // faster we need to be more clever and probably also have more
1762 // calls to stuffClipboard. (Lgb)
1763 bview->stuffClipboard(selectionAsString(bview->buffer()));
1765 // this doesnt make sense, if there is no selection
1766 if (!selection.set())
1769 // ok we have a selection. This is always between selection.start
1770 // and sel_end cursor
1772 // copy behind a space if there is one
1773 while (selection.start.par()->size() > selection.start.pos()
1774 && selection.start.par()->isLineSeparator(selection.start.pos())
1775 && (selection.start.par() != selection.end.par()
1776 || selection.start.pos() < selection.end.pos()))
1777 selection.start.pos(selection.start.pos() + 1);
1779 CutAndPaste::copySelection(selection.start.par(), selection.end.par(),
1780 selection.start.pos(), selection.end.pos(),
1781 bview->buffer()->params.textclass);
1785 void LyXText::pasteSelection(BufferView * bview)
1787 // this does not make sense, if there is nothing to paste
1788 if (!CutAndPaste::checkPastePossible(cursor.par()))
1791 setUndo(bview->buffer(), Undo::INSERT,
1792 cursor.par()->previous(),
1793 cursor.par()->next());
1796 Paragraph * actpar = cursor.par();
1798 int pos = cursor.pos();
1799 CutAndPaste::pasteSelection(&actpar, &endpar, pos,
1800 bview->buffer()->params.textclass);
1802 redoParagraphs(bview, cursor, endpar);
1804 setCursor(bview, cursor.par(), cursor.pos());
1805 clearSelection(bview);
1807 selection.cursor = cursor;
1808 setCursor(bview, actpar, pos);
1809 setSelection(bview);
1810 updateCounters(bview, cursor.row());
1814 // returns a pointer to the very first Paragraph
1815 Paragraph * LyXText::firstParagraph() const
1817 return ownerParagraph();
1821 // sets the selection over the number of characters of string, no check!!
1822 void LyXText::setSelectionOverString(BufferView * bview, string const & str)
1827 selection.cursor = cursor;
1828 for (string::size_type i = 0; i < str.length(); ++i)
1830 setSelection(bview);
1834 // simple replacing. The font of the first selected character is used
1835 void LyXText::replaceSelectionWithString(BufferView * bview,
1838 setCursorParUndo(bview->buffer());
1841 if (!selection.set()) { // create a dummy selection
1842 selection.end = cursor;
1843 selection.start = cursor;
1846 // Get font setting before we cut
1847 Paragraph::size_type pos = selection.end.pos();
1848 LyXFont const font = selection.start.par()
1849 ->getFontSettings(bview->buffer()->params,
1850 selection.start.pos());
1852 // Insert the new string
1853 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
1854 selection.end.par()->insertChar(pos, (*cit), font);
1858 // Cut the selection
1859 cutSelection(bview);
1865 // needed to insert the selection
1866 void LyXText::insertStringAsLines(BufferView * bview, string const & str)
1868 Paragraph * par = cursor.par();
1869 Paragraph::size_type pos = cursor.pos();
1870 Paragraph * endpar = cursor.par()->next();
1872 setCursorParUndo(bview->buffer());
1874 bool isEnvironment =
1875 textclasslist.Style(bview->buffer()->params.textclass,
1876 cursor.par()->getLayout()).isEnvironment();
1878 textclasslist.Style(bview->buffer()->params.textclass,
1879 cursor.par()->getLayout()).free_spacing;
1881 textclasslist.Style(bview->buffer()->params.textclass,
1882 cursor.par()->getLayout()).keepempty;
1884 // only to be sure, should not be neccessary
1885 clearSelection(bview);
1887 // insert the string, don't insert doublespace
1888 bool space_inserted = true;
1889 for(string::const_iterator cit = str.begin();
1890 cit != str.end(); ++cit) {
1892 if (par->size() || keepempty) {
1893 par->breakParagraph(bview->buffer()->params,
1894 pos, isEnvironment);
1897 space_inserted = true;
1901 // do not insert consecutive spaces if !free_spacing
1902 } else if ((*cit == ' ' || *cit == '\t')
1903 && space_inserted && !free_spacing) {
1905 } else if (*cit == '\t') {
1906 if (!free_spacing) {
1907 // tabs are like spaces here
1908 par->insertChar(pos, ' ',
1911 space_inserted = true;
1913 const Paragraph::value_type nb = 8 - pos % 8;
1914 for (Paragraph::size_type a = 0;
1916 par->insertChar(pos, ' ',
1920 space_inserted = true;
1922 } else if (!IsPrintable(*cit)) {
1923 // Ignore unprintables
1926 // just insert the character
1927 par->insertChar(pos, *cit, current_font);
1929 space_inserted = (*cit == ' ');
1934 redoParagraphs(bview, cursor, endpar);
1935 setCursor(bview, cursor.par(), cursor.pos());
1936 selection.cursor = cursor;
1937 setCursor(bview, par, pos);
1938 setSelection(bview);
1942 /* turns double-CR to single CR, others where converted into one
1943 blank. Then InsertStringAsLines is called */
1944 void LyXText::insertStringAsParagraphs(BufferView * bview, string const & str)
1946 string linestr(str);
1947 bool newline_inserted = false;
1948 for (string::size_type i = 0; i < linestr.length(); ++i) {
1949 if (linestr[i] == '\n') {
1950 if (newline_inserted) {
1951 // we know that \r will be ignored by
1952 // InsertStringA. Of course, it is a dirty
1953 // trick, but it works...
1954 linestr[i - 1] = '\r';
1958 newline_inserted = true;
1960 } else if (IsPrintable(linestr[i])) {
1961 newline_inserted = false;
1964 insertStringAsLines(bview, linestr);
1968 bool LyXText::gotoNextInset(BufferView * bview,
1969 std::vector<Inset::Code> const & codes,
1970 string const & contents) const
1972 LyXCursor res = cursor;
1975 if (res.pos() < res.par()->size() - 1) {
1976 res.pos(res.pos() + 1);
1978 res.par(res.par()->next());
1982 } while (res.par() &&
1983 !(res.par()->getChar(res.pos()) == Paragraph::META_INSET
1984 && (inset = res.par()->getInset(res.pos())) != 0
1985 && find(codes.begin(), codes.end(), inset->lyxCode())
1987 && (contents.empty() ||
1988 static_cast<InsetCommand *>(res.par()->getInset(res.pos()))->getContents()
1992 setCursor(bview, res.par(), res.pos());
1999 void LyXText::checkParagraph(BufferView * bview, Paragraph * par,
2000 Paragraph::size_type pos)
2002 LyXCursor tmpcursor;
2005 Paragraph::size_type z;
2006 Row * row = getRow(par, pos, y);
2008 // is there a break one row above
2009 if (row->previous() && row->previous()->par() == row->par()) {
2010 z = nextBreakPoint(bview, row->previous(), workWidth(bview));
2011 if (z >= row->pos()) {
2012 // set the dimensions of the row above
2013 y -= row->previous()->height();
2015 refresh_row = row->previous();
2016 status = LyXText::NEED_MORE_REFRESH;
2018 breakAgain(bview, row->previous());
2020 // set the cursor again. Otherwise
2021 // dangling pointers are possible
2022 setCursor(bview, cursor.par(), cursor.pos(),
2023 false, cursor.boundary());
2024 selection.cursor = cursor;
2029 int const tmpheight = row->height();
2030 Paragraph::size_type const tmplast = rowLast(row);
2034 breakAgain(bview, row);
2035 if (row->height() == tmpheight && rowLast(row) == tmplast)
2036 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2038 status = LyXText::NEED_MORE_REFRESH;
2040 // check the special right address boxes
2041 if (textclasslist.Style(bview->buffer()->params.textclass,
2042 par->getLayout()).margintype
2043 == MARGIN_RIGHT_ADDRESS_BOX) {
2050 redoDrawingOfParagraph(bview, tmpcursor);
2053 // set the cursor again. Otherwise dangling pointers are possible
2054 // also set the selection
2056 if (selection.set()) {
2058 setCursorIntern(bview, selection.cursor.par(), selection.cursor.pos(),
2059 false, selection.cursor.boundary());
2060 selection.cursor = cursor;
2061 setCursorIntern(bview, selection.start.par(),
2062 selection.start.pos(),
2063 false, selection.start.boundary());
2064 selection.start = cursor;
2065 setCursorIntern(bview, selection.end.par(),
2066 selection.end.pos(),
2067 false, selection.end.boundary());
2068 selection.end = cursor;
2069 setCursorIntern(bview, last_sel_cursor.par(),
2070 last_sel_cursor.pos(),
2071 false, last_sel_cursor.boundary());
2072 last_sel_cursor = cursor;
2075 setCursorIntern(bview, cursor.par(), cursor.pos(),
2076 false, cursor.boundary());
2080 // returns false if inset wasn't found
2081 bool LyXText::updateInset(BufferView * bview, Inset * inset)
2083 // first check the current paragraph
2084 int pos = cursor.par()->getPositionOfInset(inset);
2086 checkParagraph(bview, cursor.par(), pos);
2090 // check every paragraph
2092 Paragraph * par = firstParagraph();
2094 pos = par->getPositionOfInset(inset);
2096 checkParagraph(bview, par, pos);
2106 void LyXText::setCursor(BufferView * bview, Paragraph * par,
2107 Paragraph::size_type pos,
2108 bool setfont, bool boundary) const
2110 LyXCursor old_cursor = cursor;
2111 setCursorIntern(bview, par, pos, setfont, boundary);
2112 deleteEmptyParagraphMechanism(bview, old_cursor);
2116 void LyXText::setCursor(BufferView *bview, LyXCursor & cur, Paragraph * par,
2117 Paragraph::size_type pos, bool boundary) const
2121 cur.boundary(boundary);
2123 /* get the cursor y position in text */
2125 Row * row = getRow(par, pos, y);
2126 /* y is now the beginning of the cursor row */
2127 y += row->baseline();
2128 /* y is now the cursor baseline */
2131 /* now get the cursors x position */
2133 float fill_separator;
2135 float fill_label_hfill;
2136 prepareToPrint(bview, row, x, fill_separator, fill_hfill,
2138 Paragraph::size_type cursor_vpos = 0;
2139 Paragraph::size_type last = rowLastPrintable(row);
2141 if (pos > last + 1) // This shouldn't happen.
2143 else if (pos < row->pos())
2146 if (last < row->pos())
2147 cursor_vpos = row->pos();
2148 else if (pos > last && !boundary)
2149 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2150 ? row->pos() : last + 1;
2151 else if (pos > row->pos() &&
2152 (pos > last || boundary))
2153 /// Place cursor after char at (logical) position pos - 1
2154 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2155 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2157 /// Place cursor before char at (logical) position pos
2158 cursor_vpos = (bidi_level(pos) % 2 == 0)
2159 ? log2vis(pos) : log2vis(pos) + 1;
2161 Paragraph::size_type main_body =
2162 beginningOfMainBody(bview->buffer(), row->par());
2163 if ((main_body > 0) &&
2164 ((main_body-1 > last) ||
2165 !row->par()->isLineSeparator(main_body-1)))
2168 for (Paragraph::size_type vpos = row->pos();
2169 vpos < cursor_vpos; ++vpos) {
2170 pos = vis2log(vpos);
2171 if (main_body > 0 && pos == main_body - 1) {
2172 x += fill_label_hfill +
2173 lyxfont::width(textclasslist.Style(
2174 bview->buffer()->params.textclass,
2175 row->par()->getLayout())
2177 getFont(bview->buffer(), row->par(), -2));
2178 if (row->par()->isLineSeparator(main_body-1))
2179 x -= singleWidth(bview, row->par(),main_body-1);
2181 if (hfillExpansion(bview->buffer(), row, pos)) {
2182 x += singleWidth(bview, row->par(), pos);
2183 if (pos >= main_body)
2186 x += fill_label_hfill;
2187 } else if (row->par()->isSeparator(pos)) {
2188 x += singleWidth(bview, row->par(), pos);
2189 if (pos >= main_body)
2190 x += fill_separator;
2192 x += singleWidth(bview, row->par(), pos);
2201 void LyXText::setCursorIntern(BufferView * bview, Paragraph * par,
2202 Paragraph::size_type pos,
2203 bool setfont, bool boundary) const
2205 setCursor(bview, cursor, par, pos, boundary);
2207 setCurrentFont(bview);
2211 void LyXText::setCurrentFont(BufferView * bview) const
2213 Paragraph::size_type pos = cursor.pos();
2214 if (cursor.boundary() && pos > 0)
2218 if (pos == cursor.par()->size())
2220 else // potentional bug... BUG (Lgb)
2221 if (cursor.par()->isSeparator(pos)) {
2222 if (pos > cursor.row()->pos() &&
2223 bidi_level(pos) % 2 ==
2224 bidi_level(pos - 1) % 2)
2226 else if (pos + 1 < cursor.par()->size())
2232 cursor.par()->getFontSettings(bview->buffer()->params, pos);
2233 real_current_font = getFont(bview->buffer(), cursor.par(), pos);
2235 if (cursor.pos() == cursor.par()->size() &&
2236 isBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2237 !cursor.boundary()) {
2238 Language const * lang =
2239 cursor.par()->getParLanguage(bview->buffer()->params);
2240 current_font.setLanguage(lang);
2241 current_font.setNumber(LyXFont::OFF);
2242 real_current_font.setLanguage(lang);
2243 real_current_font.setNumber(LyXFont::OFF);
2248 void LyXText::setCursorFromCoordinates(BufferView * bview, int x, int y) const
2250 LyXCursor old_cursor = cursor;
2252 /* get the row first */
2254 Row * row = getRowNearY(y);
2255 cursor.par(row->par());
2258 int column = getColumnNearX(bview, row, x, bound);
2259 cursor.pos(row->pos() + column);
2261 cursor.y(y + row->baseline());
2263 cursor.boundary(bound);
2264 setCurrentFont(bview);
2265 deleteEmptyParagraphMechanism(bview, old_cursor);
2269 void LyXText::setCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2272 /* get the row first */
2274 Row * row = getRowNearY(y);
2276 int column = getColumnNearX(bview, row, x, bound);
2278 cur.par(row->par());
2279 cur.pos(row->pos() + column);
2281 cur.y(y + row->baseline());
2283 cur.boundary(bound);
2287 void LyXText::cursorLeft(BufferView * bview, bool internal) const
2289 if (cursor.pos() > 0) {
2290 bool boundary = cursor.boundary();
2291 setCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2292 if (!internal && !boundary &&
2293 isBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2294 setCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2295 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2296 Paragraph * par = cursor.par()->previous();
2297 setCursor(bview, par, par->size());
2302 void LyXText::cursorRight(BufferView * bview, bool internal) const
2304 if (!internal && cursor.boundary() &&
2305 !cursor.par()->isNewline(cursor.pos()))
2306 setCursor(bview, cursor.par(), cursor.pos(), true, false);
2307 else if (cursor.pos() < cursor.par()->size()) {
2308 setCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2310 isBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2311 setCursor(bview, cursor.par(), cursor.pos(), true, true);
2312 } else if (cursor.par()->next())
2313 setCursor(bview, cursor.par()->next(), 0);
2317 void LyXText::cursorUp(BufferView * bview) const
2319 setCursorFromCoordinates(bview, cursor.x_fix(),
2320 cursor.y() - cursor.row()->baseline() - 1);
2324 void LyXText::cursorDown(BufferView * bview) const
2326 setCursorFromCoordinates(bview, cursor.x_fix(),
2327 cursor.y() - cursor.row()->baseline()
2328 + cursor.row()->height() + 1);
2332 void LyXText::cursorUpParagraph(BufferView * bview) const
2334 if (cursor.pos() > 0) {
2335 setCursor(bview, cursor.par(), 0);
2337 else if (cursor.par()->previous()) {
2338 setCursor(bview, cursor.par()->previous(), 0);
2343 void LyXText::cursorDownParagraph(BufferView * bview) const
2345 if (cursor.par()->next()) {
2346 setCursor(bview, cursor.par()->next(), 0);
2348 setCursor(bview, cursor.par(), cursor.par()->size());
2353 void LyXText::deleteEmptyParagraphMechanism(BufferView * bview,
2354 LyXCursor const & old_cursor) const
2356 // Would be wrong to delete anything if we have a selection.
2357 if (selection.set()) return;
2359 // We allow all kinds of "mumbo-jumbo" when freespacing.
2360 if (textclasslist.Style(bview->buffer()->params.textclass,
2361 old_cursor.par()->getLayout()).free_spacing)
2364 bool deleted = false;
2366 /* Ok I'll put some comments here about what is missing.
2367 I have fixed BackSpace (and thus Delete) to not delete
2368 double-spaces automagically. I have also changed Cut,
2369 Copy and Paste to hopefully do some sensible things.
2370 There are still some small problems that can lead to
2371 double spaces stored in the document file or space at
2372 the beginning of paragraphs. This happens if you have
2373 the cursor betwenn to spaces and then save. Or if you
2374 cut and paste and the selection have a space at the
2375 beginning and then save right after the paste. I am
2376 sure none of these are very hard to fix, but I will
2377 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2378 that I can get some feedback. (Lgb)
2381 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2382 // delete the LineSeparator.
2385 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2386 // delete the LineSeparator.
2389 // If the pos around the old_cursor were spaces, delete one of them.
2390 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
2391 // Only if the cursor has really moved
2393 if (old_cursor.pos() > 0
2394 && old_cursor.pos() < old_cursor.par()->size()
2395 && old_cursor.par()->isLineSeparator(old_cursor.pos())
2396 && old_cursor.par()->isLineSeparator(old_cursor.pos() - 1)) {
2397 old_cursor.par()->erase(old_cursor.pos() - 1);
2398 redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2400 if (old_cursor.par() == cursor.par() &&
2401 cursor.pos() > old_cursor.pos()) {
2402 setCursorIntern(bview, cursor.par(),
2405 setCursorIntern(bview, cursor.par(),
2411 // Do not delete empty paragraphs with keepempty set.
2412 if ((textclasslist.Style(bview->buffer()->params.textclass,
2413 old_cursor.par()->getLayout())).keepempty)
2416 LyXCursor tmpcursor;
2418 if (old_cursor.par() != cursor.par()) {
2419 if ((old_cursor.par()->size() == 0
2420 || (old_cursor.par()->size() == 1
2421 && old_cursor.par()->isLineSeparator(0)))) {
2422 // ok, we will delete anything
2424 // make sure that you do not delete any environments
2425 status = LyXText::NEED_MORE_REFRESH;
2428 if (old_cursor.row()->previous()) {
2429 refresh_row = old_cursor.row()->previous();
2430 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2432 cursor = old_cursor; // that undo can restore the right cursor position
2433 Paragraph * endpar = old_cursor.par()->next();
2434 if (endpar && endpar->getDepth()) {
2435 while (endpar && endpar->getDepth()) {
2436 endpar = endpar->next();
2439 setUndo(bview->buffer(), Undo::DELETE,
2440 old_cursor.par()->previous(),
2445 removeRow(old_cursor.row());
2446 if (ownerParagraph() == old_cursor.par()) {
2447 ownerParagraph(ownerParagraph()->next());
2450 delete old_cursor.par();
2452 /* Breakagain the next par. Needed
2453 * because of the parindent that
2454 * can occur or dissappear. The
2455 * next row can change its height,
2456 * if there is another layout before */
2457 if (refresh_row->next()) {
2458 breakAgain(bview, refresh_row->next());
2459 updateCounters(bview, refresh_row);
2461 setHeightOfRow(bview, refresh_row);
2463 refresh_row = old_cursor.row()->next();
2464 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2467 cursor = old_cursor; // that undo can restore the right cursor position
2468 Paragraph * endpar = old_cursor.par()->next();
2469 if (endpar && endpar->getDepth()) {
2470 while (endpar && endpar->getDepth()) {
2471 endpar = endpar->next();
2474 setUndo(bview->buffer(), Undo::DELETE,
2475 old_cursor.par()->previous(),
2480 removeRow(old_cursor.row());
2482 if (ownerParagraph() == old_cursor.par()) {
2483 ownerParagraph(ownerParagraph()->next());
2486 delete old_cursor.par();
2488 /* Breakagain the next par. Needed
2489 because of the parindent that can
2490 occur or dissappear.
2491 The next row can change its height,
2492 if there is another layout before
2495 breakAgain(bview, refresh_row);
2496 updateCounters(bview, refresh_row->previous());
2502 setCursorIntern(bview, cursor.par(), cursor.pos());
2504 if (selection.cursor.par() == old_cursor.par()
2505 && selection.cursor.pos() == selection.cursor.pos()) {
2506 // correct selection
2507 selection.cursor = cursor;
2511 if (old_cursor.par()->stripLeadingSpaces(bview->buffer()->params.textclass)) {
2512 redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2514 setCursorIntern(bview, cursor.par(), cursor.pos());
2515 selection.cursor = cursor;
2522 Paragraph * LyXText::getParFromID(int id)
2524 Paragraph * result = firstParagraph();
2525 while (result && result->id() != id)
2526 result = result->next();
2532 bool LyXText::textUndo(BufferView * bview)
2536 // returns false if no undo possible
2537 Undo * undo = bview->buffer()->undostack.pop();
2541 bview->buffer()->redostack
2542 .push(createUndo(bview->buffer(), undo->kind,
2543 getParFromID(undo->number_of_before_par),
2544 getParFromID(undo->number_of_behind_par)));
2546 return textHandleUndo(bview, undo);
2550 bool LyXText::textRedo(BufferView * bview)
2554 // returns false if no redo possible
2555 Undo * undo = bview->buffer()->redostack.pop();
2559 bview->buffer()->undostack
2560 .push(createUndo(bview->buffer(), undo->kind,
2561 getParFromID(undo->number_of_before_par),
2562 getParFromID(undo->number_of_behind_par)));
2564 return textHandleUndo(bview, undo);
2568 bool LyXText::textHandleUndo(BufferView * bview, Undo * undo)
2572 // returns false if no undo possible
2573 bool result = false;
2575 Paragraph * before =
2576 getParFromID(undo->number_of_before_par);
2577 Paragraph * behind =
2578 getParFromID(undo->number_of_behind_par);
2580 Paragraph * tmppar2;
2582 Paragraph * tmppar5;
2584 // if there's no before take the beginning
2585 // of the document for redoing
2587 setCursorIntern(bview, firstParagraph(), 0);
2589 // replace the paragraphs with the undo informations
2591 Paragraph * tmppar3 = undo->par;
2592 undo->par = 0; // otherwise the undo destructor would delete the paragraph
2593 Paragraph * tmppar4 = tmppar3;
2596 while (tmppar4->next())
2597 tmppar4 = tmppar4->next();
2598 } // get last undo par
2600 // now remove the old text if there is any
2601 if (before != behind || (!behind && !before)) {
2603 tmppar5 = before->next();
2605 tmppar5 = ownerParagraph();
2607 while (tmppar5 && tmppar5 != behind) {
2609 tmppar5 = tmppar5->next();
2610 // a memory optimization for edit: Only layout information
2611 // is stored in the undo. So restore the text informations.
2612 if (undo->kind == Undo::EDIT) {
2613 tmppar2->setContentsFromPar(tmppar);
2614 tmppar->clearContents();
2615 tmppar2 = tmppar2->next();
2620 // put the new stuff in the list if there is one
2623 before->next(tmppar3);
2625 ownerParagraph(tmppar3);
2626 tmppar3->previous(before);
2629 ownerParagraph(behind);
2632 tmppar4->next(behind);
2634 behind->previous(tmppar4);
2638 // Set the cursor for redoing
2640 setCursorIntern(bview, before, 0);
2643 // calculate the endpar for redoing the paragraphs.
2645 endpar = behind->next();
2649 tmppar = getParFromID(undo->number_of_cursor_par);
2650 redoParagraphs(bview, cursor, endpar);
2652 setCursorIntern(bview, tmppar, undo->cursor_pos);
2653 updateCounters(bview, cursor.row());
2663 void LyXText::finishUndo()
2667 // makes sure the next operation will be stored
2668 undo_finished = true;
2672 void LyXText::freezeUndo()
2676 // this is dangerous and for internal use only
2681 void LyXText::unFreezeUndo()
2685 // this is dangerous and for internal use only
2686 undo_frozen = false;
2690 void LyXText::setUndo(Buffer * buf, Undo::undo_kind kind,
2691 Paragraph const * before,
2692 Paragraph const * behind) const
2697 buf->undostack.push(createUndo(buf, kind, before, behind));
2698 buf->redostack.clear();
2702 void LyXText::setRedo(Buffer * buf, Undo::undo_kind kind,
2703 Paragraph const * before, Paragraph const * behind)
2707 buf->redostack.push(createUndo(buf, kind, before, behind));
2711 Undo * LyXText::createUndo(Buffer * buf, Undo::undo_kind kind,
2712 Paragraph const * before,
2713 Paragraph const * behind) const
2718 int before_number = -1;
2719 int behind_number = -1;
2721 before_number = before->id();
2723 behind_number = behind->id();
2724 // Undo::EDIT and Undo::FINISH are
2725 // always finished. (no overlapping there)
2726 // overlapping only with insert and delete inside one paragraph:
2727 // Nobody wants all removed character
2728 // appear one by one when undoing.
2729 // EDIT is special since only layout information, not the
2730 // contents of a paragaph are stored.
2731 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
2732 // check wether storing is needed
2733 if (!buf->undostack.empty() &&
2734 buf->undostack.top()->kind == kind &&
2735 buf->undostack.top()->number_of_before_par == before_number &&
2736 buf->undostack.top()->number_of_behind_par == behind_number ){
2741 // create a new Undo
2742 Paragraph * undopar;
2744 Paragraph * start = 0;
2745 Paragraph * end = 0;
2748 start = const_cast<Paragraph*>(before->next());
2750 start = firstParagraph();
2752 end = const_cast<Paragraph*>(behind->previous());
2754 end = firstParagraph();
2758 if (start && end && (start != end->next()) &&
2759 ((before != behind) || (!before && !behind))) {
2760 Paragraph * tmppar = start;
2761 Paragraph * tmppar2 = new Paragraph(*tmppar);
2762 tmppar2->id(tmppar->id());
2764 // a memory optimization: Just store the layout information
2766 if (kind == Undo::EDIT){
2767 //tmppar2->text.clear();
2768 tmppar2->clearContents();
2773 while (tmppar != end && tmppar->next()) {
2774 tmppar = tmppar->next();
2775 tmppar2->next(new Paragraph(*tmppar));
2776 tmppar2->next()->id(tmppar->id());
2777 // a memory optimization: Just store the layout
2778 // information when only edit
2779 if (kind == Undo::EDIT){
2780 //tmppar2->next->text.clear();
2781 tmppar2->clearContents();
2783 tmppar2->next()->previous(tmppar2);
2784 tmppar2 = tmppar2->next();
2788 undopar = 0; // nothing to replace (undo of delete maybe)
2790 int cursor_par = cursor.par()->id();
2791 int cursor_pos = cursor.pos();
2793 Undo * undo = new Undo(kind,
2794 before_number, behind_number,
2795 cursor_par, cursor_pos,
2798 undo_finished = false;
2803 void LyXText::setCursorParUndo(Buffer * buf)
2807 setUndo(buf, Undo::FINISH,
2808 cursor.par()->previous(),
2809 cursor.par()->next());
2813 void LyXText::toggleAppendix(BufferView * bview)
2815 Paragraph * par = cursor.par();
2816 bool start = !par->params().startOfAppendix();
2818 // ensure that we have only one start_of_appendix in this document
2819 Paragraph * tmp = firstParagraph();
2820 for (; tmp; tmp = tmp->next())
2821 tmp->params().startOfAppendix(false);
2823 par->params().startOfAppendix(start);
2825 // we can set the refreshing parameters now
2826 status = LyXText::NEED_MORE_REFRESH;
2828 refresh_row = 0; // not needed for full update
2829 updateCounters(bview, 0);
2830 setCursor(bview, cursor.par(), cursor.pos());
2834 Paragraph * LyXText::ownerParagraph() const
2837 return inset_owner->par;
2839 return bv_owner->buffer()->paragraph;
2843 Paragraph * LyXText::ownerParagraph(Paragraph * p) const
2846 inset_owner->par = p;
2848 bv_owner->buffer()->paragraph = p;