1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 1995 Matthias Ettrich
7 * Copyright 1995-2000 The LyX Team.
9 * ====================================================== */
13 #include FORMS_H_LOCATION
17 #pragma implementation "lyxtext.h"
22 #include "lyxparagraph.h"
23 #include "insets/inseterror.h"
24 #include "insets/insetbib.h"
25 #include "insets/insetspecialchar.h"
26 #include "insets/insettext.h"
27 #include "insets/insetfloat.h"
30 #include "support/textutils.h"
33 #include "bufferparams.h"
34 #include "lyx_gui_misc.h"
36 #include "BufferView.h"
38 #include "CutAndPaste.h"
43 #include "FloatList.h"
53 LyXText::LyXText(BufferView * bv)
61 LyXText::LyXText(InsetText * inset)
71 the_locking_inset = 0;
79 status = LyXText::UNCHANGED;
80 // set cursor at the very top position
81 selection = true; /* these setting is necessary
82 because of the delete-empty-
83 paragraph mechanism in
86 LyXParagraph * par = OwnerParagraph();
87 current_font = GetFont(bv_owner->buffer(), par, 0);
89 InsertParagraph(bv_owner, par, lastrow);
92 SetCursor(bv_owner, firstrow->par(), 0);
94 current_font = LyXFont(LyXFont::ALL_SANE);
100 // no rebreak necessary
103 undo_finished = true;
106 // Default layouttype for copy environment type
110 // Dump all rowinformation:
111 Row * tmprow = firstrow;
112 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
114 lyxerr << tmprow->baseline() << '\t'
115 << tmprow->par << '\t'
116 << tmprow->pos() << '\t'
117 << tmprow->height << '\t'
118 << tmprow->ascent_of_text << '\t'
119 << tmprow->fill << '\n';
120 tmprow = tmprow->next();
127 void LyXText::init(BufferView * bview)
132 LyXParagraph * par = OwnerParagraph();
133 current_font = GetFont(bview->buffer(), par, 0);
135 InsertParagraph(bview, par, lastrow);
138 SetCursorIntern(bview, firstrow->par(), 0);
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 LyXParagraph::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, LyXParagraph * par,
178 LyXParagraph::size_type pos) const
180 LyXLayout const & layout =
181 textclasslist.Style(buf->params.textclass, par->GetLayout());
183 char 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->DepthHook(par_depth - 1);
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(Buffer const * buf, LyXParagraph * par,
251 LyXParagraph::size_type pos,
255 // Let the insets convert their font
256 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
257 if (par->GetInset(pos))
258 font = par->GetInset(pos)->ConvertFont(font);
261 LyXLayout const & layout =
262 textclasslist.Style(buf->params.textclass,
265 // Get concrete layout font to reduce against
268 if (pos < BeginningOfMainBody(buf, par))
269 layoutfont = layout.labelfont;
271 layoutfont = layout.font;
273 // Realize against environment font information
274 if (par->GetDepth()){
275 LyXParagraph * tp = par;
276 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
277 tp = tp->DepthHook(tp->GetDepth()-1);
279 layoutfont.realize(textclasslist.
280 Style(buf->params.textclass,
281 tp->GetLayout()).font);
285 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
287 // Now, reduce font against full layout font
288 font.reduce(layoutfont);
290 par->SetFont(pos, font);
294 /* inserts a new row behind the specified row, increments
295 * the touched counters */
296 void LyXText::InsertRow(Row * row, LyXParagraph * par,
297 LyXParagraph::size_type pos) const
299 Row * tmprow = new Row;
302 tmprow->next(firstrow);
305 tmprow->previous(row);
306 tmprow->next(row->next());
311 tmprow->next()->previous(tmprow);
313 if (tmprow->previous())
314 tmprow->previous()->next(tmprow);
322 ++number_of_rows; // one more row
326 // removes the row and reset the touched counters
327 void LyXText::RemoveRow(Row * row) const
329 /* this must not happen before the currentrow for clear reasons.
330 so the trick is just to set the current row onto the previous
333 GetRow(row->par(), row->pos(), unused_y);
336 row->next()->previous(row->previous());
337 if (!row->previous()) {
338 firstrow = row->next();
340 row->previous()->next(row->next());
343 lastrow = row->previous();
345 height -= row->height(); // the text becomes smaller
348 --number_of_rows; // one row less
352 // remove all following rows of the paragraph of the specified row.
353 void LyXText::RemoveParagraph(Row * row) const
355 LyXParagraph * tmppar = row->par();
359 while (row && row->par() == tmppar) {
360 tmprow = row->next();
367 // insert the specified paragraph behind the specified row
368 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
371 InsertRow(row, par, 0); /* insert a new row, starting
374 SetCounter(bview->buffer(), par); // set the counters
376 // and now append the whole paragraph behind the new row
379 AppendParagraph(bview, firstrow);
381 row->next()->height(0);
382 AppendParagraph(bview, row->next());
387 /* used in setlayout */
388 // Asger is not sure we want to do this...
389 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
393 LyXLayout const & layout =
394 textclasslist.Style(buf->params.textclass, par->GetLayout());
396 LyXFont layoutfont, tmpfont;
397 for (LyXParagraph::size_type pos = 0;
398 pos < par->size(); ++pos) {
399 if (pos < BeginningOfMainBody(buf, par))
400 layoutfont = layout.labelfont;
402 layoutfont = layout.font;
404 tmpfont = par->GetFontSettings(buf->params, pos);
405 tmpfont.reduce(layoutfont);
406 par->SetFont(pos, tmpfont);
411 LyXParagraph * LyXText::SetLayout(BufferView * bview,
412 LyXCursor & cur, LyXCursor & sstart_cur,
413 LyXCursor & send_cur,
414 LyXTextClass::size_type layout)
416 LyXParagraph * endpar = send_cur.par()->next();
417 LyXParagraph * undoendpar = endpar;
419 if (endpar && endpar->GetDepth()) {
420 while (endpar && endpar->GetDepth()) {
421 endpar = endpar->next();
425 endpar = endpar->next(); // because of parindents etc.
428 SetUndo(bview->buffer(), Undo::EDIT,
429 sstart_cur.par()->previous(),
432 /* ok we have a selection. This is always between sstart_cur
433 * and sel_end cursor */
436 LyXLayout const & lyxlayout =
437 textclasslist.Style(bview->buffer()->params.textclass, layout);
439 while (cur.par() != send_cur.par()) {
440 cur.par()->SetLayout(layout);
441 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
442 LyXParagraph * fppar = cur.par();
443 fppar->params.spaceTop(lyxlayout.fill_top ?
444 VSpace(VSpace::VFILL)
445 : VSpace(VSpace::NONE));
446 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
447 VSpace(VSpace::VFILL)
448 : VSpace(VSpace::NONE));
449 if (lyxlayout.margintype == MARGIN_MANUAL)
450 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
451 if (lyxlayout.labeltype != LABEL_BIBLIO
453 delete fppar->bibkey;
456 cur.par(cur.par()->next());
458 cur.par()->SetLayout(layout);
459 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
460 LyXParagraph * fppar = cur.par();
461 fppar->params.spaceTop(lyxlayout.fill_top ?
462 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
463 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
464 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
465 if (lyxlayout.margintype == MARGIN_MANUAL)
466 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
467 if (lyxlayout.labeltype != LABEL_BIBLIO
469 delete fppar->bibkey;
476 // set layout over selection and make a total rebreak of those paragraphs
477 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
479 LyXCursor tmpcursor = cursor; /* store the current cursor */
481 // if there is no selection just set the layout
482 // of the current paragraph */
484 sel_start_cursor = cursor; // dummy selection
485 sel_end_cursor = cursor;
488 endpar = SetLayout(bview, cursor, sel_start_cursor,
489 sel_end_cursor, layout);
490 RedoParagraphs(bview, sel_start_cursor, endpar);
492 // we have to reset the selection, because the
493 // geometry could have changed
494 SetCursor(bview, sel_start_cursor.par(),
495 sel_start_cursor.pos(), false);
497 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
499 UpdateCounters(bview, cursor.row());
500 ClearSelection(bview);
502 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
506 // increment depth over selection and
507 // make a total rebreak of those paragraphs
508 void LyXText::IncDepth(BufferView * bview)
510 // If there is no selection, just use the current paragraph
512 sel_start_cursor = cursor; // dummy selection
513 sel_end_cursor = cursor;
516 // We end at the next paragraph with depth 0
517 LyXParagraph * endpar = sel_end_cursor.par()->next();
519 LyXParagraph * undoendpar = endpar;
521 if (endpar && endpar->GetDepth()) {
522 while (endpar && endpar->GetDepth()) {
523 endpar = endpar->next();
528 endpar = endpar->next(); // because of parindents etc.
531 SetUndo(bview->buffer(), Undo::EDIT,
532 sel_start_cursor.par()->previous(),
535 LyXCursor tmpcursor = cursor; // store the current cursor
537 // ok we have a selection. This is always between sel_start_cursor
538 // and sel_end cursor
539 cursor = sel_start_cursor;
541 bool anything_changed = false;
544 // NOTE: you can't change the depth of a bibliography entry
546 textclasslist.Style(bview->buffer()->params.textclass,
547 cursor.par()->GetLayout()
548 ).labeltype != LABEL_BIBLIO) {
549 LyXParagraph * prev = cursor.par()->previous();
552 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
553 || (prev->GetDepth() == cursor.par()->GetDepth()
554 && textclasslist.Style(bview->buffer()->params.textclass,
555 prev->GetLayout()).isEnvironment()))) {
556 cursor.par()->params.depth(cursor.par()->params.depth() + 1);
557 anything_changed = true;
560 if (cursor.par() == sel_end_cursor.par())
562 cursor.par(cursor.par()->next());
565 // if nothing changed set all depth to 0
566 if (!anything_changed) {
567 cursor = sel_start_cursor;
568 while (cursor.par() != sel_end_cursor.par()) {
569 cursor.par()->params.depth(0);
570 cursor.par(cursor.par()->next());
572 cursor.par()->params.depth(0);
575 RedoParagraphs(bview, sel_start_cursor, endpar);
577 // we have to reset the selection, because the
578 // geometry could have changed
579 SetCursor(bview, sel_start_cursor.par(),
580 sel_start_cursor.pos());
582 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
583 UpdateCounters(bview, cursor.row());
584 ClearSelection(bview);
586 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
590 // decrement depth over selection and
591 // make a total rebreak of those paragraphs
592 void LyXText::DecDepth(BufferView * bview)
594 // if there is no selection just set the layout
595 // of the current paragraph
597 sel_start_cursor = cursor; // dummy selection
598 sel_end_cursor = cursor;
600 LyXParagraph * endpar = sel_end_cursor.par()->next();
601 LyXParagraph * undoendpar = endpar;
603 if (endpar && endpar->GetDepth()) {
604 while (endpar && endpar->GetDepth()) {
605 endpar = endpar->next();
610 endpar = endpar->next(); // because of parindents etc.
613 SetUndo(bview->buffer(), Undo::EDIT,
614 sel_start_cursor.par()->previous(),
617 LyXCursor tmpcursor = cursor; // store the current cursor
619 // ok we have a selection. This is always between sel_start_cursor
620 // and sel_end cursor
621 cursor = sel_start_cursor;
624 if (cursor.par()->params.depth())
625 cursor.par()->params.depth(cursor.par()->params.depth() - 1);
626 if (cursor.par() == sel_end_cursor.par())
628 cursor.par(cursor.par()->next());
631 RedoParagraphs(bview, sel_start_cursor, endpar);
633 // we have to reset the selection, because the
634 // geometry could have changed
635 SetCursor(bview, sel_start_cursor.par(),
636 sel_start_cursor.pos());
638 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
639 UpdateCounters(bview, cursor.row());
640 ClearSelection(bview);
642 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
646 // set font over selection and make a total rebreak of those paragraphs
647 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
649 // if there is no selection just set the current_font
651 // Determine basis font
653 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
655 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
657 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
658 // Update current font
659 real_current_font.update(font,
660 bview->buffer()->params.language,
663 // Reduce to implicit settings
664 current_font = real_current_font;
665 current_font.reduce(layoutfont);
666 // And resolve it completely
667 real_current_font.realize(layoutfont);
671 LyXCursor tmpcursor = cursor; // store the current cursor
673 // ok we have a selection. This is always between sel_start_cursor
674 // and sel_end cursor
676 SetUndo(bview->buffer(), Undo::EDIT,
677 sel_start_cursor.par()->previous(),
678 sel_end_cursor.par()->next());
679 cursor = sel_start_cursor;
680 while (cursor.par() != sel_end_cursor.par() ||
681 (cursor.pos() < sel_end_cursor.pos())) {
682 if (cursor.pos() < cursor.par()->size()) {
683 // an open footnote should behave
685 LyXFont newfont = GetFont(bview->buffer(),
686 cursor.par(), cursor.pos());
688 bview->buffer()->params.language,
690 SetCharFont(bview->buffer(),
691 cursor.par(), cursor.pos(), newfont);
692 cursor.pos(cursor.pos() + 1);
695 cursor.par(cursor.par()->next());
699 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->next());
701 // we have to reset the selection, because the
702 // geometry could have changed
703 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
705 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
706 ClearSelection(bview);
708 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
709 tmpcursor.boundary());
713 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
715 Row * tmprow = cur.row();
716 int y = cur.y() - tmprow->baseline();
718 SetHeightOfRow(bview, tmprow);
719 LyXParagraph * first_phys_par = tmprow->par();
721 // find the first row of the paragraph
722 if (first_phys_par != tmprow->par())
723 while (tmprow->previous()
724 && tmprow->previous()->par() != first_phys_par) {
725 tmprow = tmprow->previous();
726 y -= tmprow->height();
727 SetHeightOfRow(bview, tmprow);
729 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
730 tmprow = tmprow->previous();
731 y -= tmprow->height();
732 SetHeightOfRow(bview, tmprow);
735 // we can set the refreshing parameters now
736 status = LyXText::NEED_MORE_REFRESH;
738 refresh_row = tmprow;
739 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
743 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
745 Row * tmprow = cur.row();
747 int y = cur.y() - tmprow->baseline();
748 SetHeightOfRow(bview, tmprow);
749 LyXParagraph * first_phys_par = tmprow->par();
751 // find the first row of the paragraph
752 if (first_phys_par != tmprow->par())
753 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
754 tmprow = tmprow->previous();
755 y -= tmprow->height();
757 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
758 tmprow = tmprow->previous();
759 y -= tmprow->height();
762 // we can set the refreshing parameters now
763 if (status == LyXText::UNCHANGED || y < refresh_y) {
765 refresh_row = tmprow;
767 status = LyXText::NEED_MORE_REFRESH;
768 SetCursor(bview, cur.par(), cur.pos());
772 /* deletes and inserts again all paragaphs between the cursor
773 * and the specified par
774 * This function is needed after SetLayout and SetFont etc. */
775 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
776 LyXParagraph const * endpar) const
779 LyXParagraph * tmppar = 0, * first_phys_par = 0;
781 Row * tmprow = cur.row();
783 int y = cur.y() - tmprow->baseline();
785 if (!tmprow->previous()){
786 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
788 first_phys_par = tmprow->par();
789 // find the first row of the paragraph
790 if (first_phys_par != tmprow->par())
791 while (tmprow->previous() &&
792 (tmprow->previous()->par() != first_phys_par)) {
793 tmprow = tmprow->previous();
794 y -= tmprow->height();
796 while (tmprow->previous()
797 && tmprow->previous()->par() == first_phys_par) {
798 tmprow = tmprow->previous();
799 y -= tmprow->height();
803 // we can set the refreshing parameters now
804 status = LyXText::NEED_MORE_REFRESH;
806 refresh_row = tmprow->previous(); /* the real refresh row will
807 be deleted, so I store
811 tmppar = tmprow->next()->par();
814 while (tmppar != endpar) {
815 RemoveRow(tmprow->next());
817 tmppar = tmprow->next()->par();
822 // remove the first one
823 tmprow2 = tmprow; /* this is because tmprow->previous()
825 tmprow = tmprow->previous();
828 tmppar = first_phys_par;
832 InsertParagraph(bview, tmppar, tmprow);
835 while (tmprow->next() && tmprow->next()->par() == tmppar)
836 tmprow = tmprow->next();
837 tmppar = tmppar->next();
839 } while (tmppar != endpar);
841 // this is because of layout changes
843 refresh_y -= refresh_row->height();
844 SetHeightOfRow(bview, refresh_row);
846 refresh_row = firstrow;
848 SetHeightOfRow(bview, refresh_row);
851 if (tmprow && tmprow->next())
852 SetHeightOfRow(bview, tmprow->next());
856 bool LyXText::FullRebreak(BufferView * bview)
862 if (need_break_row) {
863 BreakAgain(bview, need_break_row);
871 /* important for the screen */
874 /* the cursor set functions have a special mechanism. When they
875 * realize, that you left an empty paragraph, they will delete it.
876 * They also delete the corresponding row */
878 // need the selection cursor:
879 void LyXText::SetSelection(BufferView * bview)
881 const bool lsel = selection;
884 last_sel_cursor = sel_cursor;
885 sel_start_cursor = sel_cursor;
886 sel_end_cursor = sel_cursor;
891 // first the toggling area
892 if (cursor.y() < last_sel_cursor.y()
893 || (cursor.y() == last_sel_cursor.y()
894 && cursor.x() < last_sel_cursor.x())) {
895 toggle_end_cursor = last_sel_cursor;
896 toggle_cursor = cursor;
898 toggle_end_cursor = cursor;
899 toggle_cursor = last_sel_cursor;
902 last_sel_cursor = cursor;
904 // and now the whole selection
906 if (sel_cursor.par() == cursor.par())
907 if (sel_cursor.pos() < cursor.pos()) {
908 sel_end_cursor = cursor;
909 sel_start_cursor = sel_cursor;
911 sel_end_cursor = sel_cursor;
912 sel_start_cursor = cursor;
914 else if (sel_cursor.y() < cursor.y() ||
915 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
916 sel_end_cursor = cursor;
917 sel_start_cursor = sel_cursor;
920 sel_end_cursor = sel_cursor;
921 sel_start_cursor = cursor;
924 // a selection with no contents is not a selection
925 if (sel_start_cursor.par() == sel_end_cursor.par() &&
926 sel_start_cursor.pos() == sel_end_cursor.pos())
929 if (inset_owner && (selection || lsel))
930 inset_owner->SetUpdateStatus(bview, InsetText::SELECTION);
934 string const LyXText::selectionAsString(Buffer const * buffer) const
936 if (!selection) return string();
939 // Special handling if the whole selection is within one paragraph
940 if (sel_start_cursor.par() == sel_end_cursor.par()) {
941 result += sel_start_cursor.par()->String(buffer,
942 sel_start_cursor.pos(),
943 sel_end_cursor.pos());
947 // The selection spans more than one paragraph
949 // First paragraph in selection
950 result += sel_start_cursor.par()->String(buffer,
951 sel_start_cursor.pos(),
952 sel_start_cursor.par()->size())
955 // The paragraphs in between (if any)
956 LyXCursor tmpcur(sel_start_cursor);
957 tmpcur.par(tmpcur.par()->next());
958 while (tmpcur.par() != sel_end_cursor.par()) {
959 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->size()) + "\n\n";
960 tmpcur.par(tmpcur.par()->next()); // Or NextAfterFootnote??
963 // Last paragraph in selection
964 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
970 void LyXText::ClearSelection(BufferView * /*bview*/) const
977 void LyXText::CursorHome(BufferView * bview) const
979 SetCursor(bview, cursor.par(), cursor.row()->pos());
983 void LyXText::CursorEnd(BufferView * bview) const
985 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
986 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
988 if (cursor.par()->size() &&
989 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
990 || cursor.par()->IsNewline(RowLast(cursor.row()))))
991 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
993 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
998 void LyXText::CursorTop(BufferView * bview) const
1000 while (cursor.par()->previous())
1001 cursor.par(cursor.par()->previous());
1002 SetCursor(bview, cursor.par(), 0);
1006 void LyXText::CursorBottom(BufferView * bview) const
1008 while (cursor.par()->next())
1009 cursor.par(cursor.par()->next());
1010 SetCursor(bview, cursor.par(), cursor.par()->size());
1014 void LyXText::ToggleFree(BufferView * bview,
1015 LyXFont const & font, bool toggleall)
1017 // If the mask is completely neutral, tell user
1018 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1019 // Could only happen with user style
1020 bview->owner()->message(_("No font change defined. Use Character under the Layout menu to define font change."));
1024 // Try implicit word selection
1025 // If there is a change in the language the implicit word selection
1027 LyXCursor resetCursor = cursor;
1028 bool implicitSelection = (font.language() == ignore_language
1029 && font.number() == LyXFont::IGNORE)
1030 ? SelectWordWhenUnderCursor(bview) : false;
1033 SetFont(bview, font, toggleall);
1035 /* Implicit selections are cleared afterwards and cursor is set to the
1036 original position. */
1037 if (implicitSelection) {
1038 ClearSelection(bview);
1039 cursor = resetCursor;
1040 SetCursor(bview, cursor.par(), cursor.pos());
1041 sel_cursor = cursor;
1044 inset_owner->SetUpdateStatus(bview, InsetText::CURSOR_PAR);
1048 LyXParagraph::size_type
1049 LyXText::BeginningOfMainBody(Buffer const * buf,
1050 LyXParagraph const * par) const
1052 if (textclasslist.Style(buf->params.textclass,
1053 par->GetLayout()).labeltype != LABEL_MANUAL)
1056 return par->BeginningOfMainBody();
1060 /* the DTP switches for paragraphs. LyX will store them in the
1061 * first physicla paragraph. When a paragraph is broken, the top settings
1062 * rest, the bottom settings are given to the new one. So I can make shure,
1063 * they do not duplicate themself and you cannnot make dirty things with
1066 void LyXText::SetParagraph(BufferView * bview,
1067 bool line_top, bool line_bottom,
1068 bool pagebreak_top, bool pagebreak_bottom,
1069 VSpace const & space_top,
1070 VSpace const & space_bottom,
1072 string labelwidthstring,
1075 LyXCursor tmpcursor = cursor;
1077 sel_start_cursor = cursor;
1078 sel_end_cursor = cursor;
1081 // make sure that the depth behind the selection are restored, too
1082 LyXParagraph * endpar = sel_end_cursor.par()->next();
1083 LyXParagraph * undoendpar = endpar;
1085 if (endpar && endpar->GetDepth()) {
1086 while (endpar && endpar->GetDepth()) {
1087 endpar = endpar->next();
1088 undoendpar = endpar;
1092 endpar = endpar->next(); // because of parindents etc.
1095 SetUndo(bview->buffer(), Undo::EDIT,
1096 sel_start_cursor.par()->previous(),
1100 LyXParagraph * tmppar = sel_end_cursor.par();
1101 while (tmppar != sel_start_cursor.par()->previous()) {
1102 SetCursor(bview, tmppar, 0);
1103 status = LyXText::NEED_MORE_REFRESH;
1104 refresh_row = cursor.row();
1105 refresh_y = cursor.y() - cursor.row()->baseline();
1106 cursor.par()->params.lineTop(line_top);
1107 cursor.par()->params.lineBottom(line_bottom);
1108 cursor.par()->params.pagebreakTop(pagebreak_top);
1109 cursor.par()->params.pagebreakBottom(pagebreak_bottom);
1110 cursor.par()->params.spaceTop(space_top);
1111 cursor.par()->params.spaceBottom(space_bottom);
1112 // does the layout allow the new alignment?
1113 if (align == LYX_ALIGN_LAYOUT)
1114 align = textclasslist
1115 .Style(bview->buffer()->params.textclass,
1116 cursor.par()->GetLayout()).align;
1117 if (align & textclasslist
1118 .Style(bview->buffer()->params.textclass,
1119 cursor.par()->GetLayout()).alignpossible) {
1120 if (align == textclasslist
1121 .Style(bview->buffer()->params.textclass,
1122 cursor.par()->GetLayout()).align)
1123 cursor.par()->params.align(LYX_ALIGN_LAYOUT);
1125 cursor.par()->params.align(align);
1127 cursor.par()->SetLabelWidthString(labelwidthstring);
1128 cursor.par()->params.noindent(noindent);
1129 tmppar = cursor.par()->previous();
1132 RedoParagraphs(bview, sel_start_cursor, endpar);
1134 ClearSelection(bview);
1135 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1136 sel_cursor = cursor;
1137 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1138 SetSelection(bview);
1139 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1141 bview->updateInset(inset_owner, true);
1145 char loweralphaCounter(int n)
1147 if (n < 1 || n > 26)
1157 char alphaCounter(int n)
1159 if (n < 1 || n > 26)
1167 char hebrewCounter(int n)
1169 static const char hebrew[22] = {
1170 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1171 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1172 '÷', 'ø', 'ù', 'ú'
1174 if (n < 1 || n > 22)
1182 string const romanCounter(int n)
1184 static char const * roman[20] = {
1185 "i", "ii", "iii", "iv", "v",
1186 "vi", "vii", "viii", "ix", "x",
1187 "xi", "xii", "xiii", "xiv", "xv",
1188 "xvi", "xvii", "xviii", "xix", "xx"
1190 if (n < 1 || n > 20)
1199 // set the counter of a paragraph. This includes the labels
1200 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1202 LyXLayout const & layout =
1203 textclasslist.Style(buf->params.textclass,
1206 LyXTextClass const & textclass =
1207 textclasslist.TextClass(buf->params.textclass);
1209 /* copy the prev-counters to this one, unless this is the start of a
1210 footnote or of a bibliography or the very first paragraph */
1212 && !(textclasslist.Style(buf->params.textclass,
1213 par->previous()->GetLayout()
1214 ).labeltype != LABEL_BIBLIO
1215 && layout.labeltype == LABEL_BIBLIO)) {
1216 for (int i = 0; i < 10; ++i) {
1217 par->setCounter(i, par->previous()->GetFirstCounter(i));
1219 par->params.appendix(par->previous()->params.appendix());
1220 if (!par->params.appendix() && par->params.startOfAppendix()) {
1221 par->params.appendix(true);
1222 for (int i = 0; i < 10; ++i) {
1223 par->setCounter(i, 0);
1226 par->enumdepth = par->previous()->enumdepth;
1227 par->itemdepth = par->previous()->itemdepth;
1229 for (int i = 0; i < 10; ++i) {
1230 par->setCounter(i, 0);
1232 par->params.appendix(par->params.startOfAppendix());
1237 /* Maybe we have to increment the enumeration depth.
1238 * BUT, enumeration in a footnote is considered in isolation from its
1239 * surrounding paragraph so don't increment if this is the
1240 * first line of the footnote
1241 * AND, bibliographies can't have their depth changed ie. they
1242 * are always of depth 0
1245 && par->previous()->GetDepth() < par->GetDepth()
1246 && textclasslist.Style(buf->params.textclass,
1247 par->previous()->GetLayout()
1248 ).labeltype == LABEL_COUNTER_ENUMI
1249 && par->enumdepth < 3
1250 && layout.labeltype != LABEL_BIBLIO) {
1254 /* Maybe we have to decrement the enumeration depth, see note above */
1256 && par->previous()->GetDepth() > par->GetDepth()
1257 && layout.labeltype != LABEL_BIBLIO) {
1258 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1259 par->setCounter(6 + par->enumdepth,
1260 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1261 /* reset the counters.
1262 * A depth change is like a breaking layout
1264 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1265 par->setCounter(i, 0);
1268 if (!par->params.labelString().empty()) {
1269 par->params.labelString(string());
1272 if (layout.margintype == MARGIN_MANUAL) {
1273 if (par->params.labelWidthString().empty()) {
1274 par->SetLabelWidthString(layout.labelstring());
1277 par->SetLabelWidthString(string());
1280 /* is it a layout that has an automatic label ? */
1281 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1283 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1284 if (i >= 0 && i<= buf->params.secnumdepth) {
1285 par->incCounter(i); // increment the counter
1287 // Is there a label? Useful for Chapter layout
1288 if (!par->params.appendix()) {
1289 if (!layout.labelstring().empty())
1290 par->params.labelString(layout.labelstring());
1292 par->params.labelString(string());
1294 if (!layout.labelstring_appendix().empty())
1295 par->params.labelString(layout.labelstring_appendix());
1297 par->params.labelString(string());
1300 std::ostringstream s;
1302 if (!par->params.appendix()) {
1303 switch (2 * LABEL_COUNTER_CHAPTER -
1304 textclass.maxcounter() + i) {
1305 case LABEL_COUNTER_CHAPTER:
1306 s << par->getCounter(i);
1308 case LABEL_COUNTER_SECTION:
1309 s << par->getCounter(i - 1) << '.'
1310 << par->getCounter(i);
1312 case LABEL_COUNTER_SUBSECTION:
1313 s << par->getCounter(i - 2) << '.'
1314 << par->getCounter(i - 1) << '.'
1315 << par->getCounter(i);
1317 case LABEL_COUNTER_SUBSUBSECTION:
1318 s << par->getCounter(i - 3) << '.'
1319 << par->getCounter(i - 2) << '.'
1320 << par->getCounter(i - 1) << '.'
1321 << par->getCounter(i);
1324 case LABEL_COUNTER_PARAGRAPH:
1325 s << par->getCounter(i - 4) << '.'
1326 << par->getCounter(i - 3) << '.'
1327 << par->getCounter(i - 2) << '.'
1328 << par->getCounter(i - 1) << '.'
1329 << par->getCounter(i);
1331 case LABEL_COUNTER_SUBPARAGRAPH:
1332 s << par->getCounter(i - 5) << '.'
1333 << par->getCounter(i - 4) << '.'
1334 << par->getCounter(i - 3) << '.'
1335 << par->getCounter(i - 2) << '.'
1336 << par->getCounter(i - 1) << '.'
1337 << par->getCounter(i);
1341 // Can this ever be reached? And in the
1342 // case it is, how can this be correct?
1344 s << par->getCounter(i) << '.';
1347 } else { // appendix
1348 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1349 case LABEL_COUNTER_CHAPTER:
1350 if (par->isRightToLeftPar(buf->params))
1351 s << hebrewCounter(par->getCounter(i));
1353 s << alphaCounter(par->getCounter(i));
1355 case LABEL_COUNTER_SECTION:
1356 if (par->isRightToLeftPar(buf->params))
1357 s << hebrewCounter(par->getCounter(i - 1));
1359 s << alphaCounter(par->getCounter(i - 1));
1362 << par->getCounter(i);
1365 case LABEL_COUNTER_SUBSECTION:
1366 if (par->isRightToLeftPar(buf->params))
1367 s << hebrewCounter(par->getCounter(i - 2));
1369 s << alphaCounter(par->getCounter(i - 2));
1372 << par->getCounter(i-1) << '.'
1373 << par->getCounter(i);
1376 case LABEL_COUNTER_SUBSUBSECTION:
1377 if (par->isRightToLeftPar(buf->params))
1378 s << hebrewCounter(par->getCounter(i-3));
1380 s << alphaCounter(par->getCounter(i-3));
1383 << par->getCounter(i-2) << '.'
1384 << par->getCounter(i-1) << '.'
1385 << par->getCounter(i);
1388 case LABEL_COUNTER_PARAGRAPH:
1389 if (par->isRightToLeftPar(buf->params))
1390 s << hebrewCounter(par->getCounter(i-4));
1392 s << alphaCounter(par->getCounter(i-4));
1395 << par->getCounter(i-3) << '.'
1396 << par->getCounter(i-2) << '.'
1397 << par->getCounter(i-1) << '.'
1398 << par->getCounter(i);
1401 case LABEL_COUNTER_SUBPARAGRAPH:
1402 if (par->isRightToLeftPar(buf->params))
1403 s << hebrewCounter(par->getCounter(i-5));
1405 s << alphaCounter(par->getCounter(i-5));
1408 << par->getCounter(i-4) << '.'
1409 << par->getCounter(i-3) << '.'
1410 << par->getCounter(i-2) << '.'
1411 << par->getCounter(i-1) << '.'
1412 << par->getCounter(i);
1416 // Can this ever be reached? And in the
1417 // case it is, how can this be correct?
1419 s << par->getCounter(i) << '.';
1425 par->params.labelString(par->params.labelString() +s.str().c_str());
1426 // We really want to remove the c_str as soon as
1429 for (i++; i < 10; ++i) {
1430 // reset the following counters
1431 par->setCounter(i, 0);
1433 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1434 for (i++; i < 10; ++i) {
1435 // reset the following counters
1436 par->setCounter(i, 0);
1438 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1439 par->incCounter(i + par->enumdepth);
1440 int number = par->getCounter(i + par->enumdepth);
1442 std::ostringstream s;
1444 switch (par->enumdepth) {
1446 if (par->isRightToLeftPar(buf->params))
1448 << hebrewCounter(number)
1452 << loweralphaCounter(number)
1456 if (par->isRightToLeftPar(buf->params))
1457 s << '.' << romanCounter(number);
1459 s << romanCounter(number) << '.';
1462 if (par->isRightToLeftPar(buf->params))
1464 << alphaCounter(number);
1466 s << alphaCounter(number)
1470 if (par->isRightToLeftPar(buf->params))
1477 par->params.labelString(s.str().c_str());
1478 // we really want to get rid of that c_str()
1480 for (i += par->enumdepth + 1; i < 10; ++i)
1481 par->setCounter(i, 0); /* reset the following counters */
1484 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1485 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1487 int number = par->getCounter(i);
1489 InsetCommandParams p( "bibitem" );
1490 par->bibkey = new InsetBibKey(p);
1492 par->bibkey->setCounter(number);
1493 par->params.labelString(layout.labelstring());
1495 // In biblio should't be following counters but...
1497 string s = layout.labelstring();
1499 // the caption hack:
1500 if (layout.labeltype == LABEL_SENSITIVE) {
1501 bool isOK (par->InInset() && par->InInset()->owner() &&
1502 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
1504 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
1506 = floatList.getType(tmp->type());
1507 // We should get the correct number here too.
1508 s = fl.name() + " #:";
1510 /* par->SetLayout(0);
1511 s = layout->labelstring; */
1512 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1513 ? " :úåòîùî øñç" : "Senseless: ";
1516 par->params.labelString(s);
1518 /* reset the enumeration counter. They are always resetted
1519 * when there is any other layout between */
1520 for (int i = 6 + par->enumdepth; i < 10; ++i)
1521 par->setCounter(i, 0);
1526 /* Updates all counters BEHIND the row. Changed paragraphs
1527 * with a dynamic left margin will be rebroken. */
1528 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1536 par = row->par()->next();
1540 while (row->par() != par)
1543 SetCounter(bview->buffer(), par);
1545 /* now check for the headline layouts. remember that they
1546 * have a dynamic left margin */
1547 if ((textclasslist.Style(bview->buffer()->params.textclass,
1548 par->layout).margintype == MARGIN_DYNAMIC
1549 || textclasslist.Style(bview->buffer()->params.textclass,
1550 par->layout).labeltype == LABEL_SENSITIVE)) {
1552 /* Rebreak the paragraph */
1553 RemoveParagraph(row);
1554 AppendParagraph(bview, row);
1561 /* insets an inset. */
1562 void LyXText::InsertInset(BufferView * bview, Inset * inset)
1564 if (!cursor.par()->InsertInsetAllowed(inset))
1566 SetUndo(bview->buffer(), Undo::INSERT,
1567 cursor.par()->previous(),
1568 cursor.par()->next());
1569 cursor.par()->InsertInset(cursor.pos(), inset);
1570 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
1571 * The character will not be inserted a
1574 // If we enter a highly editable inset the cursor should be to before
1575 // the inset. This couldn't happen before as Undo was not handled inside
1576 // inset now after the Undo LyX tries to call inset->Edit(...) again
1577 // and cannot do this as the cursor is behind the inset and GetInset
1578 // does not return the inset!
1579 if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
1580 CursorLeft(bview, true);
1586 void LyXText::copyEnvironmentType()
1588 copylayouttype = cursor.par()->GetLayout();
1592 void LyXText::pasteEnvironmentType(BufferView * bview)
1594 SetLayout(bview, copylayouttype);
1598 void LyXText::CutSelection(BufferView * bview, bool doclear)
1600 // Stuff what we got on the clipboard. Even if there is no selection.
1602 // There is a problem with having the stuffing here in that the
1603 // larger the selection the slower LyX will get. This can be
1604 // solved by running the line below only when the selection has
1605 // finished. The solution used currently just works, to make it
1606 // faster we need to be more clever and probably also have more
1607 // calls to stuffClipboard. (Lgb)
1608 bview->stuffClipboard(selectionAsString(bview->buffer()));
1610 // This doesn't make sense, if there is no selection
1614 // OK, we have a selection. This is always between sel_start_cursor
1615 // and sel_end_cursor
1617 // make sure that the depth behind the selection are restored, too
1618 LyXParagraph * endpar = sel_end_cursor.par()->next();
1619 LyXParagraph * undoendpar = endpar;
1621 if (endpar && endpar->GetDepth()) {
1622 while (endpar && endpar->GetDepth()) {
1623 endpar = endpar->next();
1624 undoendpar = endpar;
1626 } else if (endpar) {
1627 endpar = endpar->next(); // because of parindents etc.
1630 SetUndo(bview->buffer(), Undo::DELETE,
1631 sel_start_cursor.par()->previous(),
1636 // there are two cases: cut only within one paragraph or
1637 // more than one paragraph
1638 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1639 // only within one paragraph
1640 endpar = sel_start_cursor.par();
1641 int pos = sel_end_cursor.pos();
1642 cap.cutSelection(sel_start_cursor.par(), &endpar,
1643 sel_start_cursor.pos(), pos,
1644 bview->buffer()->params.textclass, doclear);
1645 sel_end_cursor.pos(pos);
1647 endpar = sel_end_cursor.par();
1649 int pos = sel_end_cursor.pos();
1650 cap.cutSelection(sel_start_cursor.par(), &endpar,
1651 sel_start_cursor.pos(), pos,
1652 bview->buffer()->params.textclass, doclear);
1654 sel_end_cursor.par(endpar);
1655 sel_end_cursor.pos(pos);
1656 cursor.pos(sel_end_cursor.pos());
1658 endpar = endpar->next();
1660 // sometimes necessary
1662 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
1664 RedoParagraphs(bview, sel_start_cursor, endpar);
1666 ClearSelection(bview);
1667 cursor = sel_start_cursor;
1668 SetCursor(bview, cursor.par(), cursor.pos());
1669 sel_cursor = cursor;
1670 UpdateCounters(bview, cursor.row());
1674 void LyXText::CopySelection(BufferView * bview)
1676 // Stuff what we got on the clipboard. Even if there is no selection.
1678 // There is a problem with having the stuffing here in that the
1679 // larger the selection the slower LyX will get. This can be
1680 // solved by running the line below only when the selection has
1681 // finished. The solution used currently just works, to make it
1682 // faster we need to be more clever and probably also have more
1683 // calls to stuffClipboard. (Lgb)
1684 bview->stuffClipboard(selectionAsString(bview->buffer()));
1686 // this doesnt make sense, if there is no selection
1690 // ok we have a selection. This is always between sel_start_cursor
1691 // and sel_end cursor
1693 // copy behind a space if there is one
1694 while (sel_start_cursor.par()->size() > sel_start_cursor.pos()
1695 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
1696 && (sel_start_cursor.par() != sel_end_cursor.par()
1697 || sel_start_cursor.pos() < sel_end_cursor.pos()))
1698 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
1702 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
1703 sel_start_cursor.pos(), sel_end_cursor.pos(),
1704 bview->buffer()->params.textclass);
1708 void LyXText::PasteSelection(BufferView * bview)
1712 // this does not make sense, if there is nothing to paste
1713 if (!cap.checkPastePossible(cursor.par()))
1716 SetUndo(bview->buffer(), Undo::INSERT,
1717 cursor.par()->previous(),
1718 cursor.par()->next());
1720 LyXParagraph * endpar;
1721 LyXParagraph * actpar = cursor.par();
1723 int pos = cursor.pos();
1724 cap.pasteSelection(&actpar, &endpar, pos,
1725 bview->buffer()->params.textclass);
1727 RedoParagraphs(bview, cursor, endpar);
1729 SetCursor(bview, cursor.par(), cursor.pos());
1730 ClearSelection(bview);
1732 sel_cursor = cursor;
1733 SetCursor(bview, actpar, pos);
1734 SetSelection(bview);
1735 UpdateCounters(bview, cursor.row());
1739 // returns a pointer to the very first LyXParagraph
1740 LyXParagraph * LyXText::FirstParagraph() const
1742 return OwnerParagraph();
1746 // sets the selection over the number of characters of string, no check!!
1747 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
1749 sel_cursor = cursor;
1750 for (int i = 0; str[i]; ++i)
1752 SetSelection(bview);
1756 // simple replacing. The font of the first selected character is used
1757 void LyXText::ReplaceSelectionWithString(BufferView * bview,
1760 SetCursorParUndo(bview->buffer());
1763 if (!selection) { // create a dummy selection
1764 sel_end_cursor = cursor;
1765 sel_start_cursor = cursor;
1768 // Get font setting before we cut
1769 LyXParagraph::size_type pos = sel_end_cursor.pos();
1770 LyXFont const font = sel_start_cursor.par()
1771 ->GetFontSettings(bview->buffer()->params,
1772 sel_start_cursor.pos());
1774 // Insert the new string
1775 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
1776 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
1780 // Cut the selection
1781 CutSelection(bview);
1787 // needed to insert the selection
1788 void LyXText::InsertStringA(BufferView * bview, string const & str)
1790 LyXParagraph * par = cursor.par();
1791 LyXParagraph::size_type pos = cursor.pos();
1792 LyXParagraph::size_type a = 0;
1793 LyXParagraph * endpar = cursor.par()->next();
1795 SetCursorParUndo(bview->buffer());
1798 textclasslist.Style(bview->buffer()->params.textclass,
1799 cursor.par()->GetLayout()).isEnvironment();
1800 // only to be sure, should not be neccessary
1801 ClearSelection(bview);
1803 // insert the string, don't insert doublespace
1804 string::size_type i = 0;
1805 while (i < str.length()) {
1806 if (str[i] != '\n') {
1808 && i + 1 < str.length() && str[i + 1] != ' '
1809 && pos && par->GetChar(pos - 1)!= ' ') {
1810 par->InsertChar(pos, ' ', current_font);
1812 } else if (str[i] == ' ') {
1813 InsetSpecialChar * new_inset =
1814 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1815 if (par->InsertInsetAllowed(new_inset)) {
1816 par->InsertInset(pos, new_inset,
1822 } else if (str[i] == '\t') {
1823 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
1824 InsetSpecialChar * new_inset =
1825 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1826 if (par->InsertInsetAllowed(new_inset)) {
1827 par->InsertInset(pos, new_inset,
1834 } else if (str[i] != 13 &&
1835 // Ignore unprintables
1836 (str[i] & 127) >= ' ') {
1837 par->InsertChar(pos, str[i], current_font);
1841 if (!par->size()) { // par is empty
1842 InsetSpecialChar * new_inset =
1843 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1844 if (par->InsertInsetAllowed(new_inset)) {
1845 par->InsertInset(pos,
1853 par->BreakParagraph(bview->buffer()->params, pos, flag);
1860 RedoParagraphs(bview, cursor, endpar);
1861 SetCursor(bview, cursor.par(), cursor.pos());
1862 sel_cursor = cursor;
1863 SetCursor(bview, par, pos);
1864 SetSelection(bview);
1868 /* turns double-CR to single CR, others where converted into one blank and 13s
1869 * that are ignored .Double spaces are also converted into one. Spaces at
1870 * the beginning of a paragraph are forbidden. tabs are converted into one
1871 * space. then InsertStringA is called */
1872 void LyXText::InsertStringB(BufferView * bview, string const & s)
1875 string::size_type i = 1;
1876 while (i < str.length()) {
1879 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
1881 if (str[i] == '\n' && i + 1 < str.length()) {
1882 if (str[i + 1] != '\n') {
1883 if (str[i - 1] != ' ')
1888 while (i + 1 < str.length()
1889 && (str[i + 1] == ' '
1890 || str[i + 1] == '\t'
1891 || str[i + 1] == '\n'
1892 || str[i + 1] == 13)) {
1899 InsertStringA(bview, str);
1903 bool LyXText::GotoNextInset(BufferView * bview,
1904 std::vector<Inset::Code> const & codes,
1905 string const & contents) const
1907 LyXCursor res = cursor;
1910 if (res.pos() < res.par()->size() - 1) {
1911 res.pos(res.pos() + 1);
1913 res.par(res.par()->next());
1917 } while (res.par() &&
1918 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
1919 && (inset = res.par()->GetInset(res.pos())) != 0
1920 && find(codes.begin(), codes.end(), inset->LyxCode())
1922 && (contents.empty() ||
1923 static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
1927 SetCursor(bview, res.par(), res.pos());
1934 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
1935 LyXParagraph::size_type pos)
1937 LyXCursor tmpcursor;
1940 LyXParagraph::size_type z;
1941 Row * row = GetRow(par, pos, y);
1943 // is there a break one row above
1944 if (row->previous() && row->previous()->par() == row->par()) {
1945 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
1946 if (z >= row->pos()) {
1947 // set the dimensions of the row above
1948 y -= row->previous()->height();
1950 refresh_row = row->previous();
1951 status = LyXText::NEED_MORE_REFRESH;
1953 BreakAgain(bview, row->previous());
1955 // set the cursor again. Otherwise
1956 // dangling pointers are possible
1957 SetCursor(bview, cursor.par(), cursor.pos(),
1958 false, cursor.boundary());
1959 sel_cursor = cursor;
1964 int const tmpheight = row->height();
1965 LyXParagraph::size_type const tmplast = RowLast(row);
1969 BreakAgain(bview, row);
1970 if (row->height() == tmpheight && RowLast(row) == tmplast)
1971 status = LyXText::NEED_VERY_LITTLE_REFRESH;
1973 status = LyXText::NEED_MORE_REFRESH;
1975 // check the special right address boxes
1976 if (textclasslist.Style(bview->buffer()->params.textclass,
1977 par->GetLayout()).margintype
1978 == MARGIN_RIGHT_ADDRESS_BOX) {
1985 RedoDrawingOfParagraph(bview, tmpcursor);
1988 // set the cursor again. Otherwise dangling pointers are possible
1989 // also set the selection
1993 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
1994 false, sel_cursor.boundary());
1995 sel_cursor = cursor;
1996 SetCursorIntern(bview, sel_start_cursor.par(),
1997 sel_start_cursor.pos(),
1998 false, sel_start_cursor.boundary());
1999 sel_start_cursor = cursor;
2000 SetCursorIntern(bview, sel_end_cursor.par(),
2001 sel_end_cursor.pos(),
2002 false, sel_end_cursor.boundary());
2003 sel_end_cursor = cursor;
2004 SetCursorIntern(bview, last_sel_cursor.par(),
2005 last_sel_cursor.pos(),
2006 false, last_sel_cursor.boundary());
2007 last_sel_cursor = cursor;
2010 SetCursorIntern(bview, cursor.par(), cursor.pos(),
2011 false, cursor.boundary());
2015 // returns false if inset wasn't found
2016 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2018 // first check the current paragraph
2019 int pos = cursor.par()->GetPositionOfInset(inset);
2021 CheckParagraph(bview, cursor.par(), pos);
2025 // check every paragraph
2027 LyXParagraph * par = FirstParagraph();
2029 pos = par->GetPositionOfInset(inset);
2031 CheckParagraph(bview, par, pos);
2041 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2042 LyXParagraph::size_type pos,
2043 bool setfont, bool boundary) const
2045 LyXCursor old_cursor = cursor;
2046 SetCursorIntern(bview, par, pos, setfont, boundary);
2047 DeleteEmptyParagraphMechanism(bview, old_cursor);
2051 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2052 LyXParagraph::size_type pos, bool boundary) const
2056 cur.boundary(boundary);
2058 /* get the cursor y position in text */
2060 Row * row = GetRow(par, pos, y);
2061 /* y is now the beginning of the cursor row */
2062 y += row->baseline();
2063 /* y is now the cursor baseline */
2066 /* now get the cursors x position */
2068 float fill_separator, fill_hfill, fill_label_hfill;
2069 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2071 LyXParagraph::size_type cursor_vpos = 0;
2072 LyXParagraph::size_type last = RowLastPrintable(row);
2074 if (pos > last + 1) // This shouldn't happen.
2076 else if (pos < row->pos())
2079 if (last < row->pos())
2080 cursor_vpos = row->pos();
2081 else if (pos > last && !boundary)
2082 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2083 ? row->pos() : last + 1;
2084 else if (pos > row->pos() &&
2085 (pos > last || boundary))
2086 /// Place cursor after char at (logical) position pos - 1
2087 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2088 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2090 /// Place cursor before char at (logical) position pos
2091 cursor_vpos = (bidi_level(pos) % 2 == 0)
2092 ? log2vis(pos) : log2vis(pos) + 1;
2094 LyXParagraph::size_type main_body =
2095 BeginningOfMainBody(bview->buffer(), row->par());
2096 if ((main_body > 0) &&
2097 ((main_body-1 > last) ||
2098 !row->par()->IsLineSeparator(main_body-1)))
2101 for (LyXParagraph::size_type vpos = row->pos();
2102 vpos < cursor_vpos; ++vpos) {
2103 pos = vis2log(vpos);
2104 if (main_body > 0 && pos == main_body - 1) {
2105 x += fill_label_hfill +
2106 lyxfont::width(textclasslist.Style(
2107 bview->buffer()->params.textclass,
2108 row->par()->GetLayout())
2110 GetFont(bview->buffer(), row->par(), -2));
2111 if (row->par()->IsLineSeparator(main_body-1))
2112 x -= SingleWidth(bview, row->par(),main_body-1);
2114 if (HfillExpansion(bview->buffer(), row, pos)) {
2115 x += SingleWidth(bview, row->par(), pos);
2116 if (pos >= main_body)
2119 x += fill_label_hfill;
2120 } else if (row->par()->IsSeparator(pos)) {
2121 x += SingleWidth(bview, row->par(), pos);
2122 if (pos >= main_body)
2123 x += fill_separator;
2125 x += SingleWidth(bview, row->par(), pos);
2134 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2135 LyXParagraph::size_type pos,
2136 bool setfont, bool boundary) const
2138 SetCursor(bview, cursor, par, pos, boundary);
2140 SetCurrentFont(bview);
2144 void LyXText::SetCurrentFont(BufferView * bview) const
2146 LyXParagraph::size_type pos = cursor.pos();
2147 if (cursor.boundary() && pos > 0)
2151 if (pos == cursor.par()->size())
2153 else if (cursor.par()->IsSeparator(pos)) {
2154 if (pos > cursor.row()->pos() &&
2155 bidi_level(pos) % 2 ==
2156 bidi_level(pos - 1) % 2)
2158 else if (pos + 1 < cursor.par()->size())
2164 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2165 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2167 if (cursor.pos() == cursor.par()->size() &&
2168 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2169 !cursor.boundary()) {
2170 Language const * lang =
2171 cursor.par()->getParLanguage(bview->buffer()->params);
2172 current_font.setLanguage(lang);
2173 current_font.setNumber(LyXFont::OFF);
2174 real_current_font.setLanguage(lang);
2175 real_current_font.setNumber(LyXFont::OFF);
2180 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2182 LyXCursor old_cursor = cursor;
2184 /* get the row first */
2186 Row * row = GetRowNearY(y);
2187 cursor.par(row->par());
2190 int column = GetColumnNearX(bview, row, x, bound);
2191 cursor.pos(row->pos() + column);
2193 cursor.y(y + row->baseline());
2195 cursor.boundary(bound);
2196 SetCurrentFont(bview);
2197 DeleteEmptyParagraphMechanism(bview, old_cursor);
2201 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2204 /* get the row first */
2206 Row * row = GetRowNearY(y);
2208 int column = GetColumnNearX(bview, row, x, bound);
2210 cur.par(row->par());
2211 cur.pos(row->pos() + column);
2213 cur.y(y + row->baseline());
2215 cur.boundary(bound);
2219 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2221 if (cursor.pos() > 0) {
2222 bool boundary = cursor.boundary();
2223 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2224 if (!internal && !boundary &&
2225 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2226 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2227 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2228 LyXParagraph * par = cursor.par()->previous();
2229 SetCursor(bview, par, par->size());
2234 void LyXText::CursorRight(BufferView * bview, bool internal) const
2236 if (!internal && cursor.boundary() &&
2237 !cursor.par()->IsNewline(cursor.pos()))
2238 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2239 else if (cursor.pos() < cursor.par()->size()) {
2240 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2242 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2243 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2244 } else if (cursor.par()->next())
2245 SetCursor(bview, cursor.par()->next(), 0);
2249 void LyXText::CursorUp(BufferView * bview) const
2251 SetCursorFromCoordinates(bview, cursor.x_fix(),
2252 cursor.y() - cursor.row()->baseline() - 1);
2256 void LyXText::CursorDown(BufferView * bview) const
2258 SetCursorFromCoordinates(bview, cursor.x_fix(),
2259 cursor.y() - cursor.row()->baseline()
2260 + cursor.row()->height() + 1);
2264 void LyXText::CursorUpParagraph(BufferView * bview) const
2266 if (cursor.pos() > 0) {
2267 SetCursor(bview, cursor.par(), 0);
2269 else if (cursor.par()->previous()) {
2270 SetCursor(bview, cursor.par()->previous(), 0);
2275 void LyXText::CursorDownParagraph(BufferView * bview) const
2277 if (cursor.par()->next()) {
2278 SetCursor(bview, cursor.par()->next(), 0);
2280 SetCursor(bview, cursor.par(), cursor.par()->size());
2285 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
2286 LyXCursor const & old_cursor) const
2288 // Would be wrong to delete anything if we have a selection.
2289 if (selection) return;
2291 // We allow all kinds of "mumbo-jumbo" when freespacing.
2292 if (textclasslist.Style(bview->buffer()->params.textclass,
2293 old_cursor.par()->GetLayout()).free_spacing)
2296 bool deleted = false;
2298 /* Ok I'll put some comments here about what is missing.
2299 I have fixed BackSpace (and thus Delete) to not delete
2300 double-spaces automagically. I have also changed Cut,
2301 Copy and Paste to hopefully do some sensible things.
2302 There are still some small problems that can lead to
2303 double spaces stored in the document file or space at
2304 the beginning of paragraphs. This happens if you have
2305 the cursor betwenn to spaces and then save. Or if you
2306 cut and paste and the selection have a space at the
2307 beginning and then save right after the paste. I am
2308 sure none of these are very hard to fix, but I will
2309 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2310 that I can get some feedback. (Lgb)
2313 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2314 // delete the LineSeparator.
2317 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2318 // delete the LineSeparator.
2321 // If the pos around the old_cursor were spaces, delete one of them.
2322 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
2323 // Only if the cursor has really moved
2325 if (old_cursor.pos() > 0
2326 && old_cursor.pos() < old_cursor.par()->size()
2327 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
2328 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
2329 old_cursor.par()->Erase(old_cursor.pos() - 1);
2330 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
2332 if (old_cursor.par() == cursor.par() &&
2333 cursor.pos() > old_cursor.pos()) {
2334 SetCursorIntern(bview, cursor.par(),
2337 SetCursorIntern(bview, cursor.par(),
2343 // Do not delete empty paragraphs with keepempty set.
2344 if ((textclasslist.Style(bview->buffer()->params.textclass,
2345 old_cursor.par()->GetLayout())).keepempty)
2348 LyXCursor tmpcursor;
2350 if (old_cursor.par() != cursor.par()) {
2351 if ((old_cursor.par()->size() == 0
2352 || (old_cursor.par()->size() == 1
2353 && old_cursor.par()->IsLineSeparator(0)))) {
2354 // ok, we will delete anything
2356 // make sure that you do not delete any environments
2357 status = LyXText::NEED_MORE_REFRESH;
2360 if (old_cursor.row()->previous()) {
2361 refresh_row = old_cursor.row()->previous();
2362 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2364 cursor = old_cursor; // that undo can restore the right cursor position
2365 LyXParagraph * endpar = old_cursor.par()->next();
2366 if (endpar && endpar->GetDepth()) {
2367 while (endpar && endpar->GetDepth()) {
2368 endpar = endpar->next();
2371 SetUndo(bview->buffer(), Undo::DELETE,
2372 old_cursor.par()->previous(),
2377 RemoveRow(old_cursor.row());
2378 if (OwnerParagraph() == old_cursor.par()) {
2379 OwnerParagraph(OwnerParagraph()->next());
2382 delete old_cursor.par();
2384 /* Breakagain the next par. Needed
2385 * because of the parindent that
2386 * can occur or dissappear. The
2387 * next row can change its height,
2388 * if there is another layout before */
2389 if (refresh_row->next()) {
2390 BreakAgain(bview, refresh_row->next());
2391 UpdateCounters(bview, refresh_row);
2393 SetHeightOfRow(bview, refresh_row);
2395 refresh_row = old_cursor.row()->next();
2396 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2399 cursor = old_cursor; // that undo can restore the right cursor position
2400 LyXParagraph * endpar = old_cursor.par()->next();
2401 if (endpar && endpar->GetDepth()) {
2402 while (endpar && endpar->GetDepth()) {
2403 endpar = endpar->next();
2406 SetUndo(bview->buffer(), Undo::DELETE,
2407 old_cursor.par()->previous(),
2412 RemoveRow(old_cursor.row());
2414 if (OwnerParagraph() == old_cursor.par()) {
2415 OwnerParagraph(OwnerParagraph()->next());
2418 delete old_cursor.par();
2420 /* Breakagain the next par. Needed
2421 because of the parindent that can
2422 occur or dissappear.
2423 The next row can change its height,
2424 if there is another layout before
2427 BreakAgain(bview, refresh_row);
2428 UpdateCounters(bview, refresh_row->previous());
2434 SetCursorIntern(bview, cursor.par(), cursor.pos());
2436 if (sel_cursor.par() == old_cursor.par()
2437 && sel_cursor.pos() == sel_cursor.pos()) {
2438 // correct selection
2439 sel_cursor = cursor;
2443 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
2444 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
2446 SetCursorIntern(bview, cursor.par(), cursor.pos());
2447 sel_cursor = cursor;
2454 LyXParagraph * LyXText::GetParFromID(int id)
2456 LyXParagraph * result = FirstParagraph();
2457 while (result && result->id() != id)
2458 result = result->next();
2464 bool LyXText::TextUndo(BufferView * bview)
2468 // returns false if no undo possible
2469 Undo * undo = bview->buffer()->undostack.pop();
2473 bview->buffer()->redostack
2474 .push(CreateUndo(bview->buffer(), undo->kind,
2475 GetParFromID(undo->number_of_before_par),
2476 GetParFromID(undo->number_of_behind_par)));
2478 return TextHandleUndo(bview, undo);
2482 bool LyXText::TextRedo(BufferView * bview)
2486 // returns false if no redo possible
2487 Undo * undo = bview->buffer()->redostack.pop();
2491 bview->buffer()->undostack
2492 .push(CreateUndo(bview->buffer(), undo->kind,
2493 GetParFromID(undo->number_of_before_par),
2494 GetParFromID(undo->number_of_behind_par)));
2496 return TextHandleUndo(bview, undo);
2500 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
2504 // returns false if no undo possible
2505 bool result = false;
2507 LyXParagraph * before =
2508 GetParFromID(undo->number_of_before_par);
2509 LyXParagraph * behind =
2510 GetParFromID(undo->number_of_behind_par);
2511 LyXParagraph * tmppar;
2512 LyXParagraph * tmppar2;
2513 LyXParagraph * endpar;
2514 LyXParagraph * tmppar5;
2516 // if there's no before take the beginning
2517 // of the document for redoing
2519 SetCursorIntern(bview, FirstParagraph(), 0);
2521 // replace the paragraphs with the undo informations
2523 LyXParagraph * tmppar3 = undo->par;
2524 undo->par = 0; // otherwise the undo destructor would delete the paragraph
2525 LyXParagraph * tmppar4 = tmppar3;
2528 while (tmppar4->next())
2529 tmppar4 = tmppar4->next();
2530 } // get last undo par
2532 // now remove the old text if there is any
2533 if (before != behind || (!behind && !before)) {
2535 tmppar5 = before->next();
2537 tmppar5 = OwnerParagraph();
2539 while (tmppar5 && tmppar5 != behind) {
2541 tmppar5 = tmppar5->next();
2542 // a memory optimization for edit: Only layout information
2543 // is stored in the undo. So restore the text informations.
2544 if (undo->kind == Undo::EDIT) {
2545 tmppar2->setContentsFromPar(tmppar);
2546 tmppar->clearContents();
2547 tmppar2 = tmppar2->next();
2552 // put the new stuff in the list if there is one
2555 before->next(tmppar3);
2557 OwnerParagraph(tmppar3);
2558 tmppar3->previous(before);
2561 OwnerParagraph(behind);
2564 tmppar4->next(behind);
2566 behind->previous(tmppar4);
2570 // Set the cursor for redoing
2572 SetCursorIntern(bview, before, 0);
2575 // calculate the endpar for redoing the paragraphs.
2577 endpar = behind->next();
2581 tmppar = GetParFromID(undo->number_of_cursor_par);
2582 RedoParagraphs(bview, cursor, endpar);
2584 SetCursorIntern(bview, tmppar, undo->cursor_pos);
2585 UpdateCounters(bview, cursor.row());
2595 void LyXText::FinishUndo()
2599 // makes sure the next operation will be stored
2600 undo_finished = true;
2604 void LyXText::FreezeUndo()
2608 // this is dangerous and for internal use only
2613 void LyXText::UnFreezeUndo()
2617 // this is dangerous and for internal use only
2618 undo_frozen = false;
2622 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
2623 LyXParagraph const * before,
2624 LyXParagraph const * behind) const
2629 buf->undostack.push(CreateUndo(buf, kind, before, behind));
2630 buf->redostack.clear();
2634 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
2635 LyXParagraph const * before, LyXParagraph const * behind)
2639 buf->redostack.push(CreateUndo(buf, kind, before, behind));
2643 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
2644 LyXParagraph const * before,
2645 LyXParagraph const * behind) const
2650 int before_number = -1;
2651 int behind_number = -1;
2653 before_number = before->id();
2655 behind_number = behind->id();
2656 // Undo::EDIT and Undo::FINISH are
2657 // always finished. (no overlapping there)
2658 // overlapping only with insert and delete inside one paragraph:
2659 // Nobody wants all removed character
2660 // appear one by one when undoing.
2661 // EDIT is special since only layout information, not the
2662 // contents of a paragaph are stored.
2663 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
2664 // check wether storing is needed
2665 if (!buf->undostack.empty() &&
2666 buf->undostack.top()->kind == kind &&
2667 buf->undostack.top()->number_of_before_par == before_number &&
2668 buf->undostack.top()->number_of_behind_par == behind_number ){
2673 // create a new Undo
2674 LyXParagraph * undopar;
2676 LyXParagraph * start = 0;
2677 LyXParagraph * end = 0;
2680 start = const_cast<LyXParagraph*>(before->next());
2682 start = FirstParagraph();
2684 end = const_cast<LyXParagraph*>(behind->previous());
2686 end = FirstParagraph();
2690 if (start && end && (start != end->next()) &&
2691 ((before != behind) || (!before && !behind))) {
2692 LyXParagraph * tmppar = start;
2694 LyXParagraph * tmppar2 = tmppar->Clone();
2696 LyXParagraph * tmppar2 = new LyXParagraph(*tmppar);
2698 tmppar2->id(tmppar->id());
2700 // a memory optimization: Just store the layout information
2702 if (kind == Undo::EDIT){
2703 //tmppar2->text.clear();
2704 tmppar2->clearContents();
2709 while (tmppar != end && tmppar->next()) {
2710 tmppar = tmppar->next();
2712 tmppar2->next(tmppar->Clone());
2714 tmppar2->next(new LyXParagraph(*tmppar));
2716 tmppar2->next()->id(tmppar->id());
2717 // a memory optimization: Just store the layout
2718 // information when only edit
2719 if (kind == Undo::EDIT){
2720 //tmppar2->next->text.clear();
2721 tmppar2->clearContents();
2723 tmppar2->next()->previous(tmppar2);
2724 tmppar2 = tmppar2->next();
2728 undopar = 0; // nothing to replace (undo of delete maybe)
2730 int cursor_par = cursor.par()->id();
2731 int cursor_pos = cursor.pos();
2733 Undo * undo = new Undo(kind,
2734 before_number, behind_number,
2735 cursor_par, cursor_pos,
2738 undo_finished = false;
2743 void LyXText::SetCursorParUndo(Buffer * buf)
2747 SetUndo(buf, Undo::FINISH,
2748 cursor.par()->previous(),
2749 cursor.par()->next());
2753 void LyXText::toggleAppendix(BufferView * bview)
2755 LyXParagraph * par = cursor.par();
2756 bool start = !par->params.startOfAppendix();
2758 // ensure that we have only one start_of_appendix in this document
2759 LyXParagraph * tmp = FirstParagraph();
2760 for (; tmp; tmp = tmp->next())
2761 tmp->params.startOfAppendix(false);
2763 par->params.startOfAppendix(start);
2765 // we can set the refreshing parameters now
2766 status = LyXText::NEED_MORE_REFRESH;
2768 refresh_row = 0; // not needed for full update
2769 UpdateCounters(bview, 0);
2770 SetCursor(bview, cursor.par(), cursor.pos());
2774 LyXParagraph * LyXText::OwnerParagraph() const
2777 return inset_owner->par;
2779 return bv_owner->buffer()->paragraph;
2783 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
2786 inset_owner->par = p;
2788 bv_owner->buffer()->paragraph = p;