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(),
1713 // there are two cases: cut only within one paragraph or
1714 // more than one paragraph
1715 if (selection.start.par() == selection.end.par()) {
1716 // only within one paragraph
1717 endpar = selection.end.par();
1718 int pos = selection.end.pos();
1719 cap.cutSelection(selection.start.par(), &endpar,
1720 selection.start.pos(), pos,
1721 bview->buffer()->params.textclass, doclear);
1722 selection.end.pos(pos);
1724 endpar = selection.end.par();
1725 int pos = selection.end.pos();
1726 cap.cutSelection(selection.start.par(), &endpar,
1727 selection.start.pos(), pos,
1728 bview->buffer()->params.textclass, doclear);
1730 selection.end.par(endpar);
1731 selection.end.pos(pos);
1732 cursor.pos(selection.end.pos());
1734 endpar = endpar->next();
1736 // sometimes necessary
1738 selection.start.par()->stripLeadingSpaces(bview->buffer()->params.textclass);
1740 redoParagraphs(bview, selection.start, endpar);
1742 // cutSelection can invalidate the cursor so we need to set
1744 cursor = selection.start;
1746 // need a valid cursor. (Lgb)
1747 clearSelection(bview);
1749 setCursor(bview, cursor.par(), cursor.pos());
1750 selection.cursor = cursor;
1751 updateCounters(bview, cursor.row());
1755 void LyXText::copySelection(BufferView * bview)
1757 // Stuff what we got on the clipboard. Even if there is no selection.
1759 // There is a problem with having the stuffing here in that the
1760 // larger the selection the slower LyX will get. This can be
1761 // solved by running the line below only when the selection has
1762 // finished. The solution used currently just works, to make it
1763 // faster we need to be more clever and probably also have more
1764 // calls to stuffClipboard. (Lgb)
1765 bview->stuffClipboard(selectionAsString(bview->buffer()));
1767 // this doesnt make sense, if there is no selection
1768 if (!selection.set())
1771 // ok we have a selection. This is always between selection.start
1772 // and sel_end cursor
1774 // copy behind a space if there is one
1775 while (selection.start.par()->size() > selection.start.pos()
1776 && selection.start.par()->isLineSeparator(selection.start.pos())
1777 && (selection.start.par() != selection.end.par()
1778 || selection.start.pos() < selection.end.pos()))
1779 selection.start.pos(selection.start.pos() + 1);
1783 cap.copySelection(selection.start.par(), selection.end.par(),
1784 selection.start.pos(), selection.end.pos(),
1785 bview->buffer()->params.textclass);
1789 void LyXText::pasteSelection(BufferView * bview)
1793 // this does not make sense, if there is nothing to paste
1794 if (!cap.checkPastePossible(cursor.par()))
1797 setUndo(bview->buffer(), Undo::INSERT,
1798 cursor.par()->previous(),
1799 cursor.par()->next());
1802 Paragraph * actpar = cursor.par();
1804 int pos = cursor.pos();
1805 cap.pasteSelection(&actpar, &endpar, pos,
1806 bview->buffer()->params.textclass);
1808 redoParagraphs(bview, cursor, endpar);
1810 setCursor(bview, cursor.par(), cursor.pos());
1811 clearSelection(bview);
1813 selection.cursor = cursor;
1814 setCursor(bview, actpar, pos);
1815 setSelection(bview);
1816 updateCounters(bview, cursor.row());
1820 // returns a pointer to the very first Paragraph
1821 Paragraph * LyXText::firstParagraph() const
1823 return ownerParagraph();
1827 // sets the selection over the number of characters of string, no check!!
1828 void LyXText::setSelectionOverString(BufferView * bview, string const & str)
1833 selection.cursor = cursor;
1834 for (string::size_type i = 0; i < str.length(); ++i)
1836 setSelection(bview);
1840 // simple replacing. The font of the first selected character is used
1841 void LyXText::replaceSelectionWithString(BufferView * bview,
1844 setCursorParUndo(bview->buffer());
1847 if (!selection.set()) { // create a dummy selection
1848 selection.end = cursor;
1849 selection.start = cursor;
1852 // Get font setting before we cut
1853 Paragraph::size_type pos = selection.end.pos();
1854 LyXFont const font = selection.start.par()
1855 ->getFontSettings(bview->buffer()->params,
1856 selection.start.pos());
1858 // Insert the new string
1859 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
1860 selection.end.par()->insertChar(pos, (*cit), font);
1864 // Cut the selection
1865 cutSelection(bview);
1871 // needed to insert the selection
1872 void LyXText::insertStringAsLines(BufferView * bview, string const & str)
1874 Paragraph * par = cursor.par();
1875 Paragraph::size_type pos = cursor.pos();
1876 Paragraph * endpar = cursor.par()->next();
1878 setCursorParUndo(bview->buffer());
1880 bool isEnvironment =
1881 textclasslist.Style(bview->buffer()->params.textclass,
1882 cursor.par()->getLayout()).isEnvironment();
1884 textclasslist.Style(bview->buffer()->params.textclass,
1885 cursor.par()->getLayout()).free_spacing;
1887 textclasslist.Style(bview->buffer()->params.textclass,
1888 cursor.par()->getLayout()).keepempty;
1890 // only to be sure, should not be neccessary
1891 clearSelection(bview);
1893 // insert the string, don't insert doublespace
1894 bool space_inserted = true;
1895 for(string::const_iterator cit = str.begin();
1896 cit != str.end(); ++cit) {
1898 if (par->size() || keepempty) {
1899 par->breakParagraph(bview->buffer()->params,
1900 pos, isEnvironment);
1903 space_inserted = true;
1907 // do not insert consecutive spaces if !free_spacing
1908 } else if ((*cit == ' ' || *cit == '\t')
1909 && space_inserted && !free_spacing) {
1911 } else if (*cit == '\t') {
1912 if (!free_spacing) {
1913 // tabs are like spaces here
1914 par->insertChar(pos, ' ',
1917 space_inserted = true;
1919 const Paragraph::value_type nb = 8 - pos % 8;
1920 for (Paragraph::size_type a = 0;
1922 par->insertChar(pos, ' ',
1926 space_inserted = true;
1928 } else if (!IsPrintable(*cit)) {
1929 // Ignore unprintables
1932 // just insert the character
1933 par->insertChar(pos, *cit, current_font);
1935 space_inserted = (*cit == ' ');
1940 redoParagraphs(bview, cursor, endpar);
1941 setCursor(bview, cursor.par(), cursor.pos());
1942 selection.cursor = cursor;
1943 setCursor(bview, par, pos);
1944 setSelection(bview);
1948 /* turns double-CR to single CR, others where converted into one
1949 blank. Then InsertStringAsLines is called */
1950 void LyXText::insertStringAsParagraphs(BufferView * bview, string const & str)
1952 string linestr(str);
1953 bool newline_inserted = false;
1954 for (string::size_type i = 0; i < linestr.length(); ++i) {
1955 if (linestr[i] == '\n') {
1956 if (newline_inserted) {
1957 // we know that \r will be ignored by
1958 // InsertStringA. Of course, it is a dirty
1959 // trick, but it works...
1960 linestr[i - 1] = '\r';
1964 newline_inserted = true;
1966 } else if (IsPrintable(linestr[i])) {
1967 newline_inserted = false;
1970 insertStringAsLines(bview, linestr);
1974 bool LyXText::gotoNextInset(BufferView * bview,
1975 std::vector<Inset::Code> const & codes,
1976 string const & contents) const
1978 LyXCursor res = cursor;
1981 if (res.pos() < res.par()->size() - 1) {
1982 res.pos(res.pos() + 1);
1984 res.par(res.par()->next());
1988 } while (res.par() &&
1989 !(res.par()->getChar(res.pos()) == Paragraph::META_INSET
1990 && (inset = res.par()->getInset(res.pos())) != 0
1991 && find(codes.begin(), codes.end(), inset->lyxCode())
1993 && (contents.empty() ||
1994 static_cast<InsetCommand *>(res.par()->getInset(res.pos()))->getContents()
1998 setCursor(bview, res.par(), res.pos());
2005 void LyXText::checkParagraph(BufferView * bview, Paragraph * par,
2006 Paragraph::size_type pos)
2008 LyXCursor tmpcursor;
2011 Paragraph::size_type z;
2012 Row * row = getRow(par, pos, y);
2014 // is there a break one row above
2015 if (row->previous() && row->previous()->par() == row->par()) {
2016 z = nextBreakPoint(bview, row->previous(), workWidth(bview));
2017 if (z >= row->pos()) {
2018 // set the dimensions of the row above
2019 y -= row->previous()->height();
2021 refresh_row = row->previous();
2022 status = LyXText::NEED_MORE_REFRESH;
2024 breakAgain(bview, row->previous());
2026 // set the cursor again. Otherwise
2027 // dangling pointers are possible
2028 setCursor(bview, cursor.par(), cursor.pos(),
2029 false, cursor.boundary());
2030 selection.cursor = cursor;
2035 int const tmpheight = row->height();
2036 Paragraph::size_type const tmplast = rowLast(row);
2040 breakAgain(bview, row);
2041 if (row->height() == tmpheight && rowLast(row) == tmplast)
2042 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2044 status = LyXText::NEED_MORE_REFRESH;
2046 // check the special right address boxes
2047 if (textclasslist.Style(bview->buffer()->params.textclass,
2048 par->getLayout()).margintype
2049 == MARGIN_RIGHT_ADDRESS_BOX) {
2056 redoDrawingOfParagraph(bview, tmpcursor);
2059 // set the cursor again. Otherwise dangling pointers are possible
2060 // also set the selection
2062 if (selection.set()) {
2064 setCursorIntern(bview, selection.cursor.par(), selection.cursor.pos(),
2065 false, selection.cursor.boundary());
2066 selection.cursor = cursor;
2067 setCursorIntern(bview, selection.start.par(),
2068 selection.start.pos(),
2069 false, selection.start.boundary());
2070 selection.start = cursor;
2071 setCursorIntern(bview, selection.end.par(),
2072 selection.end.pos(),
2073 false, selection.end.boundary());
2074 selection.end = cursor;
2075 setCursorIntern(bview, last_sel_cursor.par(),
2076 last_sel_cursor.pos(),
2077 false, last_sel_cursor.boundary());
2078 last_sel_cursor = cursor;
2081 setCursorIntern(bview, cursor.par(), cursor.pos(),
2082 false, cursor.boundary());
2086 // returns false if inset wasn't found
2087 bool LyXText::updateInset(BufferView * bview, Inset * inset)
2089 // first check the current paragraph
2090 int pos = cursor.par()->getPositionOfInset(inset);
2092 checkParagraph(bview, cursor.par(), pos);
2096 // check every paragraph
2098 Paragraph * par = firstParagraph();
2100 pos = par->getPositionOfInset(inset);
2102 checkParagraph(bview, par, pos);
2112 void LyXText::setCursor(BufferView * bview, Paragraph * par,
2113 Paragraph::size_type pos,
2114 bool setfont, bool boundary) const
2116 LyXCursor old_cursor = cursor;
2117 setCursorIntern(bview, par, pos, setfont, boundary);
2118 deleteEmptyParagraphMechanism(bview, old_cursor);
2122 void LyXText::setCursor(BufferView *bview, LyXCursor & cur, Paragraph * par,
2123 Paragraph::size_type pos, bool boundary) const
2127 cur.boundary(boundary);
2129 /* get the cursor y position in text */
2131 Row * row = getRow(par, pos, y);
2132 /* y is now the beginning of the cursor row */
2133 y += row->baseline();
2134 /* y is now the cursor baseline */
2137 /* now get the cursors x position */
2139 float fill_separator;
2141 float fill_label_hfill;
2142 prepareToPrint(bview, row, x, fill_separator, fill_hfill,
2144 Paragraph::size_type cursor_vpos = 0;
2145 Paragraph::size_type last = rowLastPrintable(row);
2147 if (pos > last + 1) // This shouldn't happen.
2149 else if (pos < row->pos())
2152 if (last < row->pos())
2153 cursor_vpos = row->pos();
2154 else if (pos > last && !boundary)
2155 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2156 ? row->pos() : last + 1;
2157 else if (pos > row->pos() &&
2158 (pos > last || boundary))
2159 /// Place cursor after char at (logical) position pos - 1
2160 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2161 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2163 /// Place cursor before char at (logical) position pos
2164 cursor_vpos = (bidi_level(pos) % 2 == 0)
2165 ? log2vis(pos) : log2vis(pos) + 1;
2167 Paragraph::size_type main_body =
2168 beginningOfMainBody(bview->buffer(), row->par());
2169 if ((main_body > 0) &&
2170 ((main_body-1 > last) ||
2171 !row->par()->isLineSeparator(main_body-1)))
2174 for (Paragraph::size_type vpos = row->pos();
2175 vpos < cursor_vpos; ++vpos) {
2176 pos = vis2log(vpos);
2177 if (main_body > 0 && pos == main_body - 1) {
2178 x += fill_label_hfill +
2179 lyxfont::width(textclasslist.Style(
2180 bview->buffer()->params.textclass,
2181 row->par()->getLayout())
2183 getFont(bview->buffer(), row->par(), -2));
2184 if (row->par()->isLineSeparator(main_body-1))
2185 x -= singleWidth(bview, row->par(),main_body-1);
2187 if (hfillExpansion(bview->buffer(), row, pos)) {
2188 x += singleWidth(bview, row->par(), pos);
2189 if (pos >= main_body)
2192 x += fill_label_hfill;
2193 } else if (row->par()->isSeparator(pos)) {
2194 x += singleWidth(bview, row->par(), pos);
2195 if (pos >= main_body)
2196 x += fill_separator;
2198 x += singleWidth(bview, row->par(), pos);
2207 void LyXText::setCursorIntern(BufferView * bview, Paragraph * par,
2208 Paragraph::size_type pos,
2209 bool setfont, bool boundary) const
2211 setCursor(bview, cursor, par, pos, boundary);
2213 setCurrentFont(bview);
2217 void LyXText::setCurrentFont(BufferView * bview) const
2219 Paragraph::size_type pos = cursor.pos();
2220 if (cursor.boundary() && pos > 0)
2224 if (pos == cursor.par()->size())
2226 else // potentional bug... BUG (Lgb)
2227 if (cursor.par()->isSeparator(pos)) {
2228 if (pos > cursor.row()->pos() &&
2229 bidi_level(pos) % 2 ==
2230 bidi_level(pos - 1) % 2)
2232 else if (pos + 1 < cursor.par()->size())
2238 cursor.par()->getFontSettings(bview->buffer()->params, pos);
2239 real_current_font = getFont(bview->buffer(), cursor.par(), pos);
2241 if (cursor.pos() == cursor.par()->size() &&
2242 isBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2243 !cursor.boundary()) {
2244 Language const * lang =
2245 cursor.par()->getParLanguage(bview->buffer()->params);
2246 current_font.setLanguage(lang);
2247 current_font.setNumber(LyXFont::OFF);
2248 real_current_font.setLanguage(lang);
2249 real_current_font.setNumber(LyXFont::OFF);
2254 void LyXText::setCursorFromCoordinates(BufferView * bview, int x, int y) const
2256 LyXCursor old_cursor = cursor;
2258 /* get the row first */
2260 Row * row = getRowNearY(y);
2261 cursor.par(row->par());
2264 int column = getColumnNearX(bview, row, x, bound);
2265 cursor.pos(row->pos() + column);
2267 cursor.y(y + row->baseline());
2269 cursor.boundary(bound);
2270 setCurrentFont(bview);
2271 deleteEmptyParagraphMechanism(bview, old_cursor);
2275 void LyXText::setCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2278 /* get the row first */
2280 Row * row = getRowNearY(y);
2282 int column = getColumnNearX(bview, row, x, bound);
2284 cur.par(row->par());
2285 cur.pos(row->pos() + column);
2287 cur.y(y + row->baseline());
2289 cur.boundary(bound);
2293 void LyXText::cursorLeft(BufferView * bview, bool internal) const
2295 if (cursor.pos() > 0) {
2296 bool boundary = cursor.boundary();
2297 setCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2298 if (!internal && !boundary &&
2299 isBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2300 setCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2301 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2302 Paragraph * par = cursor.par()->previous();
2303 setCursor(bview, par, par->size());
2308 void LyXText::cursorRight(BufferView * bview, bool internal) const
2310 if (!internal && cursor.boundary() &&
2311 !cursor.par()->isNewline(cursor.pos()))
2312 setCursor(bview, cursor.par(), cursor.pos(), true, false);
2313 else if (cursor.pos() < cursor.par()->size()) {
2314 setCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2316 isBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2317 setCursor(bview, cursor.par(), cursor.pos(), true, true);
2318 } else if (cursor.par()->next())
2319 setCursor(bview, cursor.par()->next(), 0);
2323 void LyXText::cursorUp(BufferView * bview) const
2325 setCursorFromCoordinates(bview, cursor.x_fix(),
2326 cursor.y() - cursor.row()->baseline() - 1);
2330 void LyXText::cursorDown(BufferView * bview) const
2332 setCursorFromCoordinates(bview, cursor.x_fix(),
2333 cursor.y() - cursor.row()->baseline()
2334 + cursor.row()->height() + 1);
2338 void LyXText::cursorUpParagraph(BufferView * bview) const
2340 if (cursor.pos() > 0) {
2341 setCursor(bview, cursor.par(), 0);
2343 else if (cursor.par()->previous()) {
2344 setCursor(bview, cursor.par()->previous(), 0);
2349 void LyXText::cursorDownParagraph(BufferView * bview) const
2351 if (cursor.par()->next()) {
2352 setCursor(bview, cursor.par()->next(), 0);
2354 setCursor(bview, cursor.par(), cursor.par()->size());
2359 void LyXText::deleteEmptyParagraphMechanism(BufferView * bview,
2360 LyXCursor const & old_cursor) const
2362 // Would be wrong to delete anything if we have a selection.
2363 if (selection.set()) return;
2365 // We allow all kinds of "mumbo-jumbo" when freespacing.
2366 if (textclasslist.Style(bview->buffer()->params.textclass,
2367 old_cursor.par()->getLayout()).free_spacing)
2370 bool deleted = false;
2372 /* Ok I'll put some comments here about what is missing.
2373 I have fixed BackSpace (and thus Delete) to not delete
2374 double-spaces automagically. I have also changed Cut,
2375 Copy and Paste to hopefully do some sensible things.
2376 There are still some small problems that can lead to
2377 double spaces stored in the document file or space at
2378 the beginning of paragraphs. This happens if you have
2379 the cursor betwenn to spaces and then save. Or if you
2380 cut and paste and the selection have a space at the
2381 beginning and then save right after the paste. I am
2382 sure none of these are very hard to fix, but I will
2383 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2384 that I can get some feedback. (Lgb)
2387 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2388 // delete the LineSeparator.
2391 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2392 // delete the LineSeparator.
2395 // If the pos around the old_cursor were spaces, delete one of them.
2396 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
2397 // Only if the cursor has really moved
2399 if (old_cursor.pos() > 0
2400 && old_cursor.pos() < old_cursor.par()->size()
2401 && old_cursor.par()->isLineSeparator(old_cursor.pos())
2402 && old_cursor.par()->isLineSeparator(old_cursor.pos() - 1)) {
2403 old_cursor.par()->erase(old_cursor.pos() - 1);
2404 redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2406 if (old_cursor.par() == cursor.par() &&
2407 cursor.pos() > old_cursor.pos()) {
2408 setCursorIntern(bview, cursor.par(),
2411 setCursorIntern(bview, cursor.par(),
2417 // Do not delete empty paragraphs with keepempty set.
2418 if ((textclasslist.Style(bview->buffer()->params.textclass,
2419 old_cursor.par()->getLayout())).keepempty)
2422 LyXCursor tmpcursor;
2424 if (old_cursor.par() != cursor.par()) {
2425 if ((old_cursor.par()->size() == 0
2426 || (old_cursor.par()->size() == 1
2427 && old_cursor.par()->isLineSeparator(0)))) {
2428 // ok, we will delete anything
2430 // make sure that you do not delete any environments
2431 status = LyXText::NEED_MORE_REFRESH;
2434 if (old_cursor.row()->previous()) {
2435 refresh_row = old_cursor.row()->previous();
2436 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2438 cursor = old_cursor; // that undo can restore the right cursor position
2439 Paragraph * endpar = old_cursor.par()->next();
2440 if (endpar && endpar->getDepth()) {
2441 while (endpar && endpar->getDepth()) {
2442 endpar = endpar->next();
2445 setUndo(bview->buffer(), Undo::DELETE,
2446 old_cursor.par()->previous(),
2451 removeRow(old_cursor.row());
2452 if (ownerParagraph() == old_cursor.par()) {
2453 ownerParagraph(ownerParagraph()->next());
2456 delete old_cursor.par();
2458 /* Breakagain the next par. Needed
2459 * because of the parindent that
2460 * can occur or dissappear. The
2461 * next row can change its height,
2462 * if there is another layout before */
2463 if (refresh_row->next()) {
2464 breakAgain(bview, refresh_row->next());
2465 updateCounters(bview, refresh_row);
2467 setHeightOfRow(bview, refresh_row);
2469 refresh_row = old_cursor.row()->next();
2470 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2473 cursor = old_cursor; // that undo can restore the right cursor position
2474 Paragraph * endpar = old_cursor.par()->next();
2475 if (endpar && endpar->getDepth()) {
2476 while (endpar && endpar->getDepth()) {
2477 endpar = endpar->next();
2480 setUndo(bview->buffer(), Undo::DELETE,
2481 old_cursor.par()->previous(),
2486 removeRow(old_cursor.row());
2488 if (ownerParagraph() == old_cursor.par()) {
2489 ownerParagraph(ownerParagraph()->next());
2492 delete old_cursor.par();
2494 /* Breakagain the next par. Needed
2495 because of the parindent that can
2496 occur or dissappear.
2497 The next row can change its height,
2498 if there is another layout before
2501 breakAgain(bview, refresh_row);
2502 updateCounters(bview, refresh_row->previous());
2508 setCursorIntern(bview, cursor.par(), cursor.pos());
2510 if (selection.cursor.par() == old_cursor.par()
2511 && selection.cursor.pos() == selection.cursor.pos()) {
2512 // correct selection
2513 selection.cursor = cursor;
2517 if (old_cursor.par()->stripLeadingSpaces(bview->buffer()->params.textclass)) {
2518 redoParagraphs(bview, old_cursor, old_cursor.par()->next());
2520 setCursorIntern(bview, cursor.par(), cursor.pos());
2521 selection.cursor = cursor;
2528 Paragraph * LyXText::getParFromID(int id)
2530 Paragraph * result = firstParagraph();
2531 while (result && result->id() != id)
2532 result = result->next();
2538 bool LyXText::textUndo(BufferView * bview)
2542 // returns false if no undo possible
2543 Undo * undo = bview->buffer()->undostack.pop();
2547 bview->buffer()->redostack
2548 .push(createUndo(bview->buffer(), undo->kind,
2549 getParFromID(undo->number_of_before_par),
2550 getParFromID(undo->number_of_behind_par)));
2552 return textHandleUndo(bview, undo);
2556 bool LyXText::textRedo(BufferView * bview)
2560 // returns false if no redo possible
2561 Undo * undo = bview->buffer()->redostack.pop();
2565 bview->buffer()->undostack
2566 .push(createUndo(bview->buffer(), undo->kind,
2567 getParFromID(undo->number_of_before_par),
2568 getParFromID(undo->number_of_behind_par)));
2570 return textHandleUndo(bview, undo);
2574 bool LyXText::textHandleUndo(BufferView * bview, Undo * undo)
2578 // returns false if no undo possible
2579 bool result = false;
2581 Paragraph * before =
2582 getParFromID(undo->number_of_before_par);
2583 Paragraph * behind =
2584 getParFromID(undo->number_of_behind_par);
2586 Paragraph * tmppar2;
2588 Paragraph * tmppar5;
2590 // if there's no before take the beginning
2591 // of the document for redoing
2593 setCursorIntern(bview, firstParagraph(), 0);
2595 // replace the paragraphs with the undo informations
2597 Paragraph * tmppar3 = undo->par;
2598 undo->par = 0; // otherwise the undo destructor would delete the paragraph
2599 Paragraph * tmppar4 = tmppar3;
2602 while (tmppar4->next())
2603 tmppar4 = tmppar4->next();
2604 } // get last undo par
2606 // now remove the old text if there is any
2607 if (before != behind || (!behind && !before)) {
2609 tmppar5 = before->next();
2611 tmppar5 = ownerParagraph();
2613 while (tmppar5 && tmppar5 != behind) {
2615 tmppar5 = tmppar5->next();
2616 // a memory optimization for edit: Only layout information
2617 // is stored in the undo. So restore the text informations.
2618 if (undo->kind == Undo::EDIT) {
2619 tmppar2->setContentsFromPar(tmppar);
2620 tmppar->clearContents();
2621 tmppar2 = tmppar2->next();
2626 // put the new stuff in the list if there is one
2629 before->next(tmppar3);
2631 ownerParagraph(tmppar3);
2632 tmppar3->previous(before);
2635 ownerParagraph(behind);
2638 tmppar4->next(behind);
2640 behind->previous(tmppar4);
2644 // Set the cursor for redoing
2646 setCursorIntern(bview, before, 0);
2649 // calculate the endpar for redoing the paragraphs.
2651 endpar = behind->next();
2655 tmppar = getParFromID(undo->number_of_cursor_par);
2656 redoParagraphs(bview, cursor, endpar);
2658 setCursorIntern(bview, tmppar, undo->cursor_pos);
2659 updateCounters(bview, cursor.row());
2669 void LyXText::finishUndo()
2673 // makes sure the next operation will be stored
2674 undo_finished = true;
2678 void LyXText::freezeUndo()
2682 // this is dangerous and for internal use only
2687 void LyXText::unFreezeUndo()
2691 // this is dangerous and for internal use only
2692 undo_frozen = false;
2696 void LyXText::setUndo(Buffer * buf, Undo::undo_kind kind,
2697 Paragraph const * before,
2698 Paragraph const * behind) const
2703 buf->undostack.push(createUndo(buf, kind, before, behind));
2704 buf->redostack.clear();
2708 void LyXText::setRedo(Buffer * buf, Undo::undo_kind kind,
2709 Paragraph const * before, Paragraph const * behind)
2713 buf->redostack.push(createUndo(buf, kind, before, behind));
2717 Undo * LyXText::createUndo(Buffer * buf, Undo::undo_kind kind,
2718 Paragraph const * before,
2719 Paragraph const * behind) const
2724 int before_number = -1;
2725 int behind_number = -1;
2727 before_number = before->id();
2729 behind_number = behind->id();
2730 // Undo::EDIT and Undo::FINISH are
2731 // always finished. (no overlapping there)
2732 // overlapping only with insert and delete inside one paragraph:
2733 // Nobody wants all removed character
2734 // appear one by one when undoing.
2735 // EDIT is special since only layout information, not the
2736 // contents of a paragaph are stored.
2737 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
2738 // check wether storing is needed
2739 if (!buf->undostack.empty() &&
2740 buf->undostack.top()->kind == kind &&
2741 buf->undostack.top()->number_of_before_par == before_number &&
2742 buf->undostack.top()->number_of_behind_par == behind_number ){
2747 // create a new Undo
2748 Paragraph * undopar;
2750 Paragraph * start = 0;
2751 Paragraph * end = 0;
2754 start = const_cast<Paragraph*>(before->next());
2756 start = firstParagraph();
2758 end = const_cast<Paragraph*>(behind->previous());
2760 end = firstParagraph();
2764 if (start && end && (start != end->next()) &&
2765 ((before != behind) || (!before && !behind))) {
2766 Paragraph * tmppar = start;
2767 Paragraph * tmppar2 = new Paragraph(*tmppar);
2768 tmppar2->id(tmppar->id());
2770 // a memory optimization: Just store the layout information
2772 if (kind == Undo::EDIT){
2773 //tmppar2->text.clear();
2774 tmppar2->clearContents();
2779 while (tmppar != end && tmppar->next()) {
2780 tmppar = tmppar->next();
2781 tmppar2->next(new Paragraph(*tmppar));
2782 tmppar2->next()->id(tmppar->id());
2783 // a memory optimization: Just store the layout
2784 // information when only edit
2785 if (kind == Undo::EDIT){
2786 //tmppar2->next->text.clear();
2787 tmppar2->clearContents();
2789 tmppar2->next()->previous(tmppar2);
2790 tmppar2 = tmppar2->next();
2794 undopar = 0; // nothing to replace (undo of delete maybe)
2796 int cursor_par = cursor.par()->id();
2797 int cursor_pos = cursor.pos();
2799 Undo * undo = new Undo(kind,
2800 before_number, behind_number,
2801 cursor_par, cursor_pos,
2804 undo_finished = false;
2809 void LyXText::setCursorParUndo(Buffer * buf)
2813 setUndo(buf, Undo::FINISH,
2814 cursor.par()->previous(),
2815 cursor.par()->next());
2819 void LyXText::toggleAppendix(BufferView * bview)
2821 Paragraph * par = cursor.par();
2822 bool start = !par->params().startOfAppendix();
2824 // ensure that we have only one start_of_appendix in this document
2825 Paragraph * tmp = firstParagraph();
2826 for (; tmp; tmp = tmp->next())
2827 tmp->params().startOfAppendix(false);
2829 par->params().startOfAppendix(start);
2831 // we can set the refreshing parameters now
2832 status = LyXText::NEED_MORE_REFRESH;
2834 refresh_row = 0; // not needed for full update
2835 updateCounters(bview, 0);
2836 setCursor(bview, cursor.par(), cursor.pos());
2840 Paragraph * LyXText::ownerParagraph() const
2843 return inset_owner->par;
2845 return bv_owner->buffer()->paragraph;
2849 Paragraph * LyXText::ownerParagraph(Paragraph * p) const
2852 inset_owner->par = p;
2854 bv_owner->buffer()->paragraph = p;