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 * ====================================================== */
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 printf("TP = %x\n",inset_owner->owner());
142 // Dump all rowinformation:
143 Row * tmprow = firstrow;
144 lyxerr << "Width = " << width << endl;
145 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
147 lyxerr << tmprow->baseline() << '\t'
148 << tmprow->par() << '\t'
149 << tmprow->pos() << '\t'
150 << tmprow->height() << '\t'
151 << tmprow->ascent_of_text() << '\t'
152 << tmprow->fill() << '\n';
153 tmprow = tmprow->next();
161 // Delete all rows, this does not touch the paragraphs!
162 Row * tmprow = firstrow;
164 tmprow = firstrow->next();
171 // Gets the fully instantiated font at a given position in a paragraph
172 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
173 // The difference is that this one is used for displaying, and thus we
174 // are allowed to make cosmetic improvements. For instance make footnotes
176 // If position is -1, we get the layout font of the paragraph.
177 // If position is -2, we get the font of the manual label of the paragraph.
178 LyXFont const LyXText::GetFont(Buffer const * buf, LyXParagraph * par,
179 LyXParagraph::size_type pos) const
181 LyXLayout const & layout =
182 textclasslist.Style(buf->params.textclass, par->GetLayout());
184 char par_depth = par->GetDepth();
185 // We specialize the 95% common case:
189 if (layout.labeltype == LABEL_MANUAL
190 && pos < BeginningOfMainBody(buf, par)) {
192 LyXFont f = par->GetFontSettings(buf->params,
194 return f.realize(layout.reslabelfont);
196 LyXFont f = par->GetFontSettings(buf->params, pos);
197 return f.realize(layout.resfont);
202 // process layoutfont for pos == -1 and labelfont for pos < -1
204 return layout.resfont;
206 return layout.reslabelfont;
210 // The uncommon case need not be optimized as much
212 LyXFont layoutfont, tmpfont;
216 if (pos < BeginningOfMainBody(buf, par)) {
218 layoutfont = layout.labelfont;
221 layoutfont = layout.font;
223 tmpfont = par->GetFontSettings(buf->params, pos);
224 tmpfont.realize(layoutfont);
227 // process layoutfont for pos == -1 and labelfont for pos < -1
229 tmpfont = layout.font;
231 tmpfont = layout.labelfont;
234 // Resolve against environment font information
235 while (par && par_depth && !tmpfont.resolved()) {
236 par = par->DepthHook(par_depth - 1);
238 tmpfont.realize(textclasslist.
239 Style(buf->params.textclass,
240 par->GetLayout()).font);
241 par_depth = par->GetDepth();
245 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
251 void LyXText::SetCharFont(BufferView * bv, LyXParagraph * par,
252 LyXParagraph::size_type pos, LyXFont const & fnt,
255 Buffer const * buf = bv->buffer();
256 LyXFont font = GetFont(buf, par, pos);
257 font.update(fnt, buf->params.language, toggleall);
258 // Let the insets convert their font
259 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
260 Inset * inset = par->GetInset(pos);
262 if (inset->Editable()==Inset::HIGHLY_EDITABLE) {
263 UpdatableInset * uinset = static_cast<UpdatableInset *>(inset);
264 uinset->SetFont(bv, fnt, toggleall, true);
266 font = inset->ConvertFont(font);
270 LyXLayout const & layout =
271 textclasslist.Style(buf->params.textclass,
274 // Get concrete layout font to reduce against
277 if (pos < BeginningOfMainBody(buf, par))
278 layoutfont = layout.labelfont;
280 layoutfont = layout.font;
282 // Realize against environment font information
283 if (par->GetDepth()){
284 LyXParagraph * tp = par;
285 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
286 tp = tp->DepthHook(tp->GetDepth()-1);
288 layoutfont.realize(textclasslist.
289 Style(buf->params.textclass,
290 tp->GetLayout()).font);
294 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
296 // Now, reduce font against full layout font
297 font.reduce(layoutfont);
299 par->SetFont(pos, font);
302 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
303 LyXParagraph::size_type pos, LyXFont const & fnt)
306 // Let the insets convert their font
307 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
308 font = par->GetInset(pos)->ConvertFont(font);
311 LyXLayout const & layout =
312 textclasslist.Style(buf->params.textclass,
315 // Get concrete layout font to reduce against
318 if (pos < BeginningOfMainBody(buf, par))
319 layoutfont = layout.labelfont;
321 layoutfont = layout.font;
323 // Realize against environment font information
324 if (par->GetDepth()){
325 LyXParagraph * tp = par;
326 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
327 tp = tp->DepthHook(tp->GetDepth()-1);
329 layoutfont.realize(textclasslist.
330 Style(buf->params.textclass,
331 tp->GetLayout()).font);
335 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
337 // Now, reduce font against full layout font
338 font.reduce(layoutfont);
340 par->SetFont(pos, font);
344 /* inserts a new row behind the specified row, increments
345 * the touched counters */
346 void LyXText::InsertRow(Row * row, LyXParagraph * par,
347 LyXParagraph::size_type pos) const
349 Row * tmprow = new Row;
352 tmprow->next(firstrow);
355 tmprow->previous(row);
356 tmprow->next(row->next());
361 tmprow->next()->previous(tmprow);
363 if (tmprow->previous())
364 tmprow->previous()->next(tmprow);
372 ++number_of_rows; // one more row
376 // removes the row and reset the touched counters
377 void LyXText::RemoveRow(Row * row) const
379 /* this must not happen before the currentrow for clear reasons.
380 so the trick is just to set the current row onto the previous
383 GetRow(row->par(), row->pos(), unused_y);
386 row->next()->previous(row->previous());
387 if (!row->previous()) {
388 firstrow = row->next();
390 row->previous()->next(row->next());
393 lastrow = row->previous();
395 height -= row->height(); // the text becomes smaller
398 --number_of_rows; // one row less
402 // remove all following rows of the paragraph of the specified row.
403 void LyXText::RemoveParagraph(Row * row) const
405 LyXParagraph * tmppar = row->par();
409 while (row && row->par() == tmppar) {
410 tmprow = row->next();
417 // insert the specified paragraph behind the specified row
418 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
421 InsertRow(row, par, 0); /* insert a new row, starting
424 SetCounter(bview->buffer(), par); // set the counters
426 // and now append the whole paragraph behind the new row
429 AppendParagraph(bview, firstrow);
431 row->next()->height(0);
432 AppendParagraph(bview, row->next());
437 /* used in setlayout */
438 // Asger is not sure we want to do this...
439 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
443 LyXLayout const & layout =
444 textclasslist.Style(buf->params.textclass, par->GetLayout());
446 LyXFont layoutfont, tmpfont;
447 for (LyXParagraph::size_type pos = 0;
448 pos < par->size(); ++pos) {
449 if (pos < BeginningOfMainBody(buf, par))
450 layoutfont = layout.labelfont;
452 layoutfont = layout.font;
454 tmpfont = par->GetFontSettings(buf->params, pos);
455 tmpfont.reduce(layoutfont);
456 par->SetFont(pos, tmpfont);
461 LyXParagraph * LyXText::SetLayout(BufferView * bview,
462 LyXCursor & cur, LyXCursor & sstart_cur,
463 LyXCursor & send_cur,
464 LyXTextClass::size_type layout)
466 LyXParagraph * endpar = send_cur.par()->next();
467 LyXParagraph * undoendpar = endpar;
469 if (endpar && endpar->GetDepth()) {
470 while (endpar && endpar->GetDepth()) {
471 endpar = endpar->next();
475 endpar = endpar->next(); // because of parindents etc.
478 SetUndo(bview->buffer(), Undo::EDIT,
479 sstart_cur.par()->previous(),
482 /* ok we have a selection. This is always between sstart_cur
483 * and sel_end cursor */
486 LyXLayout const & lyxlayout =
487 textclasslist.Style(bview->buffer()->params.textclass, layout);
489 while (cur.par() != send_cur.par()) {
490 cur.par()->SetLayout(layout);
491 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
492 LyXParagraph * fppar = cur.par();
493 fppar->params.spaceTop(lyxlayout.fill_top ?
494 VSpace(VSpace::VFILL)
495 : VSpace(VSpace::NONE));
496 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
497 VSpace(VSpace::VFILL)
498 : VSpace(VSpace::NONE));
499 if (lyxlayout.margintype == MARGIN_MANUAL)
500 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
501 if (lyxlayout.labeltype != LABEL_BIBLIO
503 delete fppar->bibkey;
506 cur.par(cur.par()->next());
508 cur.par()->SetLayout(layout);
509 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
510 LyXParagraph * fppar = cur.par();
511 fppar->params.spaceTop(lyxlayout.fill_top ?
512 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
513 fppar->params.spaceBottom(lyxlayout.fill_bottom ?
514 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
515 if (lyxlayout.margintype == MARGIN_MANUAL)
516 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
517 if (lyxlayout.labeltype != LABEL_BIBLIO
519 delete fppar->bibkey;
526 // set layout over selection and make a total rebreak of those paragraphs
527 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
529 LyXCursor tmpcursor = cursor; /* store the current cursor */
531 // if there is no selection just set the layout
532 // of the current paragraph */
534 sel_start_cursor = cursor; // dummy selection
535 sel_end_cursor = cursor;
538 endpar = SetLayout(bview, cursor, sel_start_cursor,
539 sel_end_cursor, layout);
540 RedoParagraphs(bview, sel_start_cursor, endpar);
542 // we have to reset the selection, because the
543 // geometry could have changed
544 SetCursor(bview, sel_start_cursor.par(),
545 sel_start_cursor.pos(), false);
547 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
549 UpdateCounters(bview, cursor.row());
550 ClearSelection(bview);
552 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
556 // increment depth over selection and
557 // make a total rebreak of those paragraphs
558 void LyXText::IncDepth(BufferView * bview)
560 // If there is no selection, just use the current paragraph
562 sel_start_cursor = cursor; // dummy selection
563 sel_end_cursor = cursor;
566 // We end at the next paragraph with depth 0
567 LyXParagraph * endpar = sel_end_cursor.par()->next();
569 LyXParagraph * undoendpar = endpar;
571 if (endpar && endpar->GetDepth()) {
572 while (endpar && endpar->GetDepth()) {
573 endpar = endpar->next();
578 endpar = endpar->next(); // because of parindents etc.
581 SetUndo(bview->buffer(), Undo::EDIT,
582 sel_start_cursor.par()->previous(),
585 LyXCursor tmpcursor = cursor; // store the current cursor
587 // ok we have a selection. This is always between sel_start_cursor
588 // and sel_end cursor
589 cursor = sel_start_cursor;
591 bool anything_changed = false;
594 // NOTE: you can't change the depth of a bibliography entry
596 textclasslist.Style(bview->buffer()->params.textclass,
597 cursor.par()->GetLayout()
598 ).labeltype != LABEL_BIBLIO) {
599 LyXParagraph * prev = cursor.par()->previous();
602 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
603 || (prev->GetDepth() == cursor.par()->GetDepth()
604 && textclasslist.Style(bview->buffer()->params.textclass,
605 prev->GetLayout()).isEnvironment()))) {
606 cursor.par()->params.depth(cursor.par()->params.depth() + 1);
607 anything_changed = true;
610 if (cursor.par() == sel_end_cursor.par())
612 cursor.par(cursor.par()->next());
615 // if nothing changed set all depth to 0
616 if (!anything_changed) {
617 cursor = sel_start_cursor;
618 while (cursor.par() != sel_end_cursor.par()) {
619 cursor.par()->params.depth(0);
620 cursor.par(cursor.par()->next());
622 cursor.par()->params.depth(0);
625 RedoParagraphs(bview, sel_start_cursor, endpar);
627 // we have to reset the selection, because the
628 // geometry could have changed
629 SetCursor(bview, sel_start_cursor.par(),
630 sel_start_cursor.pos());
632 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
633 UpdateCounters(bview, cursor.row());
634 ClearSelection(bview);
636 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
640 // decrement depth over selection and
641 // make a total rebreak of those paragraphs
642 void LyXText::DecDepth(BufferView * bview)
644 // if there is no selection just set the layout
645 // of the current paragraph
647 sel_start_cursor = cursor; // dummy selection
648 sel_end_cursor = cursor;
650 LyXParagraph * endpar = sel_end_cursor.par()->next();
651 LyXParagraph * undoendpar = endpar;
653 if (endpar && endpar->GetDepth()) {
654 while (endpar && endpar->GetDepth()) {
655 endpar = endpar->next();
660 endpar = endpar->next(); // because of parindents etc.
663 SetUndo(bview->buffer(), Undo::EDIT,
664 sel_start_cursor.par()->previous(),
667 LyXCursor tmpcursor = cursor; // store the current cursor
669 // ok we have a selection. This is always between sel_start_cursor
670 // and sel_end cursor
671 cursor = sel_start_cursor;
674 if (cursor.par()->params.depth())
675 cursor.par()->params.depth(cursor.par()->params.depth() - 1);
676 if (cursor.par() == sel_end_cursor.par())
678 cursor.par(cursor.par()->next());
681 RedoParagraphs(bview, sel_start_cursor, endpar);
683 // we have to reset the selection, because the
684 // geometry could have changed
685 SetCursor(bview, sel_start_cursor.par(),
686 sel_start_cursor.pos());
688 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
689 UpdateCounters(bview, cursor.row());
690 ClearSelection(bview);
692 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
696 // set font over selection and make a total rebreak of those paragraphs
697 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
699 // if there is no selection just set the current_font
701 // Determine basis font
703 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
705 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
707 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
708 // Update current font
709 real_current_font.update(font,
710 bview->buffer()->params.language,
713 // Reduce to implicit settings
714 current_font = real_current_font;
715 current_font.reduce(layoutfont);
716 // And resolve it completely
717 real_current_font.realize(layoutfont);
721 LyXCursor tmpcursor = cursor; // store the current cursor
723 // ok we have a selection. This is always between sel_start_cursor
724 // and sel_end cursor
726 SetUndo(bview->buffer(), Undo::EDIT,
727 sel_start_cursor.par()->previous(),
728 sel_end_cursor.par()->next());
730 cursor = sel_start_cursor;
731 while (cursor.par() != sel_end_cursor.par() ||
732 (cursor.pos() < sel_end_cursor.pos())) {
733 if (cursor.pos() < cursor.par()->size()) {
734 // an open footnote should behave
736 SetCharFont(bview, cursor.par(), cursor.pos(), font, toggleall);
737 cursor.pos(cursor.pos() + 1);
740 cursor.par(cursor.par()->next());
745 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->next());
747 // we have to reset the selection, because the
748 // geometry could have changed
749 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
751 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
752 ClearSelection(bview);
754 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
755 tmpcursor.boundary());
759 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
761 Row * tmprow = cur.row();
762 int y = cur.y() - tmprow->baseline();
764 SetHeightOfRow(bview, tmprow);
765 LyXParagraph * first_phys_par = tmprow->par();
767 // find the first row of the paragraph
768 if (first_phys_par != tmprow->par())
769 while (tmprow->previous()
770 && tmprow->previous()->par() != first_phys_par) {
771 tmprow = tmprow->previous();
772 y -= tmprow->height();
773 SetHeightOfRow(bview, tmprow);
775 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
776 tmprow = tmprow->previous();
777 y -= tmprow->height();
778 SetHeightOfRow(bview, tmprow);
781 // we can set the refreshing parameters now
782 status = LyXText::NEED_MORE_REFRESH;
784 refresh_row = tmprow;
785 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
789 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
791 Row * tmprow = cur.row();
793 int y = cur.y() - tmprow->baseline();
794 SetHeightOfRow(bview, tmprow);
795 LyXParagraph * first_phys_par = tmprow->par();
797 // find the first row of the paragraph
798 if (first_phys_par != tmprow->par())
799 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
800 tmprow = tmprow->previous();
801 y -= tmprow->height();
803 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
804 tmprow = tmprow->previous();
805 y -= tmprow->height();
808 // we can set the refreshing parameters now
809 if (status == LyXText::UNCHANGED || y < refresh_y) {
811 refresh_row = tmprow;
813 status = LyXText::NEED_MORE_REFRESH;
814 SetCursor(bview, cur.par(), cur.pos());
818 /* deletes and inserts again all paragaphs between the cursor
819 * and the specified par
820 * This function is needed after SetLayout and SetFont etc. */
821 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
822 LyXParagraph const * endpar) const
825 LyXParagraph * tmppar = 0, * first_phys_par = 0;
827 Row * tmprow = cur.row();
829 int y = cur.y() - tmprow->baseline();
831 if (!tmprow->previous()){
832 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
834 first_phys_par = tmprow->par();
835 // find the first row of the paragraph
836 if (first_phys_par != tmprow->par())
837 while (tmprow->previous() &&
838 (tmprow->previous()->par() != first_phys_par)) {
839 tmprow = tmprow->previous();
840 y -= tmprow->height();
842 while (tmprow->previous()
843 && tmprow->previous()->par() == first_phys_par) {
844 tmprow = tmprow->previous();
845 y -= tmprow->height();
849 // we can set the refreshing parameters now
850 status = LyXText::NEED_MORE_REFRESH;
852 refresh_row = tmprow->previous(); /* the real refresh row will
853 be deleted, so I store
857 tmppar = tmprow->next()->par();
860 while (tmppar != endpar) {
861 RemoveRow(tmprow->next());
863 tmppar = tmprow->next()->par();
868 // remove the first one
869 tmprow2 = tmprow; /* this is because tmprow->previous()
871 tmprow = tmprow->previous();
874 tmppar = first_phys_par;
878 InsertParagraph(bview, tmppar, tmprow);
881 while (tmprow->next() && tmprow->next()->par() == tmppar)
882 tmprow = tmprow->next();
883 tmppar = tmppar->next();
885 } while (tmppar != endpar);
887 // this is because of layout changes
889 refresh_y -= refresh_row->height();
890 SetHeightOfRow(bview, refresh_row);
892 refresh_row = firstrow;
894 SetHeightOfRow(bview, refresh_row);
897 if (tmprow && tmprow->next())
898 SetHeightOfRow(bview, tmprow->next());
902 bool LyXText::FullRebreak(BufferView * bview)
908 if (need_break_row) {
909 BreakAgain(bview, need_break_row);
917 /* important for the screen */
920 /* the cursor set functions have a special mechanism. When they
921 * realize, that you left an empty paragraph, they will delete it.
922 * They also delete the corresponding row */
924 // need the selection cursor:
925 void LyXText::SetSelection(BufferView * bview)
927 const bool lsel = selection;
930 last_sel_cursor = sel_cursor;
931 sel_start_cursor = sel_cursor;
932 sel_end_cursor = sel_cursor;
937 // first the toggling area
938 if (cursor.y() < last_sel_cursor.y()
939 || (cursor.y() == last_sel_cursor.y()
940 && cursor.x() < last_sel_cursor.x())) {
941 toggle_end_cursor = last_sel_cursor;
942 toggle_cursor = cursor;
944 toggle_end_cursor = cursor;
945 toggle_cursor = last_sel_cursor;
948 last_sel_cursor = cursor;
950 // and now the whole selection
952 if (sel_cursor.par() == cursor.par())
953 if (sel_cursor.pos() < cursor.pos()) {
954 sel_end_cursor = cursor;
955 sel_start_cursor = sel_cursor;
957 sel_end_cursor = sel_cursor;
958 sel_start_cursor = cursor;
960 else if (sel_cursor.y() < cursor.y() ||
961 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
962 sel_end_cursor = cursor;
963 sel_start_cursor = sel_cursor;
966 sel_end_cursor = sel_cursor;
967 sel_start_cursor = cursor;
970 // a selection with no contents is not a selection
971 if (sel_start_cursor.par() == sel_end_cursor.par() &&
972 sel_start_cursor.pos() == sel_end_cursor.pos())
975 if (inset_owner && (selection || lsel))
976 inset_owner->SetUpdateStatus(bview, InsetText::SELECTION);
980 string const LyXText::selectionAsString(Buffer const * buffer) const
982 if (!selection) return string();
985 // Special handling if the whole selection is within one paragraph
986 if (sel_start_cursor.par() == sel_end_cursor.par()) {
987 result += sel_start_cursor.par()->String(buffer,
988 sel_start_cursor.pos(),
989 sel_end_cursor.pos());
993 // The selection spans more than one paragraph
995 // First paragraph in selection
996 result += sel_start_cursor.par()->String(buffer,
997 sel_start_cursor.pos(),
998 sel_start_cursor.par()->size())
1001 // The paragraphs in between (if any)
1002 LyXCursor tmpcur(sel_start_cursor);
1003 tmpcur.par(tmpcur.par()->next());
1004 while (tmpcur.par() != sel_end_cursor.par()) {
1005 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->size()) + "\n\n";
1006 tmpcur.par(tmpcur.par()->next()); // Or NextAfterFootnote??
1009 // Last paragraph in selection
1010 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1016 void LyXText::ClearSelection(BufferView * /*bview*/) const
1020 sel_end_cursor = sel_start_cursor = cursor;
1024 void LyXText::CursorHome(BufferView * bview) const
1026 SetCursor(bview, cursor.par(), cursor.row()->pos());
1030 void LyXText::CursorEnd(BufferView * bview) const
1032 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1033 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1035 if (cursor.par()->size() &&
1036 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1037 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1038 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1040 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1045 void LyXText::CursorTop(BufferView * bview) const
1047 while (cursor.par()->previous())
1048 cursor.par(cursor.par()->previous());
1049 SetCursor(bview, cursor.par(), 0);
1053 void LyXText::CursorBottom(BufferView * bview) const
1055 while (cursor.par()->next())
1056 cursor.par(cursor.par()->next());
1057 SetCursor(bview, cursor.par(), cursor.par()->size());
1061 void LyXText::ToggleFree(BufferView * bview,
1062 LyXFont const & font, bool toggleall)
1064 // If the mask is completely neutral, tell user
1065 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1066 // Could only happen with user style
1067 bview->owner()->message(_("No font change defined. Use Character under the Layout menu to define font change."));
1071 // Try implicit word selection
1072 // If there is a change in the language the implicit word selection
1074 LyXCursor resetCursor = cursor;
1075 bool implicitSelection = (font.language() == ignore_language
1076 && font.number() == LyXFont::IGNORE)
1077 ? SelectWordWhenUnderCursor(bview) : false;
1080 SetFont(bview, font, toggleall);
1082 /* Implicit selections are cleared afterwards and cursor is set to the
1083 original position. */
1084 if (implicitSelection) {
1085 ClearSelection(bview);
1086 cursor = resetCursor;
1087 SetCursor(bview, cursor.par(), cursor.pos());
1088 sel_cursor = cursor;
1091 inset_owner->SetUpdateStatus(bview, InsetText::CURSOR_PAR);
1095 LyXParagraph::size_type
1096 LyXText::BeginningOfMainBody(Buffer const * buf,
1097 LyXParagraph const * par) const
1099 if (textclasslist.Style(buf->params.textclass,
1100 par->GetLayout()).labeltype != LABEL_MANUAL)
1103 return par->BeginningOfMainBody();
1107 /* the DTP switches for paragraphs. LyX will store them in the
1108 * first physicla paragraph. When a paragraph is broken, the top settings
1109 * rest, the bottom settings are given to the new one. So I can make shure,
1110 * they do not duplicate themself and you cannnot make dirty things with
1113 void LyXText::SetParagraph(BufferView * bview,
1114 bool line_top, bool line_bottom,
1115 bool pagebreak_top, bool pagebreak_bottom,
1116 VSpace const & space_top,
1117 VSpace const & space_bottom,
1119 string labelwidthstring,
1122 LyXCursor tmpcursor = cursor;
1124 sel_start_cursor = cursor;
1125 sel_end_cursor = cursor;
1128 // make sure that the depth behind the selection are restored, too
1129 LyXParagraph * endpar = sel_end_cursor.par()->next();
1130 LyXParagraph * undoendpar = endpar;
1132 if (endpar && endpar->GetDepth()) {
1133 while (endpar && endpar->GetDepth()) {
1134 endpar = endpar->next();
1135 undoendpar = endpar;
1139 endpar = endpar->next(); // because of parindents etc.
1142 SetUndo(bview->buffer(), Undo::EDIT,
1143 sel_start_cursor.par()->previous(),
1147 LyXParagraph * tmppar = sel_end_cursor.par();
1148 while (tmppar != sel_start_cursor.par()->previous()) {
1149 SetCursor(bview, tmppar, 0);
1150 status = LyXText::NEED_MORE_REFRESH;
1151 refresh_row = cursor.row();
1152 refresh_y = cursor.y() - cursor.row()->baseline();
1153 cursor.par()->params.lineTop(line_top);
1154 cursor.par()->params.lineBottom(line_bottom);
1155 cursor.par()->params.pagebreakTop(pagebreak_top);
1156 cursor.par()->params.pagebreakBottom(pagebreak_bottom);
1157 cursor.par()->params.spaceTop(space_top);
1158 cursor.par()->params.spaceBottom(space_bottom);
1159 // does the layout allow the new alignment?
1160 if (align == LYX_ALIGN_LAYOUT)
1161 align = textclasslist
1162 .Style(bview->buffer()->params.textclass,
1163 cursor.par()->GetLayout()).align;
1164 if (align & textclasslist
1165 .Style(bview->buffer()->params.textclass,
1166 cursor.par()->GetLayout()).alignpossible) {
1167 if (align == textclasslist
1168 .Style(bview->buffer()->params.textclass,
1169 cursor.par()->GetLayout()).align)
1170 cursor.par()->params.align(LYX_ALIGN_LAYOUT);
1172 cursor.par()->params.align(align);
1174 cursor.par()->SetLabelWidthString(labelwidthstring);
1175 cursor.par()->params.noindent(noindent);
1176 tmppar = cursor.par()->previous();
1179 RedoParagraphs(bview, sel_start_cursor, endpar);
1181 ClearSelection(bview);
1182 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1183 sel_cursor = cursor;
1184 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1185 SetSelection(bview);
1186 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1188 bview->updateInset(inset_owner, true);
1192 char loweralphaCounter(int n)
1194 if (n < 1 || n > 26)
1204 char alphaCounter(int n)
1206 if (n < 1 || n > 26)
1214 char hebrewCounter(int n)
1216 static const char hebrew[22] = {
1217 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1218 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1219 '÷', 'ø', 'ù', 'ú'
1221 if (n < 1 || n > 22)
1229 string const romanCounter(int n)
1231 static char const * roman[20] = {
1232 "i", "ii", "iii", "iv", "v",
1233 "vi", "vii", "viii", "ix", "x",
1234 "xi", "xii", "xiii", "xiv", "xv",
1235 "xvi", "xvii", "xviii", "xix", "xx"
1237 if (n < 1 || n > 20)
1246 // set the counter of a paragraph. This includes the labels
1247 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1249 LyXLayout const & layout =
1250 textclasslist.Style(buf->params.textclass,
1253 LyXTextClass const & textclass =
1254 textclasslist.TextClass(buf->params.textclass);
1256 /* copy the prev-counters to this one, unless this is the start of a
1257 footnote or of a bibliography or the very first paragraph */
1259 && !(textclasslist.Style(buf->params.textclass,
1260 par->previous()->GetLayout()
1261 ).labeltype != LABEL_BIBLIO
1262 && layout.labeltype == LABEL_BIBLIO)) {
1263 for (int i = 0; i < 10; ++i) {
1264 par->setCounter(i, par->previous()->GetFirstCounter(i));
1266 par->params.appendix(par->previous()->params.appendix());
1267 if (!par->params.appendix() && par->params.startOfAppendix()) {
1268 par->params.appendix(true);
1269 for (int i = 0; i < 10; ++i) {
1270 par->setCounter(i, 0);
1273 par->enumdepth = par->previous()->enumdepth;
1274 par->itemdepth = par->previous()->itemdepth;
1276 for (int i = 0; i < 10; ++i) {
1277 par->setCounter(i, 0);
1279 par->params.appendix(par->params.startOfAppendix());
1284 /* Maybe we have to increment the enumeration depth.
1285 * BUT, enumeration in a footnote is considered in isolation from its
1286 * surrounding paragraph so don't increment if this is the
1287 * first line of the footnote
1288 * AND, bibliographies can't have their depth changed ie. they
1289 * are always of depth 0
1292 && par->previous()->GetDepth() < par->GetDepth()
1293 && textclasslist.Style(buf->params.textclass,
1294 par->previous()->GetLayout()
1295 ).labeltype == LABEL_COUNTER_ENUMI
1296 && par->enumdepth < 3
1297 && layout.labeltype != LABEL_BIBLIO) {
1301 /* Maybe we have to decrement the enumeration depth, see note above */
1303 && par->previous()->GetDepth() > par->GetDepth()
1304 && layout.labeltype != LABEL_BIBLIO) {
1305 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1306 par->setCounter(6 + par->enumdepth,
1307 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1308 /* reset the counters.
1309 * A depth change is like a breaking layout
1311 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1312 par->setCounter(i, 0);
1315 if (!par->params.labelString().empty()) {
1316 par->params.labelString(string());
1319 if (layout.margintype == MARGIN_MANUAL) {
1320 if (par->params.labelWidthString().empty()) {
1321 par->SetLabelWidthString(layout.labelstring());
1324 par->SetLabelWidthString(string());
1327 /* is it a layout that has an automatic label ? */
1328 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1330 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1331 if (i >= 0 && i<= buf->params.secnumdepth) {
1332 par->incCounter(i); // increment the counter
1334 // Is there a label? Useful for Chapter layout
1335 if (!par->params.appendix()) {
1336 if (!layout.labelstring().empty())
1337 par->params.labelString(layout.labelstring());
1339 par->params.labelString(string());
1341 if (!layout.labelstring_appendix().empty())
1342 par->params.labelString(layout.labelstring_appendix());
1344 par->params.labelString(string());
1347 std::ostringstream s;
1349 if (!par->params.appendix()) {
1350 switch (2 * LABEL_COUNTER_CHAPTER -
1351 textclass.maxcounter() + i) {
1352 case LABEL_COUNTER_CHAPTER:
1353 s << par->getCounter(i);
1355 case LABEL_COUNTER_SECTION:
1356 s << par->getCounter(i - 1) << '.'
1357 << par->getCounter(i);
1359 case LABEL_COUNTER_SUBSECTION:
1360 s << par->getCounter(i - 2) << '.'
1361 << par->getCounter(i - 1) << '.'
1362 << par->getCounter(i);
1364 case LABEL_COUNTER_SUBSUBSECTION:
1365 s << par->getCounter(i - 3) << '.'
1366 << par->getCounter(i - 2) << '.'
1367 << par->getCounter(i - 1) << '.'
1368 << par->getCounter(i);
1371 case LABEL_COUNTER_PARAGRAPH:
1372 s << par->getCounter(i - 4) << '.'
1373 << par->getCounter(i - 3) << '.'
1374 << par->getCounter(i - 2) << '.'
1375 << par->getCounter(i - 1) << '.'
1376 << par->getCounter(i);
1378 case LABEL_COUNTER_SUBPARAGRAPH:
1379 s << par->getCounter(i - 5) << '.'
1380 << par->getCounter(i - 4) << '.'
1381 << par->getCounter(i - 3) << '.'
1382 << par->getCounter(i - 2) << '.'
1383 << par->getCounter(i - 1) << '.'
1384 << par->getCounter(i);
1388 // Can this ever be reached? And in the
1389 // case it is, how can this be correct?
1391 s << par->getCounter(i) << '.';
1394 } else { // appendix
1395 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1396 case LABEL_COUNTER_CHAPTER:
1397 if (par->isRightToLeftPar(buf->params))
1398 s << hebrewCounter(par->getCounter(i));
1400 s << alphaCounter(par->getCounter(i));
1402 case LABEL_COUNTER_SECTION:
1403 if (par->isRightToLeftPar(buf->params))
1404 s << hebrewCounter(par->getCounter(i - 1));
1406 s << alphaCounter(par->getCounter(i - 1));
1409 << par->getCounter(i);
1412 case LABEL_COUNTER_SUBSECTION:
1413 if (par->isRightToLeftPar(buf->params))
1414 s << hebrewCounter(par->getCounter(i - 2));
1416 s << alphaCounter(par->getCounter(i - 2));
1419 << par->getCounter(i-1) << '.'
1420 << par->getCounter(i);
1423 case LABEL_COUNTER_SUBSUBSECTION:
1424 if (par->isRightToLeftPar(buf->params))
1425 s << hebrewCounter(par->getCounter(i-3));
1427 s << alphaCounter(par->getCounter(i-3));
1430 << par->getCounter(i-2) << '.'
1431 << par->getCounter(i-1) << '.'
1432 << par->getCounter(i);
1435 case LABEL_COUNTER_PARAGRAPH:
1436 if (par->isRightToLeftPar(buf->params))
1437 s << hebrewCounter(par->getCounter(i-4));
1439 s << alphaCounter(par->getCounter(i-4));
1442 << par->getCounter(i-3) << '.'
1443 << par->getCounter(i-2) << '.'
1444 << par->getCounter(i-1) << '.'
1445 << par->getCounter(i);
1448 case LABEL_COUNTER_SUBPARAGRAPH:
1449 if (par->isRightToLeftPar(buf->params))
1450 s << hebrewCounter(par->getCounter(i-5));
1452 s << alphaCounter(par->getCounter(i-5));
1455 << par->getCounter(i-4) << '.'
1456 << par->getCounter(i-3) << '.'
1457 << par->getCounter(i-2) << '.'
1458 << par->getCounter(i-1) << '.'
1459 << par->getCounter(i);
1463 // Can this ever be reached? And in the
1464 // case it is, how can this be correct?
1466 s << par->getCounter(i) << '.';
1472 par->params.labelString(par->params.labelString() +s.str().c_str());
1473 // We really want to remove the c_str as soon as
1476 for (i++; i < 10; ++i) {
1477 // reset the following counters
1478 par->setCounter(i, 0);
1480 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1481 for (i++; i < 10; ++i) {
1482 // reset the following counters
1483 par->setCounter(i, 0);
1485 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1486 par->incCounter(i + par->enumdepth);
1487 int number = par->getCounter(i + par->enumdepth);
1489 std::ostringstream s;
1491 switch (par->enumdepth) {
1493 if (par->isRightToLeftPar(buf->params))
1495 << hebrewCounter(number)
1499 << loweralphaCounter(number)
1503 if (par->isRightToLeftPar(buf->params))
1504 s << '.' << romanCounter(number);
1506 s << romanCounter(number) << '.';
1509 if (par->isRightToLeftPar(buf->params))
1511 << alphaCounter(number);
1513 s << alphaCounter(number)
1517 if (par->isRightToLeftPar(buf->params))
1524 par->params.labelString(s.str().c_str());
1525 // we really want to get rid of that c_str()
1527 for (i += par->enumdepth + 1; i < 10; ++i)
1528 par->setCounter(i, 0); /* reset the following counters */
1531 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1532 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
1534 int number = par->getCounter(i);
1536 InsetCommandParams p( "bibitem" );
1537 par->bibkey = new InsetBibKey(p);
1539 par->bibkey->setCounter(number);
1540 par->params.labelString(layout.labelstring());
1542 // In biblio should't be following counters but...
1544 string s = layout.labelstring();
1546 // the caption hack:
1547 if (layout.labeltype == LABEL_SENSITIVE) {
1548 bool isOK (par->InInset() && par->InInset()->owner() &&
1549 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
1551 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
1553 = floatList.getType(tmp->type());
1554 // We should get the correct number here too.
1555 s = fl.name() + " #:";
1557 /* par->SetLayout(0);
1558 s = layout->labelstring; */
1559 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
1560 ? " :úåòîùî øñç" : "Senseless: ";
1563 par->params.labelString(s);
1565 /* reset the enumeration counter. They are always resetted
1566 * when there is any other layout between */
1567 for (int i = 6 + par->enumdepth; i < 10; ++i)
1568 par->setCounter(i, 0);
1573 /* Updates all counters BEHIND the row. Changed paragraphs
1574 * with a dynamic left margin will be rebroken. */
1575 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
1583 par = row->par()->next();
1587 while (row->par() != par)
1590 SetCounter(bview->buffer(), par);
1592 /* now check for the headline layouts. remember that they
1593 * have a dynamic left margin */
1594 if ((textclasslist.Style(bview->buffer()->params.textclass,
1595 par->layout).margintype == MARGIN_DYNAMIC
1596 || textclasslist.Style(bview->buffer()->params.textclass,
1597 par->layout).labeltype == LABEL_SENSITIVE)) {
1599 /* Rebreak the paragraph */
1600 RemoveParagraph(row);
1601 AppendParagraph(bview, row);
1608 /* insets an inset. */
1609 void LyXText::InsertInset(BufferView * bview, Inset * inset)
1611 if (!cursor.par()->InsertInsetAllowed(inset))
1613 SetUndo(bview->buffer(), Undo::INSERT,
1614 cursor.par()->previous(),
1615 cursor.par()->next());
1616 cursor.par()->InsertInset(cursor.pos(), inset);
1617 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
1618 * The character will not be inserted a
1621 // If we enter a highly editable inset the cursor should be to before
1622 // the inset. This couldn't happen before as Undo was not handled inside
1623 // inset now after the Undo LyX tries to call inset->Edit(...) again
1624 // and cannot do this as the cursor is behind the inset and GetInset
1625 // does not return the inset!
1626 if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
1627 CursorLeft(bview, true);
1633 void LyXText::copyEnvironmentType()
1635 copylayouttype = cursor.par()->GetLayout();
1639 void LyXText::pasteEnvironmentType(BufferView * bview)
1641 SetLayout(bview, copylayouttype);
1645 void LyXText::CutSelection(BufferView * bview, bool doclear)
1647 // Stuff what we got on the clipboard. Even if there is no selection.
1649 // There is a problem with having the stuffing here in that the
1650 // larger the selection the slower LyX will get. This can be
1651 // solved by running the line below only when the selection has
1652 // finished. The solution used currently just works, to make it
1653 // faster we need to be more clever and probably also have more
1654 // calls to stuffClipboard. (Lgb)
1655 bview->stuffClipboard(selectionAsString(bview->buffer()));
1657 // This doesn't make sense, if there is no selection
1661 // OK, we have a selection. This is always between sel_start_cursor
1662 // and sel_end_cursor
1664 // make sure that the depth behind the selection are restored, too
1665 LyXParagraph * endpar = sel_end_cursor.par()->next();
1666 LyXParagraph * undoendpar = endpar;
1668 if (endpar && endpar->GetDepth()) {
1669 while (endpar && endpar->GetDepth()) {
1670 endpar = endpar->next();
1671 undoendpar = endpar;
1673 } else if (endpar) {
1674 endpar = endpar->next(); // because of parindents etc.
1677 SetUndo(bview->buffer(), Undo::DELETE,
1678 sel_start_cursor.par()->previous(),
1683 // there are two cases: cut only within one paragraph or
1684 // more than one paragraph
1685 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1686 // only within one paragraph
1687 endpar = sel_end_cursor.par();
1688 int pos = sel_end_cursor.pos();
1689 cap.cutSelection(sel_start_cursor.par(), &endpar,
1690 sel_start_cursor.pos(), pos,
1691 bview->buffer()->params.textclass, doclear);
1692 sel_end_cursor.pos(pos);
1694 endpar = sel_end_cursor.par();
1695 int pos = sel_end_cursor.pos();
1696 cap.cutSelection(sel_start_cursor.par(), &endpar,
1697 sel_start_cursor.pos(), pos,
1698 bview->buffer()->params.textclass, doclear);
1700 sel_end_cursor.par(endpar);
1701 sel_end_cursor.pos(pos);
1702 cursor.pos(sel_end_cursor.pos());
1704 endpar = endpar->next();
1706 // sometimes necessary
1708 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
1710 RedoParagraphs(bview, sel_start_cursor, endpar);
1712 // cutSelection can invalidate the cursor so we need to set
1714 cursor = sel_start_cursor;
1716 // need a valid cursor. (Lgb)
1717 ClearSelection(bview);
1719 SetCursor(bview, cursor.par(), cursor.pos());
1720 sel_cursor = cursor;
1721 UpdateCounters(bview, cursor.row());
1725 void LyXText::CopySelection(BufferView * bview)
1727 // Stuff what we got on the clipboard. Even if there is no selection.
1729 // There is a problem with having the stuffing here in that the
1730 // larger the selection the slower LyX will get. This can be
1731 // solved by running the line below only when the selection has
1732 // finished. The solution used currently just works, to make it
1733 // faster we need to be more clever and probably also have more
1734 // calls to stuffClipboard. (Lgb)
1735 bview->stuffClipboard(selectionAsString(bview->buffer()));
1737 // this doesnt make sense, if there is no selection
1741 // ok we have a selection. This is always between sel_start_cursor
1742 // and sel_end cursor
1744 // copy behind a space if there is one
1745 while (sel_start_cursor.par()->size() > sel_start_cursor.pos()
1746 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
1747 && (sel_start_cursor.par() != sel_end_cursor.par()
1748 || sel_start_cursor.pos() < sel_end_cursor.pos()))
1749 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
1753 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
1754 sel_start_cursor.pos(), sel_end_cursor.pos(),
1755 bview->buffer()->params.textclass);
1759 void LyXText::PasteSelection(BufferView * bview)
1763 // this does not make sense, if there is nothing to paste
1764 if (!cap.checkPastePossible(cursor.par()))
1767 SetUndo(bview->buffer(), Undo::INSERT,
1768 cursor.par()->previous(),
1769 cursor.par()->next());
1771 LyXParagraph * endpar;
1772 LyXParagraph * actpar = cursor.par();
1774 int pos = cursor.pos();
1775 cap.pasteSelection(&actpar, &endpar, pos,
1776 bview->buffer()->params.textclass);
1778 RedoParagraphs(bview, cursor, endpar);
1780 SetCursor(bview, cursor.par(), cursor.pos());
1781 ClearSelection(bview);
1783 sel_cursor = cursor;
1784 SetCursor(bview, actpar, pos);
1785 SetSelection(bview);
1786 UpdateCounters(bview, cursor.row());
1790 // returns a pointer to the very first LyXParagraph
1791 LyXParagraph * LyXText::FirstParagraph() const
1793 return OwnerParagraph();
1797 // sets the selection over the number of characters of string, no check!!
1798 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
1800 sel_cursor = cursor;
1801 for (int i = 0; str[i]; ++i)
1803 SetSelection(bview);
1807 // simple replacing. The font of the first selected character is used
1808 void LyXText::ReplaceSelectionWithString(BufferView * bview,
1811 SetCursorParUndo(bview->buffer());
1814 if (!selection) { // create a dummy selection
1815 sel_end_cursor = cursor;
1816 sel_start_cursor = cursor;
1819 // Get font setting before we cut
1820 LyXParagraph::size_type pos = sel_end_cursor.pos();
1821 LyXFont const font = sel_start_cursor.par()
1822 ->GetFontSettings(bview->buffer()->params,
1823 sel_start_cursor.pos());
1825 // Insert the new string
1826 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
1827 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
1831 // Cut the selection
1832 CutSelection(bview);
1838 // needed to insert the selection
1839 void LyXText::InsertStringA(BufferView * bview, string const & str)
1841 LyXParagraph * par = cursor.par();
1842 LyXParagraph::size_type pos = cursor.pos();
1843 LyXParagraph::size_type a = 0;
1844 LyXParagraph * endpar = cursor.par()->next();
1846 SetCursorParUndo(bview->buffer());
1849 textclasslist.Style(bview->buffer()->params.textclass,
1850 cursor.par()->GetLayout()).isEnvironment();
1851 // only to be sure, should not be neccessary
1852 ClearSelection(bview);
1854 // insert the string, don't insert doublespace
1855 string::size_type i = 0;
1856 while (i < str.length()) {
1857 if (str[i] != '\n') {
1859 && i + 1 < str.length() && str[i + 1] != ' '
1860 && pos && par->GetChar(pos - 1)!= ' ') {
1861 par->InsertChar(pos, ' ', current_font);
1863 } else if (str[i] == ' ') {
1864 InsetSpecialChar * new_inset =
1865 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1866 if (par->InsertInsetAllowed(new_inset)) {
1867 par->InsertInset(pos, new_inset,
1873 } else if (str[i] == '\t') {
1874 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
1875 InsetSpecialChar * new_inset =
1876 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1877 if (par->InsertInsetAllowed(new_inset)) {
1878 par->InsertInset(pos, new_inset,
1885 } else if (str[i] != 13 &&
1886 // Ignore unprintables
1887 (str[i] & 127) >= ' ') {
1888 par->InsertChar(pos, str[i], current_font);
1892 if (!par->size()) { // par is empty
1893 InsetSpecialChar * new_inset =
1894 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1895 if (par->InsertInsetAllowed(new_inset)) {
1896 par->InsertInset(pos,
1904 par->BreakParagraph(bview->buffer()->params, pos, flag);
1911 RedoParagraphs(bview, cursor, endpar);
1912 SetCursor(bview, cursor.par(), cursor.pos());
1913 sel_cursor = cursor;
1914 SetCursor(bview, par, pos);
1915 SetSelection(bview);
1919 /* turns double-CR to single CR, others where converted into one blank and 13s
1920 * that are ignored .Double spaces are also converted into one. Spaces at
1921 * the beginning of a paragraph are forbidden. tabs are converted into one
1922 * space. then InsertStringA is called */
1923 void LyXText::InsertStringB(BufferView * bview, string const & s)
1926 string::size_type i = 1;
1927 while (i < str.length()) {
1930 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
1932 if (str[i] == '\n' && i + 1 < str.length()) {
1933 if (str[i + 1] != '\n') {
1934 if (str[i - 1] != ' ')
1939 while (i + 1 < str.length()
1940 && (str[i + 1] == ' '
1941 || str[i + 1] == '\t'
1942 || str[i + 1] == '\n'
1943 || str[i + 1] == 13)) {
1950 InsertStringA(bview, str);
1954 bool LyXText::GotoNextInset(BufferView * bview,
1955 std::vector<Inset::Code> const & codes,
1956 string const & contents) const
1958 LyXCursor res = cursor;
1961 if (res.pos() < res.par()->size() - 1) {
1962 res.pos(res.pos() + 1);
1964 res.par(res.par()->next());
1968 } while (res.par() &&
1969 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
1970 && (inset = res.par()->GetInset(res.pos())) != 0
1971 && find(codes.begin(), codes.end(), inset->LyxCode())
1973 && (contents.empty() ||
1974 static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
1978 SetCursor(bview, res.par(), res.pos());
1985 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
1986 LyXParagraph::size_type pos)
1988 LyXCursor tmpcursor;
1991 LyXParagraph::size_type z;
1992 Row * row = GetRow(par, pos, y);
1994 // is there a break one row above
1995 if (row->previous() && row->previous()->par() == row->par()) {
1996 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
1997 if (z >= row->pos()) {
1998 // set the dimensions of the row above
1999 y -= row->previous()->height();
2001 refresh_row = row->previous();
2002 status = LyXText::NEED_MORE_REFRESH;
2004 BreakAgain(bview, row->previous());
2006 // set the cursor again. Otherwise
2007 // dangling pointers are possible
2008 SetCursor(bview, cursor.par(), cursor.pos(),
2009 false, cursor.boundary());
2010 sel_cursor = cursor;
2015 int const tmpheight = row->height();
2016 LyXParagraph::size_type const tmplast = RowLast(row);
2020 BreakAgain(bview, row);
2021 if (row->height() == tmpheight && RowLast(row) == tmplast)
2022 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2024 status = LyXText::NEED_MORE_REFRESH;
2026 // check the special right address boxes
2027 if (textclasslist.Style(bview->buffer()->params.textclass,
2028 par->GetLayout()).margintype
2029 == MARGIN_RIGHT_ADDRESS_BOX) {
2036 RedoDrawingOfParagraph(bview, tmpcursor);
2039 // set the cursor again. Otherwise dangling pointers are possible
2040 // also set the selection
2044 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2045 false, sel_cursor.boundary());
2046 sel_cursor = cursor;
2047 SetCursorIntern(bview, sel_start_cursor.par(),
2048 sel_start_cursor.pos(),
2049 false, sel_start_cursor.boundary());
2050 sel_start_cursor = cursor;
2051 SetCursorIntern(bview, sel_end_cursor.par(),
2052 sel_end_cursor.pos(),
2053 false, sel_end_cursor.boundary());
2054 sel_end_cursor = cursor;
2055 SetCursorIntern(bview, last_sel_cursor.par(),
2056 last_sel_cursor.pos(),
2057 false, last_sel_cursor.boundary());
2058 last_sel_cursor = cursor;
2061 SetCursorIntern(bview, cursor.par(), cursor.pos(),
2062 false, cursor.boundary());
2066 // returns false if inset wasn't found
2067 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2069 // first check the current paragraph
2070 int pos = cursor.par()->GetPositionOfInset(inset);
2072 CheckParagraph(bview, cursor.par(), pos);
2076 // check every paragraph
2078 LyXParagraph * par = FirstParagraph();
2080 pos = par->GetPositionOfInset(inset);
2082 CheckParagraph(bview, par, pos);
2092 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2093 LyXParagraph::size_type pos,
2094 bool setfont, bool boundary) const
2096 LyXCursor old_cursor = cursor;
2097 SetCursorIntern(bview, par, pos, setfont, boundary);
2098 DeleteEmptyParagraphMechanism(bview, old_cursor);
2102 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2103 LyXParagraph::size_type pos, bool boundary) const
2107 cur.boundary(boundary);
2109 /* get the cursor y position in text */
2111 Row * row = GetRow(par, pos, y);
2112 /* y is now the beginning of the cursor row */
2113 y += row->baseline();
2114 /* y is now the cursor baseline */
2117 /* now get the cursors x position */
2119 float fill_separator, fill_hfill, fill_label_hfill;
2120 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2122 LyXParagraph::size_type cursor_vpos = 0;
2123 LyXParagraph::size_type last = RowLastPrintable(row);
2125 if (pos > last + 1) // This shouldn't happen.
2127 else if (pos < row->pos())
2130 if (last < row->pos())
2131 cursor_vpos = row->pos();
2132 else if (pos > last && !boundary)
2133 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2134 ? row->pos() : last + 1;
2135 else if (pos > row->pos() &&
2136 (pos > last || boundary))
2137 /// Place cursor after char at (logical) position pos - 1
2138 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2139 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2141 /// Place cursor before char at (logical) position pos
2142 cursor_vpos = (bidi_level(pos) % 2 == 0)
2143 ? log2vis(pos) : log2vis(pos) + 1;
2145 LyXParagraph::size_type main_body =
2146 BeginningOfMainBody(bview->buffer(), row->par());
2147 if ((main_body > 0) &&
2148 ((main_body-1 > last) ||
2149 !row->par()->IsLineSeparator(main_body-1)))
2152 for (LyXParagraph::size_type vpos = row->pos();
2153 vpos < cursor_vpos; ++vpos) {
2154 pos = vis2log(vpos);
2155 if (main_body > 0 && pos == main_body - 1) {
2156 x += fill_label_hfill +
2157 lyxfont::width(textclasslist.Style(
2158 bview->buffer()->params.textclass,
2159 row->par()->GetLayout())
2161 GetFont(bview->buffer(), row->par(), -2));
2162 if (row->par()->IsLineSeparator(main_body-1))
2163 x -= SingleWidth(bview, row->par(),main_body-1);
2165 if (HfillExpansion(bview->buffer(), row, pos)) {
2166 x += SingleWidth(bview, row->par(), pos);
2167 if (pos >= main_body)
2170 x += fill_label_hfill;
2171 } else if (row->par()->IsSeparator(pos)) {
2172 x += SingleWidth(bview, row->par(), pos);
2173 if (pos >= main_body)
2174 x += fill_separator;
2176 x += SingleWidth(bview, row->par(), pos);
2185 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2186 LyXParagraph::size_type pos,
2187 bool setfont, bool boundary) const
2189 SetCursor(bview, cursor, par, pos, boundary);
2191 SetCurrentFont(bview);
2195 void LyXText::SetCurrentFont(BufferView * bview) const
2197 LyXParagraph::size_type pos = cursor.pos();
2198 if (cursor.boundary() && pos > 0)
2202 if (pos == cursor.par()->size())
2204 else // potentional bug... BUG (Lgb)
2205 if (cursor.par()->IsSeparator(pos)) {
2206 if (pos > cursor.row()->pos() &&
2207 bidi_level(pos) % 2 ==
2208 bidi_level(pos - 1) % 2)
2210 else if (pos + 1 < cursor.par()->size())
2216 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2217 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2219 if (cursor.pos() == cursor.par()->size() &&
2220 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2221 !cursor.boundary()) {
2222 Language const * lang =
2223 cursor.par()->getParLanguage(bview->buffer()->params);
2224 current_font.setLanguage(lang);
2225 current_font.setNumber(LyXFont::OFF);
2226 real_current_font.setLanguage(lang);
2227 real_current_font.setNumber(LyXFont::OFF);
2232 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2234 LyXCursor old_cursor = cursor;
2236 /* get the row first */
2238 Row * row = GetRowNearY(y);
2239 cursor.par(row->par());
2242 int column = GetColumnNearX(bview, row, x, bound);
2243 cursor.pos(row->pos() + column);
2245 cursor.y(y + row->baseline());
2247 cursor.boundary(bound);
2248 SetCurrentFont(bview);
2249 DeleteEmptyParagraphMechanism(bview, old_cursor);
2253 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2256 /* get the row first */
2258 Row * row = GetRowNearY(y);
2260 int column = GetColumnNearX(bview, row, x, bound);
2262 cur.par(row->par());
2263 cur.pos(row->pos() + column);
2265 cur.y(y + row->baseline());
2267 cur.boundary(bound);
2271 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2273 if (cursor.pos() > 0) {
2274 bool boundary = cursor.boundary();
2275 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2276 if (!internal && !boundary &&
2277 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2278 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2279 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2280 LyXParagraph * par = cursor.par()->previous();
2281 SetCursor(bview, par, par->size());
2286 void LyXText::CursorRight(BufferView * bview, bool internal) const
2288 if (!internal && cursor.boundary() &&
2289 !cursor.par()->IsNewline(cursor.pos()))
2290 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2291 else if (cursor.pos() < cursor.par()->size()) {
2292 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2294 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2295 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2296 } else if (cursor.par()->next())
2297 SetCursor(bview, cursor.par()->next(), 0);
2301 void LyXText::CursorUp(BufferView * bview) const
2303 SetCursorFromCoordinates(bview, cursor.x_fix(),
2304 cursor.y() - cursor.row()->baseline() - 1);
2308 void LyXText::CursorDown(BufferView * bview) const
2310 SetCursorFromCoordinates(bview, cursor.x_fix(),
2311 cursor.y() - cursor.row()->baseline()
2312 + cursor.row()->height() + 1);
2316 void LyXText::CursorUpParagraph(BufferView * bview) const
2318 if (cursor.pos() > 0) {
2319 SetCursor(bview, cursor.par(), 0);
2321 else if (cursor.par()->previous()) {
2322 SetCursor(bview, cursor.par()->previous(), 0);
2327 void LyXText::CursorDownParagraph(BufferView * bview) const
2329 if (cursor.par()->next()) {
2330 SetCursor(bview, cursor.par()->next(), 0);
2332 SetCursor(bview, cursor.par(), cursor.par()->size());
2337 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
2338 LyXCursor const & old_cursor) const
2340 // Would be wrong to delete anything if we have a selection.
2341 if (selection) return;
2343 // We allow all kinds of "mumbo-jumbo" when freespacing.
2344 if (textclasslist.Style(bview->buffer()->params.textclass,
2345 old_cursor.par()->GetLayout()).free_spacing)
2348 bool deleted = false;
2350 /* Ok I'll put some comments here about what is missing.
2351 I have fixed BackSpace (and thus Delete) to not delete
2352 double-spaces automagically. I have also changed Cut,
2353 Copy and Paste to hopefully do some sensible things.
2354 There are still some small problems that can lead to
2355 double spaces stored in the document file or space at
2356 the beginning of paragraphs. This happens if you have
2357 the cursor betwenn to spaces and then save. Or if you
2358 cut and paste and the selection have a space at the
2359 beginning and then save right after the paste. I am
2360 sure none of these are very hard to fix, but I will
2361 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2362 that I can get some feedback. (Lgb)
2365 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2366 // delete the LineSeparator.
2369 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2370 // delete the LineSeparator.
2373 // If the pos around the old_cursor were spaces, delete one of them.
2374 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
2375 // Only if the cursor has really moved
2377 if (old_cursor.pos() > 0
2378 && old_cursor.pos() < old_cursor.par()->size()
2379 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
2380 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
2381 old_cursor.par()->Erase(old_cursor.pos() - 1);
2382 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
2384 if (old_cursor.par() == cursor.par() &&
2385 cursor.pos() > old_cursor.pos()) {
2386 SetCursorIntern(bview, cursor.par(),
2389 SetCursorIntern(bview, cursor.par(),
2395 // Do not delete empty paragraphs with keepempty set.
2396 if ((textclasslist.Style(bview->buffer()->params.textclass,
2397 old_cursor.par()->GetLayout())).keepempty)
2400 LyXCursor tmpcursor;
2402 if (old_cursor.par() != cursor.par()) {
2403 if ((old_cursor.par()->size() == 0
2404 || (old_cursor.par()->size() == 1
2405 && old_cursor.par()->IsLineSeparator(0)))) {
2406 // ok, we will delete anything
2408 // make sure that you do not delete any environments
2409 status = LyXText::NEED_MORE_REFRESH;
2412 if (old_cursor.row()->previous()) {
2413 refresh_row = old_cursor.row()->previous();
2414 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2416 cursor = old_cursor; // that undo can restore the right cursor position
2417 LyXParagraph * endpar = old_cursor.par()->next();
2418 if (endpar && endpar->GetDepth()) {
2419 while (endpar && endpar->GetDepth()) {
2420 endpar = endpar->next();
2423 SetUndo(bview->buffer(), Undo::DELETE,
2424 old_cursor.par()->previous(),
2429 RemoveRow(old_cursor.row());
2430 if (OwnerParagraph() == old_cursor.par()) {
2431 OwnerParagraph(OwnerParagraph()->next());
2434 delete old_cursor.par();
2436 /* Breakagain the next par. Needed
2437 * because of the parindent that
2438 * can occur or dissappear. The
2439 * next row can change its height,
2440 * if there is another layout before */
2441 if (refresh_row->next()) {
2442 BreakAgain(bview, refresh_row->next());
2443 UpdateCounters(bview, refresh_row);
2445 SetHeightOfRow(bview, refresh_row);
2447 refresh_row = old_cursor.row()->next();
2448 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2451 cursor = old_cursor; // that undo can restore the right cursor position
2452 LyXParagraph * endpar = old_cursor.par()->next();
2453 if (endpar && endpar->GetDepth()) {
2454 while (endpar && endpar->GetDepth()) {
2455 endpar = endpar->next();
2458 SetUndo(bview->buffer(), Undo::DELETE,
2459 old_cursor.par()->previous(),
2464 RemoveRow(old_cursor.row());
2466 if (OwnerParagraph() == old_cursor.par()) {
2467 OwnerParagraph(OwnerParagraph()->next());
2470 delete old_cursor.par();
2472 /* Breakagain the next par. Needed
2473 because of the parindent that can
2474 occur or dissappear.
2475 The next row can change its height,
2476 if there is another layout before
2479 BreakAgain(bview, refresh_row);
2480 UpdateCounters(bview, refresh_row->previous());
2486 SetCursorIntern(bview, cursor.par(), cursor.pos());
2488 if (sel_cursor.par() == old_cursor.par()
2489 && sel_cursor.pos() == sel_cursor.pos()) {
2490 // correct selection
2491 sel_cursor = cursor;
2495 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
2496 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
2498 SetCursorIntern(bview, cursor.par(), cursor.pos());
2499 sel_cursor = cursor;
2506 LyXParagraph * LyXText::GetParFromID(int id)
2508 LyXParagraph * result = FirstParagraph();
2509 while (result && result->id() != id)
2510 result = result->next();
2516 bool LyXText::TextUndo(BufferView * bview)
2520 // returns false if no undo possible
2521 Undo * undo = bview->buffer()->undostack.pop();
2525 bview->buffer()->redostack
2526 .push(CreateUndo(bview->buffer(), undo->kind,
2527 GetParFromID(undo->number_of_before_par),
2528 GetParFromID(undo->number_of_behind_par)));
2530 return TextHandleUndo(bview, undo);
2534 bool LyXText::TextRedo(BufferView * bview)
2538 // returns false if no redo possible
2539 Undo * undo = bview->buffer()->redostack.pop();
2543 bview->buffer()->undostack
2544 .push(CreateUndo(bview->buffer(), undo->kind,
2545 GetParFromID(undo->number_of_before_par),
2546 GetParFromID(undo->number_of_behind_par)));
2548 return TextHandleUndo(bview, undo);
2552 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
2556 // returns false if no undo possible
2557 bool result = false;
2559 LyXParagraph * before =
2560 GetParFromID(undo->number_of_before_par);
2561 LyXParagraph * behind =
2562 GetParFromID(undo->number_of_behind_par);
2563 LyXParagraph * tmppar;
2564 LyXParagraph * tmppar2;
2565 LyXParagraph * endpar;
2566 LyXParagraph * tmppar5;
2568 // if there's no before take the beginning
2569 // of the document for redoing
2571 SetCursorIntern(bview, FirstParagraph(), 0);
2573 // replace the paragraphs with the undo informations
2575 LyXParagraph * tmppar3 = undo->par;
2576 undo->par = 0; // otherwise the undo destructor would delete the paragraph
2577 LyXParagraph * tmppar4 = tmppar3;
2580 while (tmppar4->next())
2581 tmppar4 = tmppar4->next();
2582 } // get last undo par
2584 // now remove the old text if there is any
2585 if (before != behind || (!behind && !before)) {
2587 tmppar5 = before->next();
2589 tmppar5 = OwnerParagraph();
2591 while (tmppar5 && tmppar5 != behind) {
2593 tmppar5 = tmppar5->next();
2594 // a memory optimization for edit: Only layout information
2595 // is stored in the undo. So restore the text informations.
2596 if (undo->kind == Undo::EDIT) {
2597 tmppar2->setContentsFromPar(tmppar);
2598 tmppar->clearContents();
2599 tmppar2 = tmppar2->next();
2604 // put the new stuff in the list if there is one
2607 before->next(tmppar3);
2609 OwnerParagraph(tmppar3);
2610 tmppar3->previous(before);
2613 OwnerParagraph(behind);
2616 tmppar4->next(behind);
2618 behind->previous(tmppar4);
2622 // Set the cursor for redoing
2624 SetCursorIntern(bview, before, 0);
2627 // calculate the endpar for redoing the paragraphs.
2629 endpar = behind->next();
2633 tmppar = GetParFromID(undo->number_of_cursor_par);
2634 RedoParagraphs(bview, cursor, endpar);
2636 SetCursorIntern(bview, tmppar, undo->cursor_pos);
2637 UpdateCounters(bview, cursor.row());
2647 void LyXText::FinishUndo()
2651 // makes sure the next operation will be stored
2652 undo_finished = true;
2656 void LyXText::FreezeUndo()
2660 // this is dangerous and for internal use only
2665 void LyXText::UnFreezeUndo()
2669 // this is dangerous and for internal use only
2670 undo_frozen = false;
2674 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
2675 LyXParagraph const * before,
2676 LyXParagraph const * behind) const
2681 buf->undostack.push(CreateUndo(buf, kind, before, behind));
2682 buf->redostack.clear();
2686 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
2687 LyXParagraph const * before, LyXParagraph const * behind)
2691 buf->redostack.push(CreateUndo(buf, kind, before, behind));
2695 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
2696 LyXParagraph const * before,
2697 LyXParagraph const * behind) const
2702 int before_number = -1;
2703 int behind_number = -1;
2705 before_number = before->id();
2707 behind_number = behind->id();
2708 // Undo::EDIT and Undo::FINISH are
2709 // always finished. (no overlapping there)
2710 // overlapping only with insert and delete inside one paragraph:
2711 // Nobody wants all removed character
2712 // appear one by one when undoing.
2713 // EDIT is special since only layout information, not the
2714 // contents of a paragaph are stored.
2715 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
2716 // check wether storing is needed
2717 if (!buf->undostack.empty() &&
2718 buf->undostack.top()->kind == kind &&
2719 buf->undostack.top()->number_of_before_par == before_number &&
2720 buf->undostack.top()->number_of_behind_par == behind_number ){
2725 // create a new Undo
2726 LyXParagraph * undopar;
2728 LyXParagraph * start = 0;
2729 LyXParagraph * end = 0;
2732 start = const_cast<LyXParagraph*>(before->next());
2734 start = FirstParagraph();
2736 end = const_cast<LyXParagraph*>(behind->previous());
2738 end = FirstParagraph();
2742 if (start && end && (start != end->next()) &&
2743 ((before != behind) || (!before && !behind))) {
2744 LyXParagraph * tmppar = start;
2745 LyXParagraph * tmppar2 = new LyXParagraph(*tmppar);
2746 tmppar2->id(tmppar->id());
2748 // a memory optimization: Just store the layout information
2750 if (kind == Undo::EDIT){
2751 //tmppar2->text.clear();
2752 tmppar2->clearContents();
2757 while (tmppar != end && tmppar->next()) {
2758 tmppar = tmppar->next();
2759 tmppar2->next(new LyXParagraph(*tmppar));
2760 tmppar2->next()->id(tmppar->id());
2761 // a memory optimization: Just store the layout
2762 // information when only edit
2763 if (kind == Undo::EDIT){
2764 //tmppar2->next->text.clear();
2765 tmppar2->clearContents();
2767 tmppar2->next()->previous(tmppar2);
2768 tmppar2 = tmppar2->next();
2772 undopar = 0; // nothing to replace (undo of delete maybe)
2774 int cursor_par = cursor.par()->id();
2775 int cursor_pos = cursor.pos();
2777 Undo * undo = new Undo(kind,
2778 before_number, behind_number,
2779 cursor_par, cursor_pos,
2782 undo_finished = false;
2787 void LyXText::SetCursorParUndo(Buffer * buf)
2791 SetUndo(buf, Undo::FINISH,
2792 cursor.par()->previous(),
2793 cursor.par()->next());
2797 void LyXText::toggleAppendix(BufferView * bview)
2799 LyXParagraph * par = cursor.par();
2800 bool start = !par->params.startOfAppendix();
2802 // ensure that we have only one start_of_appendix in this document
2803 LyXParagraph * tmp = FirstParagraph();
2804 for (; tmp; tmp = tmp->next())
2805 tmp->params.startOfAppendix(false);
2807 par->params.startOfAppendix(start);
2809 // we can set the refreshing parameters now
2810 status = LyXText::NEED_MORE_REFRESH;
2812 refresh_row = 0; // not needed for full update
2813 UpdateCounters(bview, 0);
2814 SetCursor(bview, cursor.par(), cursor.pos());
2818 LyXParagraph * LyXText::OwnerParagraph() const
2821 return inset_owner->par;
2823 return bv_owner->buffer()->paragraph;
2827 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
2830 inset_owner->par = p;
2832 bv_owner->buffer()->paragraph = p;