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 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_start_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();
1696 int pos = sel_end_cursor.pos();
1697 cap.cutSelection(sel_start_cursor.par(), &endpar,
1698 sel_start_cursor.pos(), pos,
1699 bview->buffer()->params.textclass, doclear);
1701 sel_end_cursor.par(endpar);
1702 sel_end_cursor.pos(pos);
1703 cursor.pos(sel_end_cursor.pos());
1705 endpar = endpar->next();
1707 // sometimes necessary
1709 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
1711 RedoParagraphs(bview, sel_start_cursor, endpar);
1713 ClearSelection(bview);
1714 cursor = sel_start_cursor;
1715 SetCursor(bview, cursor.par(), cursor.pos());
1716 sel_cursor = cursor;
1717 UpdateCounters(bview, cursor.row());
1721 void LyXText::CopySelection(BufferView * bview)
1723 // Stuff what we got on the clipboard. Even if there is no selection.
1725 // There is a problem with having the stuffing here in that the
1726 // larger the selection the slower LyX will get. This can be
1727 // solved by running the line below only when the selection has
1728 // finished. The solution used currently just works, to make it
1729 // faster we need to be more clever and probably also have more
1730 // calls to stuffClipboard. (Lgb)
1731 bview->stuffClipboard(selectionAsString(bview->buffer()));
1733 // this doesnt make sense, if there is no selection
1737 // ok we have a selection. This is always between sel_start_cursor
1738 // and sel_end cursor
1740 // copy behind a space if there is one
1741 while (sel_start_cursor.par()->size() > sel_start_cursor.pos()
1742 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
1743 && (sel_start_cursor.par() != sel_end_cursor.par()
1744 || sel_start_cursor.pos() < sel_end_cursor.pos()))
1745 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
1749 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
1750 sel_start_cursor.pos(), sel_end_cursor.pos(),
1751 bview->buffer()->params.textclass);
1755 void LyXText::PasteSelection(BufferView * bview)
1759 // this does not make sense, if there is nothing to paste
1760 if (!cap.checkPastePossible(cursor.par()))
1763 SetUndo(bview->buffer(), Undo::INSERT,
1764 cursor.par()->previous(),
1765 cursor.par()->next());
1767 LyXParagraph * endpar;
1768 LyXParagraph * actpar = cursor.par();
1770 int pos = cursor.pos();
1771 cap.pasteSelection(&actpar, &endpar, pos,
1772 bview->buffer()->params.textclass);
1774 RedoParagraphs(bview, cursor, endpar);
1776 SetCursor(bview, cursor.par(), cursor.pos());
1777 ClearSelection(bview);
1779 sel_cursor = cursor;
1780 SetCursor(bview, actpar, pos);
1781 SetSelection(bview);
1782 UpdateCounters(bview, cursor.row());
1786 // returns a pointer to the very first LyXParagraph
1787 LyXParagraph * LyXText::FirstParagraph() const
1789 return OwnerParagraph();
1793 // sets the selection over the number of characters of string, no check!!
1794 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
1796 sel_cursor = cursor;
1797 for (int i = 0; str[i]; ++i)
1799 SetSelection(bview);
1803 // simple replacing. The font of the first selected character is used
1804 void LyXText::ReplaceSelectionWithString(BufferView * bview,
1807 SetCursorParUndo(bview->buffer());
1810 if (!selection) { // create a dummy selection
1811 sel_end_cursor = cursor;
1812 sel_start_cursor = cursor;
1815 // Get font setting before we cut
1816 LyXParagraph::size_type pos = sel_end_cursor.pos();
1817 LyXFont const font = sel_start_cursor.par()
1818 ->GetFontSettings(bview->buffer()->params,
1819 sel_start_cursor.pos());
1821 // Insert the new string
1822 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
1823 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
1827 // Cut the selection
1828 CutSelection(bview);
1834 // needed to insert the selection
1835 void LyXText::InsertStringA(BufferView * bview, string const & str)
1837 LyXParagraph * par = cursor.par();
1838 LyXParagraph::size_type pos = cursor.pos();
1839 LyXParagraph::size_type a = 0;
1840 LyXParagraph * endpar = cursor.par()->next();
1842 SetCursorParUndo(bview->buffer());
1845 textclasslist.Style(bview->buffer()->params.textclass,
1846 cursor.par()->GetLayout()).isEnvironment();
1847 // only to be sure, should not be neccessary
1848 ClearSelection(bview);
1850 // insert the string, don't insert doublespace
1851 string::size_type i = 0;
1852 while (i < str.length()) {
1853 if (str[i] != '\n') {
1855 && i + 1 < str.length() && str[i + 1] != ' '
1856 && pos && par->GetChar(pos - 1)!= ' ') {
1857 par->InsertChar(pos, ' ', current_font);
1859 } else if (str[i] == ' ') {
1860 InsetSpecialChar * new_inset =
1861 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1862 if (par->InsertInsetAllowed(new_inset)) {
1863 par->InsertInset(pos, new_inset,
1869 } else if (str[i] == '\t') {
1870 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
1871 InsetSpecialChar * new_inset =
1872 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1873 if (par->InsertInsetAllowed(new_inset)) {
1874 par->InsertInset(pos, new_inset,
1881 } else if (str[i] != 13 &&
1882 // Ignore unprintables
1883 (str[i] & 127) >= ' ') {
1884 par->InsertChar(pos, str[i], current_font);
1888 if (!par->size()) { // par is empty
1889 InsetSpecialChar * new_inset =
1890 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
1891 if (par->InsertInsetAllowed(new_inset)) {
1892 par->InsertInset(pos,
1900 par->BreakParagraph(bview->buffer()->params, pos, flag);
1907 RedoParagraphs(bview, cursor, endpar);
1908 SetCursor(bview, cursor.par(), cursor.pos());
1909 sel_cursor = cursor;
1910 SetCursor(bview, par, pos);
1911 SetSelection(bview);
1915 /* turns double-CR to single CR, others where converted into one blank and 13s
1916 * that are ignored .Double spaces are also converted into one. Spaces at
1917 * the beginning of a paragraph are forbidden. tabs are converted into one
1918 * space. then InsertStringA is called */
1919 void LyXText::InsertStringB(BufferView * bview, string const & s)
1922 string::size_type i = 1;
1923 while (i < str.length()) {
1926 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
1928 if (str[i] == '\n' && i + 1 < str.length()) {
1929 if (str[i + 1] != '\n') {
1930 if (str[i - 1] != ' ')
1935 while (i + 1 < str.length()
1936 && (str[i + 1] == ' '
1937 || str[i + 1] == '\t'
1938 || str[i + 1] == '\n'
1939 || str[i + 1] == 13)) {
1946 InsertStringA(bview, str);
1950 bool LyXText::GotoNextInset(BufferView * bview,
1951 std::vector<Inset::Code> const & codes,
1952 string const & contents) const
1954 LyXCursor res = cursor;
1957 if (res.pos() < res.par()->size() - 1) {
1958 res.pos(res.pos() + 1);
1960 res.par(res.par()->next());
1964 } while (res.par() &&
1965 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
1966 && (inset = res.par()->GetInset(res.pos())) != 0
1967 && find(codes.begin(), codes.end(), inset->LyxCode())
1969 && (contents.empty() ||
1970 static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
1974 SetCursor(bview, res.par(), res.pos());
1981 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
1982 LyXParagraph::size_type pos)
1984 LyXCursor tmpcursor;
1987 LyXParagraph::size_type z;
1988 Row * row = GetRow(par, pos, y);
1990 // is there a break one row above
1991 if (row->previous() && row->previous()->par() == row->par()) {
1992 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
1993 if (z >= row->pos()) {
1994 // set the dimensions of the row above
1995 y -= row->previous()->height();
1997 refresh_row = row->previous();
1998 status = LyXText::NEED_MORE_REFRESH;
2000 BreakAgain(bview, row->previous());
2002 // set the cursor again. Otherwise
2003 // dangling pointers are possible
2004 SetCursor(bview, cursor.par(), cursor.pos(),
2005 false, cursor.boundary());
2006 sel_cursor = cursor;
2011 int const tmpheight = row->height();
2012 LyXParagraph::size_type const tmplast = RowLast(row);
2016 BreakAgain(bview, row);
2017 if (row->height() == tmpheight && RowLast(row) == tmplast)
2018 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2020 status = LyXText::NEED_MORE_REFRESH;
2022 // check the special right address boxes
2023 if (textclasslist.Style(bview->buffer()->params.textclass,
2024 par->GetLayout()).margintype
2025 == MARGIN_RIGHT_ADDRESS_BOX) {
2032 RedoDrawingOfParagraph(bview, tmpcursor);
2035 // set the cursor again. Otherwise dangling pointers are possible
2036 // also set the selection
2040 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2041 false, sel_cursor.boundary());
2042 sel_cursor = cursor;
2043 SetCursorIntern(bview, sel_start_cursor.par(),
2044 sel_start_cursor.pos(),
2045 false, sel_start_cursor.boundary());
2046 sel_start_cursor = cursor;
2047 SetCursorIntern(bview, sel_end_cursor.par(),
2048 sel_end_cursor.pos(),
2049 false, sel_end_cursor.boundary());
2050 sel_end_cursor = cursor;
2051 SetCursorIntern(bview, last_sel_cursor.par(),
2052 last_sel_cursor.pos(),
2053 false, last_sel_cursor.boundary());
2054 last_sel_cursor = cursor;
2057 SetCursorIntern(bview, cursor.par(), cursor.pos(),
2058 false, cursor.boundary());
2062 // returns false if inset wasn't found
2063 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2065 // first check the current paragraph
2066 int pos = cursor.par()->GetPositionOfInset(inset);
2068 CheckParagraph(bview, cursor.par(), pos);
2072 // check every paragraph
2074 LyXParagraph * par = FirstParagraph();
2076 pos = par->GetPositionOfInset(inset);
2078 CheckParagraph(bview, par, pos);
2088 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2089 LyXParagraph::size_type pos,
2090 bool setfont, bool boundary) const
2092 LyXCursor old_cursor = cursor;
2093 SetCursorIntern(bview, par, pos, setfont, boundary);
2094 DeleteEmptyParagraphMechanism(bview, old_cursor);
2098 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2099 LyXParagraph::size_type pos, bool boundary) const
2103 cur.boundary(boundary);
2105 /* get the cursor y position in text */
2107 Row * row = GetRow(par, pos, y);
2108 /* y is now the beginning of the cursor row */
2109 y += row->baseline();
2110 /* y is now the cursor baseline */
2113 /* now get the cursors x position */
2115 float fill_separator, fill_hfill, fill_label_hfill;
2116 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2118 LyXParagraph::size_type cursor_vpos = 0;
2119 LyXParagraph::size_type last = RowLastPrintable(row);
2121 if (pos > last + 1) // This shouldn't happen.
2123 else if (pos < row->pos())
2126 if (last < row->pos())
2127 cursor_vpos = row->pos();
2128 else if (pos > last && !boundary)
2129 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2130 ? row->pos() : last + 1;
2131 else if (pos > row->pos() &&
2132 (pos > last || boundary))
2133 /// Place cursor after char at (logical) position pos - 1
2134 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2135 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2137 /// Place cursor before char at (logical) position pos
2138 cursor_vpos = (bidi_level(pos) % 2 == 0)
2139 ? log2vis(pos) : log2vis(pos) + 1;
2141 LyXParagraph::size_type main_body =
2142 BeginningOfMainBody(bview->buffer(), row->par());
2143 if ((main_body > 0) &&
2144 ((main_body-1 > last) ||
2145 !row->par()->IsLineSeparator(main_body-1)))
2148 for (LyXParagraph::size_type vpos = row->pos();
2149 vpos < cursor_vpos; ++vpos) {
2150 pos = vis2log(vpos);
2151 if (main_body > 0 && pos == main_body - 1) {
2152 x += fill_label_hfill +
2153 lyxfont::width(textclasslist.Style(
2154 bview->buffer()->params.textclass,
2155 row->par()->GetLayout())
2157 GetFont(bview->buffer(), row->par(), -2));
2158 if (row->par()->IsLineSeparator(main_body-1))
2159 x -= SingleWidth(bview, row->par(),main_body-1);
2161 if (HfillExpansion(bview->buffer(), row, pos)) {
2162 x += SingleWidth(bview, row->par(), pos);
2163 if (pos >= main_body)
2166 x += fill_label_hfill;
2167 } else if (row->par()->IsSeparator(pos)) {
2168 x += SingleWidth(bview, row->par(), pos);
2169 if (pos >= main_body)
2170 x += fill_separator;
2172 x += SingleWidth(bview, row->par(), pos);
2181 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2182 LyXParagraph::size_type pos,
2183 bool setfont, bool boundary) const
2185 SetCursor(bview, cursor, par, pos, boundary);
2187 SetCurrentFont(bview);
2191 void LyXText::SetCurrentFont(BufferView * bview) const
2193 LyXParagraph::size_type pos = cursor.pos();
2194 if (cursor.boundary() && pos > 0)
2198 if (pos == cursor.par()->size())
2200 else if (cursor.par()->IsSeparator(pos)) {
2201 if (pos > cursor.row()->pos() &&
2202 bidi_level(pos) % 2 ==
2203 bidi_level(pos - 1) % 2)
2205 else if (pos + 1 < cursor.par()->size())
2211 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2212 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2214 if (cursor.pos() == cursor.par()->size() &&
2215 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2216 !cursor.boundary()) {
2217 Language const * lang =
2218 cursor.par()->getParLanguage(bview->buffer()->params);
2219 current_font.setLanguage(lang);
2220 current_font.setNumber(LyXFont::OFF);
2221 real_current_font.setLanguage(lang);
2222 real_current_font.setNumber(LyXFont::OFF);
2227 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2229 LyXCursor old_cursor = cursor;
2231 /* get the row first */
2233 Row * row = GetRowNearY(y);
2234 cursor.par(row->par());
2237 int column = GetColumnNearX(bview, row, x, bound);
2238 cursor.pos(row->pos() + column);
2240 cursor.y(y + row->baseline());
2242 cursor.boundary(bound);
2243 SetCurrentFont(bview);
2244 DeleteEmptyParagraphMechanism(bview, old_cursor);
2248 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2251 /* get the row first */
2253 Row * row = GetRowNearY(y);
2255 int column = GetColumnNearX(bview, row, x, bound);
2257 cur.par(row->par());
2258 cur.pos(row->pos() + column);
2260 cur.y(y + row->baseline());
2262 cur.boundary(bound);
2266 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2268 if (cursor.pos() > 0) {
2269 bool boundary = cursor.boundary();
2270 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2271 if (!internal && !boundary &&
2272 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2273 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2274 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2275 LyXParagraph * par = cursor.par()->previous();
2276 SetCursor(bview, par, par->size());
2281 void LyXText::CursorRight(BufferView * bview, bool internal) const
2283 if (!internal && cursor.boundary() &&
2284 !cursor.par()->IsNewline(cursor.pos()))
2285 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2286 else if (cursor.pos() < cursor.par()->size()) {
2287 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2289 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2290 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2291 } else if (cursor.par()->next())
2292 SetCursor(bview, cursor.par()->next(), 0);
2296 void LyXText::CursorUp(BufferView * bview) const
2298 SetCursorFromCoordinates(bview, cursor.x_fix(),
2299 cursor.y() - cursor.row()->baseline() - 1);
2303 void LyXText::CursorDown(BufferView * bview) const
2305 SetCursorFromCoordinates(bview, cursor.x_fix(),
2306 cursor.y() - cursor.row()->baseline()
2307 + cursor.row()->height() + 1);
2311 void LyXText::CursorUpParagraph(BufferView * bview) const
2313 if (cursor.pos() > 0) {
2314 SetCursor(bview, cursor.par(), 0);
2316 else if (cursor.par()->previous()) {
2317 SetCursor(bview, cursor.par()->previous(), 0);
2322 void LyXText::CursorDownParagraph(BufferView * bview) const
2324 if (cursor.par()->next()) {
2325 SetCursor(bview, cursor.par()->next(), 0);
2327 SetCursor(bview, cursor.par(), cursor.par()->size());
2332 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
2333 LyXCursor const & old_cursor) const
2335 // Would be wrong to delete anything if we have a selection.
2336 if (selection) return;
2338 // We allow all kinds of "mumbo-jumbo" when freespacing.
2339 if (textclasslist.Style(bview->buffer()->params.textclass,
2340 old_cursor.par()->GetLayout()).free_spacing)
2343 bool deleted = false;
2345 /* Ok I'll put some comments here about what is missing.
2346 I have fixed BackSpace (and thus Delete) to not delete
2347 double-spaces automagically. I have also changed Cut,
2348 Copy and Paste to hopefully do some sensible things.
2349 There are still some small problems that can lead to
2350 double spaces stored in the document file or space at
2351 the beginning of paragraphs. This happens if you have
2352 the cursor betwenn to spaces and then save. Or if you
2353 cut and paste and the selection have a space at the
2354 beginning and then save right after the paste. I am
2355 sure none of these are very hard to fix, but I will
2356 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2357 that I can get some feedback. (Lgb)
2360 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2361 // delete the LineSeparator.
2364 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2365 // delete the LineSeparator.
2368 // If the pos around the old_cursor were spaces, delete one of them.
2369 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
2370 // Only if the cursor has really moved
2372 if (old_cursor.pos() > 0
2373 && old_cursor.pos() < old_cursor.par()->size()
2374 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
2375 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
2376 old_cursor.par()->Erase(old_cursor.pos() - 1);
2377 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
2379 if (old_cursor.par() == cursor.par() &&
2380 cursor.pos() > old_cursor.pos()) {
2381 SetCursorIntern(bview, cursor.par(),
2384 SetCursorIntern(bview, cursor.par(),
2390 // Do not delete empty paragraphs with keepempty set.
2391 if ((textclasslist.Style(bview->buffer()->params.textclass,
2392 old_cursor.par()->GetLayout())).keepempty)
2395 LyXCursor tmpcursor;
2397 if (old_cursor.par() != cursor.par()) {
2398 if ((old_cursor.par()->size() == 0
2399 || (old_cursor.par()->size() == 1
2400 && old_cursor.par()->IsLineSeparator(0)))) {
2401 // ok, we will delete anything
2403 // make sure that you do not delete any environments
2404 status = LyXText::NEED_MORE_REFRESH;
2407 if (old_cursor.row()->previous()) {
2408 refresh_row = old_cursor.row()->previous();
2409 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
2411 cursor = old_cursor; // that undo can restore the right cursor position
2412 LyXParagraph * endpar = old_cursor.par()->next();
2413 if (endpar && endpar->GetDepth()) {
2414 while (endpar && endpar->GetDepth()) {
2415 endpar = endpar->next();
2418 SetUndo(bview->buffer(), Undo::DELETE,
2419 old_cursor.par()->previous(),
2424 RemoveRow(old_cursor.row());
2425 if (OwnerParagraph() == old_cursor.par()) {
2426 OwnerParagraph(OwnerParagraph()->next());
2429 delete old_cursor.par();
2431 /* Breakagain the next par. Needed
2432 * because of the parindent that
2433 * can occur or dissappear. The
2434 * next row can change its height,
2435 * if there is another layout before */
2436 if (refresh_row->next()) {
2437 BreakAgain(bview, refresh_row->next());
2438 UpdateCounters(bview, refresh_row);
2440 SetHeightOfRow(bview, refresh_row);
2442 refresh_row = old_cursor.row()->next();
2443 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
2446 cursor = old_cursor; // that undo can restore the right cursor position
2447 LyXParagraph * endpar = old_cursor.par()->next();
2448 if (endpar && endpar->GetDepth()) {
2449 while (endpar && endpar->GetDepth()) {
2450 endpar = endpar->next();
2453 SetUndo(bview->buffer(), Undo::DELETE,
2454 old_cursor.par()->previous(),
2459 RemoveRow(old_cursor.row());
2461 if (OwnerParagraph() == old_cursor.par()) {
2462 OwnerParagraph(OwnerParagraph()->next());
2465 delete old_cursor.par();
2467 /* Breakagain the next par. Needed
2468 because of the parindent that can
2469 occur or dissappear.
2470 The next row can change its height,
2471 if there is another layout before
2474 BreakAgain(bview, refresh_row);
2475 UpdateCounters(bview, refresh_row->previous());
2481 SetCursorIntern(bview, cursor.par(), cursor.pos());
2483 if (sel_cursor.par() == old_cursor.par()
2484 && sel_cursor.pos() == sel_cursor.pos()) {
2485 // correct selection
2486 sel_cursor = cursor;
2490 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
2491 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
2493 SetCursorIntern(bview, cursor.par(), cursor.pos());
2494 sel_cursor = cursor;
2501 LyXParagraph * LyXText::GetParFromID(int id)
2503 LyXParagraph * result = FirstParagraph();
2504 while (result && result->id() != id)
2505 result = result->next();
2511 bool LyXText::TextUndo(BufferView * bview)
2515 // returns false if no undo possible
2516 Undo * undo = bview->buffer()->undostack.pop();
2520 bview->buffer()->redostack
2521 .push(CreateUndo(bview->buffer(), undo->kind,
2522 GetParFromID(undo->number_of_before_par),
2523 GetParFromID(undo->number_of_behind_par)));
2525 return TextHandleUndo(bview, undo);
2529 bool LyXText::TextRedo(BufferView * bview)
2533 // returns false if no redo possible
2534 Undo * undo = bview->buffer()->redostack.pop();
2538 bview->buffer()->undostack
2539 .push(CreateUndo(bview->buffer(), undo->kind,
2540 GetParFromID(undo->number_of_before_par),
2541 GetParFromID(undo->number_of_behind_par)));
2543 return TextHandleUndo(bview, undo);
2547 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
2551 // returns false if no undo possible
2552 bool result = false;
2554 LyXParagraph * before =
2555 GetParFromID(undo->number_of_before_par);
2556 LyXParagraph * behind =
2557 GetParFromID(undo->number_of_behind_par);
2558 LyXParagraph * tmppar;
2559 LyXParagraph * tmppar2;
2560 LyXParagraph * endpar;
2561 LyXParagraph * tmppar5;
2563 // if there's no before take the beginning
2564 // of the document for redoing
2566 SetCursorIntern(bview, FirstParagraph(), 0);
2568 // replace the paragraphs with the undo informations
2570 LyXParagraph * tmppar3 = undo->par;
2571 undo->par = 0; // otherwise the undo destructor would delete the paragraph
2572 LyXParagraph * tmppar4 = tmppar3;
2575 while (tmppar4->next())
2576 tmppar4 = tmppar4->next();
2577 } // get last undo par
2579 // now remove the old text if there is any
2580 if (before != behind || (!behind && !before)) {
2582 tmppar5 = before->next();
2584 tmppar5 = OwnerParagraph();
2586 while (tmppar5 && tmppar5 != behind) {
2588 tmppar5 = tmppar5->next();
2589 // a memory optimization for edit: Only layout information
2590 // is stored in the undo. So restore the text informations.
2591 if (undo->kind == Undo::EDIT) {
2592 tmppar2->setContentsFromPar(tmppar);
2593 tmppar->clearContents();
2594 tmppar2 = tmppar2->next();
2599 // put the new stuff in the list if there is one
2602 before->next(tmppar3);
2604 OwnerParagraph(tmppar3);
2605 tmppar3->previous(before);
2608 OwnerParagraph(behind);
2611 tmppar4->next(behind);
2613 behind->previous(tmppar4);
2617 // Set the cursor for redoing
2619 SetCursorIntern(bview, before, 0);
2622 // calculate the endpar for redoing the paragraphs.
2624 endpar = behind->next();
2628 tmppar = GetParFromID(undo->number_of_cursor_par);
2629 RedoParagraphs(bview, cursor, endpar);
2631 SetCursorIntern(bview, tmppar, undo->cursor_pos);
2632 UpdateCounters(bview, cursor.row());
2642 void LyXText::FinishUndo()
2646 // makes sure the next operation will be stored
2647 undo_finished = true;
2651 void LyXText::FreezeUndo()
2655 // this is dangerous and for internal use only
2660 void LyXText::UnFreezeUndo()
2664 // this is dangerous and for internal use only
2665 undo_frozen = false;
2669 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
2670 LyXParagraph const * before,
2671 LyXParagraph const * behind) const
2676 buf->undostack.push(CreateUndo(buf, kind, before, behind));
2677 buf->redostack.clear();
2681 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
2682 LyXParagraph const * before, LyXParagraph const * behind)
2686 buf->redostack.push(CreateUndo(buf, kind, before, behind));
2690 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
2691 LyXParagraph const * before,
2692 LyXParagraph const * behind) const
2697 int before_number = -1;
2698 int behind_number = -1;
2700 before_number = before->id();
2702 behind_number = behind->id();
2703 // Undo::EDIT and Undo::FINISH are
2704 // always finished. (no overlapping there)
2705 // overlapping only with insert and delete inside one paragraph:
2706 // Nobody wants all removed character
2707 // appear one by one when undoing.
2708 // EDIT is special since only layout information, not the
2709 // contents of a paragaph are stored.
2710 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
2711 // check wether storing is needed
2712 if (!buf->undostack.empty() &&
2713 buf->undostack.top()->kind == kind &&
2714 buf->undostack.top()->number_of_before_par == before_number &&
2715 buf->undostack.top()->number_of_behind_par == behind_number ){
2720 // create a new Undo
2721 LyXParagraph * undopar;
2723 LyXParagraph * start = 0;
2724 LyXParagraph * end = 0;
2727 start = const_cast<LyXParagraph*>(before->next());
2729 start = FirstParagraph();
2731 end = const_cast<LyXParagraph*>(behind->previous());
2733 end = FirstParagraph();
2737 if (start && end && (start != end->next()) &&
2738 ((before != behind) || (!before && !behind))) {
2739 LyXParagraph * tmppar = start;
2740 LyXParagraph * tmppar2 = new LyXParagraph(*tmppar);
2741 tmppar2->id(tmppar->id());
2743 // a memory optimization: Just store the layout information
2745 if (kind == Undo::EDIT){
2746 //tmppar2->text.clear();
2747 tmppar2->clearContents();
2752 while (tmppar != end && tmppar->next()) {
2753 tmppar = tmppar->next();
2754 tmppar2->next(new LyXParagraph(*tmppar));
2755 tmppar2->next()->id(tmppar->id());
2756 // a memory optimization: Just store the layout
2757 // information when only edit
2758 if (kind == Undo::EDIT){
2759 //tmppar2->next->text.clear();
2760 tmppar2->clearContents();
2762 tmppar2->next()->previous(tmppar2);
2763 tmppar2 = tmppar2->next();
2767 undopar = 0; // nothing to replace (undo of delete maybe)
2769 int cursor_par = cursor.par()->id();
2770 int cursor_pos = cursor.pos();
2772 Undo * undo = new Undo(kind,
2773 before_number, behind_number,
2774 cursor_par, cursor_pos,
2777 undo_finished = false;
2782 void LyXText::SetCursorParUndo(Buffer * buf)
2786 SetUndo(buf, Undo::FINISH,
2787 cursor.par()->previous(),
2788 cursor.par()->next());
2792 void LyXText::toggleAppendix(BufferView * bview)
2794 LyXParagraph * par = cursor.par();
2795 bool start = !par->params.startOfAppendix();
2797 // ensure that we have only one start_of_appendix in this document
2798 LyXParagraph * tmp = FirstParagraph();
2799 for (; tmp; tmp = tmp->next())
2800 tmp->params.startOfAppendix(false);
2802 par->params.startOfAppendix(start);
2804 // we can set the refreshing parameters now
2805 status = LyXText::NEED_MORE_REFRESH;
2807 refresh_row = 0; // not needed for full update
2808 UpdateCounters(bview, 0);
2809 SetCursor(bview, cursor.par(), cursor.pos());
2813 LyXParagraph * LyXText::OwnerParagraph() const
2816 return inset_owner->par;
2818 return bv_owner->buffer()->paragraph;
2822 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
2825 inset_owner->par = p;
2827 bv_owner->buffer()->paragraph = p;