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"
21 #include "lyxparagraph.h"
22 #include "insets/inseterror.h"
23 #include "insets/insetbib.h"
24 #include "insets/insetspecialchar.h"
25 #include "insets/insettext.h"
26 #include "insets/insetfloat.h"
29 #include "support/textutils.h"
31 #include "minibuffer.h"
33 #include "bufferparams.h"
34 #include "lyx_gui_misc.h"
37 #include "BufferView.h"
40 #include "CutAndPaste.h"
45 #include "FloatList.h"
54 LyXText::LyXText(BufferView * bv)
62 LyXText::LyXText(InsetText * inset)
72 the_locking_inset = 0;
80 status = LyXText::UNCHANGED;
81 // set cursor at the very top position
82 selection = true; /* these setting is necessary
83 because of the delete-empty-
84 paragraph mechanism in
87 LyXParagraph * par = OwnerParagraph();
88 current_font = GetFont(bv_owner->buffer(), par, 0);
90 InsertParagraph(bv_owner, par, lastrow);
93 SetCursor(bv_owner, firstrow->par(), 0);
95 current_font = LyXFont(LyXFont::ALL_SANE);
101 // no rebreak necessary
104 undo_finished = true;
107 // Default layouttype for copy environment type
111 // Dump all rowinformation:
112 Row * tmprow = firstrow;
113 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
115 lyxerr << tmprow->baseline() << '\t'
116 << tmprow->par << '\t'
117 << tmprow->pos() << '\t'
118 << tmprow->height << '\t'
119 << tmprow->ascent_of_text << '\t'
120 << tmprow->fill << '\n';
121 tmprow = tmprow->next();
128 void LyXText::init(BufferView * bview)
133 LyXParagraph * par = OwnerParagraph();
134 current_font = GetFont(bview->buffer(), par, 0);
136 InsertParagraph(bview, par, lastrow);
139 SetCursorIntern(bview, firstrow->par(), 0);
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:
188 par->footnoteflag == LyXParagraph::NO_FOOTNOTE &&
193 if (layout.labeltype == LABEL_MANUAL
194 && pos < BeginningOfMainBody(buf, par)) {
196 LyXFont f = par->GetFontSettings(buf->params,
198 return f.realize(layout.reslabelfont);
200 LyXFont f = par->GetFontSettings(buf->params, pos);
201 return f.realize(layout.resfont);
206 // process layoutfont for pos == -1 and labelfont for pos < -1
208 return layout.resfont;
210 return layout.reslabelfont;
214 // The uncommon case need not be optimized as much
216 LyXFont layoutfont, tmpfont;
220 if (pos < BeginningOfMainBody(buf, par)) {
222 layoutfont = layout.labelfont;
225 layoutfont = layout.font;
227 tmpfont = par->GetFontSettings(buf->params, pos);
228 tmpfont.realize(layoutfont);
231 // process layoutfont for pos == -1 and labelfont for pos < -1
233 tmpfont = layout.font;
235 tmpfont = layout.labelfont;
238 // Resolve against environment font information
239 while (par && par_depth && !tmpfont.resolved()) {
240 par = par->DepthHook(par_depth - 1);
242 tmpfont.realize(textclasslist.
243 Style(buf->params.textclass,
244 par->GetLayout()).font);
245 par_depth = par->GetDepth();
249 tmpfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
252 // Cosmetic improvement: If this is an open footnote, make the font
254 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
255 && par->footnotekind == LyXParagraph::FOOTNOTE) {
263 void LyXText::SetCharFont(Buffer const * buf, LyXParagraph * par,
264 LyXParagraph::size_type pos,
268 // Let the insets convert their font
269 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
270 if (par->GetInset(pos))
271 font = par->GetInset(pos)->ConvertFont(font);
274 LyXLayout const & layout =
275 textclasslist.Style(buf->params.textclass,
278 // Get concrete layout font to reduce against
281 if (pos < BeginningOfMainBody(buf, par))
282 layoutfont = layout.labelfont;
284 layoutfont = layout.font;
286 // Realize against environment font information
287 if (par->GetDepth()){
288 LyXParagraph * tp = par;
289 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
290 tp = tp->DepthHook(tp->GetDepth()-1);
292 layoutfont.realize(textclasslist.
293 Style(buf->params.textclass,
294 tp->GetLayout()).font);
298 layoutfont.realize(textclasslist.TextClass(buf->params.textclass).defaultfont());
301 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
302 && par->footnotekind == LyXParagraph::FOOTNOTE) {
303 layoutfont.decSize();
306 // Now, reduce font against full layout font
307 font.reduce(layoutfont);
309 par->SetFont(pos, font);
313 /* inserts a new row behind the specified row, increments
314 * the touched counters */
315 void LyXText::InsertRow(Row * row, LyXParagraph * par,
316 LyXParagraph::size_type pos) const
318 Row * tmprow = new Row;
321 tmprow->next(firstrow);
324 tmprow->previous(row);
325 tmprow->next(row->next());
330 tmprow->next()->previous(tmprow);
332 if (tmprow->previous())
333 tmprow->previous()->next(tmprow);
341 ++number_of_rows; // one more row
345 // removes the row and reset the touched counters
346 void LyXText::RemoveRow(Row * row) const
348 /* this must not happen before the currentrow for clear reasons.
349 so the trick is just to set the current row onto the previous
352 GetRow(row->par(), row->pos(), unused_y);
355 row->next()->previous(row->previous());
356 if (!row->previous()) {
357 firstrow = row->next();
359 row->previous()->next(row->next());
362 lastrow = row->previous();
364 height -= row->height(); // the text becomes smaller
367 --number_of_rows; // one row less
371 // remove all following rows of the paragraph of the specified row.
372 void LyXText::RemoveParagraph(Row * row) const
374 LyXParagraph * tmppar = row->par();
378 while (row && row->par() == tmppar) {
379 tmprow = row->next();
386 // insert the specified paragraph behind the specified row
387 void LyXText::InsertParagraph(BufferView * bview, LyXParagraph * par,
390 InsertRow(row, par, 0); /* insert a new row, starting
393 SetCounter(bview->buffer(), par); // set the counters
395 // and now append the whole paragraph behind the new row
398 AppendParagraph(bview, firstrow);
400 row->next()->height(0);
401 AppendParagraph(bview, row->next());
407 void LyXText::ToggleFootnote(BufferView * bview)
409 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
411 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
413 bview->owner()->getMiniBuffer()->Set(_("Opened float"));
415 bview->owner()->getMiniBuffer()->Set(_("Closed float"));
416 CloseFootnote(bview);
423 void LyXText::OpenStuff(BufferView * bview)
425 if (cursor.pos() == 0 && cursor.par()->bibkey){
426 cursor.par()->bibkey->Edit(bview, 0, 0, 0);
427 } else if (cursor.pos() < cursor.par()->Last()
428 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
429 && cursor.par()->GetInset(cursor.pos())->Editable()) {
430 bview->owner()->getMiniBuffer()
431 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
432 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
433 SetCursorParUndo(bview->buffer());
434 cursor.par()->GetInset(cursor.pos())->Edit(bview, 0, 0, 0);
438 ToggleFootnote(bview);
446 void LyXText::CloseFootnote(BufferView * bview)
448 LyXParagraph * tmppar;
449 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
451 // if the cursor is not in an open footnote, or
452 // there is no open footnote in this paragraph, just return.
453 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
456 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
457 bview->owner()->getMiniBuffer()
458 ->Set(_("Nothing to do"));
462 // ok, move the cursor right before the footnote
463 // just a little faster than using CursorRight()
465 cursor.par()->ParFromPos(cursor.pos()) != par;) {
466 cursor.pos(cursor.pos() + 1);
469 // now the cursor is at the beginning of the physical par
470 SetCursor(bview, cursor.par(),
472 cursor.par()->ParFromPos(cursor.pos())->size());
474 /* we are in a footnote, so let us move at the beginning */
475 /* this is just faster than using just CursorLeft() */
477 tmppar = cursor.par();
478 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
479 // just a little bit faster than movin the cursor
480 tmppar = tmppar->Previous();
482 SetCursor(bview, tmppar, tmppar->Last());
485 // the cursor must be exactly before the footnote
486 par = cursor.par()->ParFromPos(cursor.pos());
488 status = LyXText::NEED_MORE_REFRESH;
489 refresh_row = cursor.row();
490 refresh_y = cursor.y() - cursor.row()->baseline();
492 tmppar = cursor.par();
493 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
494 Row * row = cursor.row();
496 tmppar->CloseFootnote(cursor.pos());
498 while (tmppar != endpar) {
499 RemoveRow(row->next());
501 tmppar = row->next()->par();
506 AppendParagraph(bview, cursor.row());
508 SetCursor(bview, cursor.par(), cursor.pos());
512 if (cursor.row()->next())
513 SetHeightOfRow(bview, cursor.row()->next());
518 /* used in setlayout */
519 // Asger is not sure we want to do this...
520 void LyXText::MakeFontEntriesLayoutSpecific(Buffer const * buf,
524 LyXLayout const & layout =
525 textclasslist.Style(buf->params.textclass, par->GetLayout());
527 LyXFont layoutfont, tmpfont;
528 for (LyXParagraph::size_type pos = 0;
529 pos < par->Last(); ++pos) {
530 if (pos < BeginningOfMainBody(buf, par))
531 layoutfont = layout.labelfont;
533 layoutfont = layout.font;
535 tmpfont = par->GetFontSettings(buf->params, pos);
536 tmpfont.reduce(layoutfont);
537 par->SetFont(pos, tmpfont);
542 LyXParagraph * LyXText::SetLayout(BufferView * bview,
543 LyXCursor & cur, LyXCursor & sstart_cur,
544 LyXCursor & send_cur,
545 LyXTextClass::size_type layout)
548 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
550 LyXParagraph * endpar = send_cur.par()->Next();
552 LyXParagraph * undoendpar = endpar;
554 if (endpar && endpar->GetDepth()) {
555 while (endpar && endpar->GetDepth()) {
557 endpar = endpar->LastPhysicalPar()->Next();
559 endpar = endpar->Next();
564 endpar = endpar->Next(); // because of parindents etc.
567 SetUndo(bview->buffer(), Undo::EDIT,
569 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
571 sstart_cur.par()->previous,
575 /* ok we have a selection. This is always between sstart_cur
576 * and sel_end cursor */
579 LyXLayout const & lyxlayout =
580 textclasslist.Style(bview->buffer()->params.textclass, layout);
582 while (cur.par() != send_cur.par()) {
584 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
586 cur.par()->SetLayout(bview->buffer()->params, layout);
587 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
589 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
591 LyXParagraph * fppar = cur.par();
593 fppar->added_space_top = lyxlayout.fill_top ?
594 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
595 fppar->added_space_bottom = lyxlayout.fill_bottom ?
596 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
597 if (lyxlayout.margintype == MARGIN_MANUAL)
598 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
599 if (lyxlayout.labeltype != LABEL_BIBLIO
601 delete fppar->bibkey;
607 cur.par(cur.par()->Next());
610 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
612 cur.par()->SetLayout(bview->buffer()->params, layout);
613 MakeFontEntriesLayoutSpecific(bview->buffer(), cur.par());
615 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
617 LyXParagraph * fppar = cur.par();
619 fppar->added_space_top = lyxlayout.fill_top ?
620 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
621 fppar->added_space_bottom = lyxlayout.fill_bottom ?
622 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
623 if (lyxlayout.margintype == MARGIN_MANUAL)
624 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
625 if (lyxlayout.labeltype != LABEL_BIBLIO
627 delete fppar->bibkey;
636 // set layout over selection and make a total rebreak of those paragraphs
637 void LyXText::SetLayout(BufferView * bview, LyXTextClass::size_type layout)
639 LyXCursor tmpcursor = cursor; /* store the current cursor */
641 // if there is no selection just set the layout
642 // of the current paragraph */
644 sel_start_cursor = cursor; // dummy selection
645 sel_end_cursor = cursor;
648 endpar = SetLayout(bview, cursor, sel_start_cursor,
649 sel_end_cursor, layout);
650 RedoParagraphs(bview, sel_start_cursor, endpar);
652 // we have to reset the selection, because the
653 // geometry could have changed
654 SetCursor(bview, sel_start_cursor.par(),
655 sel_start_cursor.pos(), false);
657 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos(),
659 UpdateCounters(bview, cursor.row());
660 ClearSelection(bview);
662 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true);
666 // increment depth over selection and
667 // make a total rebreak of those paragraphs
668 void LyXText::IncDepth(BufferView * bview)
670 // If there is no selection, just use the current paragraph
672 sel_start_cursor = cursor; // dummy selection
673 sel_end_cursor = cursor;
676 // We end at the next paragraph with depth 0
677 LyXParagraph * endpar =
679 sel_end_cursor.par()->LastPhysicalPar()->Next();
681 sel_end_cursor.par()->Next();
683 LyXParagraph * undoendpar = endpar;
685 if (endpar && endpar->GetDepth()) {
686 while (endpar && endpar->GetDepth()) {
688 endpar = endpar->LastPhysicalPar()->Next();
690 endpar = endpar->Next();
696 endpar = endpar->Next(); // because of parindents etc.
699 SetUndo(bview->buffer(), Undo::EDIT,
702 .par()->ParFromPos(sel_start_cursor.pos())->previous,
704 sel_start_cursor.par()->previous,
708 LyXCursor tmpcursor = cursor; // store the current cursor
710 // ok we have a selection. This is always between sel_start_cursor
711 // and sel_end cursor
712 cursor = sel_start_cursor;
714 bool anything_changed = false;
717 // NOTE: you can't change the depth of a bibliography entry
720 cursor.par()->footnoteflag ==
721 sel_start_cursor.par()->footnoteflag &&
723 textclasslist.Style(bview->buffer()->params.textclass,
724 cursor.par()->GetLayout()
725 ).labeltype != LABEL_BIBLIO) {
726 LyXParagraph * prev =
728 cursor.par()->FirstPhysicalPar()->Previous();
730 cursor.par()->Previous();
733 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
734 || (prev->GetDepth() == cursor.par()->GetDepth()
735 && textclasslist.Style(bview->buffer()->params.textclass,
736 prev->GetLayout()).isEnvironment()))) {
738 cursor.par()->FirstPhysicalPar()->depth++;
740 cursor.par()->depth++;
742 anything_changed = true;
745 if (cursor.par() == sel_end_cursor.par())
747 cursor.par(cursor.par()->Next());
750 // if nothing changed set all depth to 0
751 if (!anything_changed) {
752 cursor = sel_start_cursor;
753 while (cursor.par() != sel_end_cursor.par()) {
755 cursor.par()->FirstPhysicalPar()->depth = 0;
757 cursor.par()->depth = 0;
759 cursor.par(cursor.par()->Next());
762 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
763 cursor.par()->FirstPhysicalPar()->depth = 0;
765 cursor.par()->depth = 0;
769 RedoParagraphs(bview, sel_start_cursor, endpar);
771 // we have to reset the selection, because the
772 // geometry could have changed
773 SetCursor(bview, sel_start_cursor.par(),
774 sel_start_cursor.pos());
776 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
777 UpdateCounters(bview, cursor.row());
778 ClearSelection(bview);
780 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
784 // decrement depth over selection and
785 // make a total rebreak of those paragraphs
786 void LyXText::DecDepth(BufferView * bview)
788 // if there is no selection just set the layout
789 // of the current paragraph
791 sel_start_cursor = cursor; // dummy selection
792 sel_end_cursor = cursor;
795 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
797 LyXParagraph * endpar = sel_end_cursor.par()->Next();
799 LyXParagraph * undoendpar = endpar;
801 if (endpar && endpar->GetDepth()) {
802 while (endpar && endpar->GetDepth()) {
804 endpar = endpar->LastPhysicalPar()->Next();
806 endpar = endpar->Next();
812 endpar = endpar->Next(); // because of parindents etc.
815 SetUndo(bview->buffer(), Undo::EDIT,
818 .par()->ParFromPos(sel_start_cursor.pos())->previous,
820 sel_start_cursor.par()->previous,
824 LyXCursor tmpcursor = cursor; // store the current cursor
826 // ok we have a selection. This is always between sel_start_cursor
827 // and sel_end cursor
828 cursor = sel_start_cursor;
832 if (cursor.par()->footnoteflag ==
833 sel_start_cursor.par()->footnoteflag) {
834 if (cursor.par()->FirstPhysicalPar()->depth)
835 cursor.par()->FirstPhysicalPar()->depth--;
838 if (cursor.par()->depth)
839 cursor.par()->depth--;
841 if (cursor.par() == sel_end_cursor.par())
843 cursor.par(cursor.par()->Next());
846 RedoParagraphs(bview, sel_start_cursor, endpar);
848 // we have to reset the selection, because the
849 // geometry could have changed
850 SetCursor(bview, sel_start_cursor.par(),
851 sel_start_cursor.pos());
853 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
854 UpdateCounters(bview, cursor.row());
855 ClearSelection(bview);
857 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
861 // set font over selection and make a total rebreak of those paragraphs
862 void LyXText::SetFont(BufferView * bview, LyXFont const & font, bool toggleall)
864 // if there is no selection just set the current_font
866 // Determine basis font
868 if (cursor.pos() < BeginningOfMainBody(bview->buffer(),
870 layoutfont = GetFont(bview->buffer(), cursor.par(),-2);
872 layoutfont = GetFont(bview->buffer(), cursor.par(),-1);
873 // Update current font
874 real_current_font.update(font,
875 bview->buffer()->params.language,
878 // Reduce to implicit settings
879 current_font = real_current_font;
880 current_font.reduce(layoutfont);
881 // And resolve it completely
882 real_current_font.realize(layoutfont);
886 LyXCursor tmpcursor = cursor; // store the current cursor
888 // ok we have a selection. This is always between sel_start_cursor
889 // and sel_end cursor
891 SetUndo(bview->buffer(), Undo::EDIT,
893 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
894 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next
896 sel_start_cursor.par()->previous,
897 sel_end_cursor.par()->next
900 cursor = sel_start_cursor;
901 while (cursor.par() != sel_end_cursor.par() ||
904 cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag &&
906 cursor.pos() < sel_end_cursor.pos()))
908 if (cursor.pos() < cursor.par()->Last()
910 && cursor.par()->footnoteflag
911 == sel_start_cursor.par()->footnoteflag
914 // an open footnote should behave
916 LyXFont newfont = GetFont(bview->buffer(),
917 cursor.par(), cursor.pos());
919 bview->buffer()->params.language,
921 SetCharFont(bview->buffer(),
922 cursor.par(), cursor.pos(), newfont);
923 cursor.pos(cursor.pos() + 1);
926 cursor.par(cursor.par()->Next());
930 RedoParagraphs(bview, sel_start_cursor, sel_end_cursor.par()->Next());
932 // we have to reset the selection, because the
933 // geometry could have changed
934 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
936 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
937 ClearSelection(bview);
939 SetCursor(bview, tmpcursor.par(), tmpcursor.pos(), true,
940 tmpcursor.boundary());
944 void LyXText::RedoHeightOfParagraph(BufferView * bview, LyXCursor const & cur)
946 Row * tmprow = cur.row();
947 int y = cur.y() - tmprow->baseline();
949 SetHeightOfRow(bview, tmprow);
951 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
953 LyXParagraph * first_phys_par = tmprow->par();
955 // find the first row of the paragraph
956 if (first_phys_par != tmprow->par())
957 while (tmprow->previous()
958 && tmprow->previous()->par() != first_phys_par) {
959 tmprow = tmprow->previous();
960 y -= tmprow->height();
961 SetHeightOfRow(bview, tmprow);
963 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
964 tmprow = tmprow->previous();
965 y -= tmprow->height();
966 SetHeightOfRow(bview, tmprow);
969 // we can set the refreshing parameters now
970 status = LyXText::NEED_MORE_REFRESH;
972 refresh_row = tmprow;
973 SetCursor(bview, cur.par(), cur.pos(), false, cursor.boundary());
977 void LyXText::RedoDrawingOfParagraph(BufferView * bview, LyXCursor const & cur)
979 Row * tmprow = cur.row();
981 int y = cur.y() - tmprow->baseline();
982 SetHeightOfRow(bview, tmprow);
984 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
986 LyXParagraph * first_phys_par = tmprow->par();
988 // find the first row of the paragraph
989 if (first_phys_par != tmprow->par())
990 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
991 tmprow = tmprow->previous();
992 y -= tmprow->height();
994 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
995 tmprow = tmprow->previous();
996 y -= tmprow->height();
999 // we can set the refreshing parameters now
1000 if (status == LyXText::UNCHANGED || y < refresh_y) {
1002 refresh_row = tmprow;
1004 status = LyXText::NEED_MORE_REFRESH;
1005 SetCursor(bview, cur.par(), cur.pos());
1009 /* deletes and inserts again all paragaphs between the cursor
1010 * and the specified par
1011 * This function is needed after SetLayout and SetFont etc. */
1012 void LyXText::RedoParagraphs(BufferView * bview, LyXCursor const & cur,
1013 LyXParagraph const * endpar) const
1016 LyXParagraph * tmppar = 0, * first_phys_par = 0;
1018 Row * tmprow = cur.row();
1020 int y = cur.y() - tmprow->baseline();
1022 if (!tmprow->previous()){
1023 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
1026 first_phys_par = tmprow->par()->FirstPhysicalPar();
1028 first_phys_par = tmprow->par();
1030 // find the first row of the paragraph
1031 if (first_phys_par != tmprow->par())
1032 while (tmprow->previous() &&
1033 (tmprow->previous()->par() != first_phys_par)) {
1034 tmprow = tmprow->previous();
1035 y -= tmprow->height();
1037 while (tmprow->previous()
1038 && tmprow->previous()->par() == first_phys_par) {
1039 tmprow = tmprow->previous();
1040 y -= tmprow->height();
1044 // we can set the refreshing parameters now
1045 status = LyXText::NEED_MORE_REFRESH;
1047 refresh_row = tmprow->previous(); /* the real refresh row will
1048 be deleted, so I store
1049 the previous here */
1052 tmppar = tmprow->next()->par();
1055 while (tmppar != endpar) {
1056 RemoveRow(tmprow->next());
1058 tmppar = tmprow->next()->par();
1063 // remove the first one
1064 tmprow2 = tmprow; /* this is because tmprow->previous()
1066 tmprow = tmprow->previous();
1069 tmppar = first_phys_par;
1073 InsertParagraph(bview, tmppar, tmprow);
1076 while (tmprow->next() && tmprow->next()->par() == tmppar)
1077 tmprow = tmprow->next();
1078 tmppar = tmppar->Next();
1080 } while (tmppar != endpar);
1082 // this is because of layout changes
1084 refresh_y -= refresh_row->height();
1085 SetHeightOfRow(bview, refresh_row);
1087 refresh_row = firstrow;
1089 SetHeightOfRow(bview, refresh_row);
1092 if (tmprow && tmprow->next())
1093 SetHeightOfRow(bview, tmprow->next());
1097 bool LyXText::FullRebreak(BufferView * bview)
1103 if (need_break_row) {
1104 BreakAgain(bview, need_break_row);
1112 /* important for the screen */
1115 /* the cursor set functions have a special mechanism. When they
1116 * realize, that you left an empty paragraph, they will delete it.
1117 * They also delete the corresponding row */
1119 // need the selection cursor:
1120 void LyXText::SetSelection(BufferView * bview)
1122 const bool lsel = selection;
1125 last_sel_cursor = sel_cursor;
1126 sel_start_cursor = sel_cursor;
1127 sel_end_cursor = sel_cursor;
1132 // first the toggling area
1133 if (cursor.y() < last_sel_cursor.y()
1134 || (cursor.y() == last_sel_cursor.y()
1135 && cursor.x() < last_sel_cursor.x())) {
1136 toggle_end_cursor = last_sel_cursor;
1137 toggle_cursor = cursor;
1139 toggle_end_cursor = cursor;
1140 toggle_cursor = last_sel_cursor;
1143 last_sel_cursor = cursor;
1145 // and now the whole selection
1147 if (sel_cursor.par() == cursor.par())
1148 if (sel_cursor.pos() < cursor.pos()) {
1149 sel_end_cursor = cursor;
1150 sel_start_cursor = sel_cursor;
1152 sel_end_cursor = sel_cursor;
1153 sel_start_cursor = cursor;
1155 else if (sel_cursor.y() < cursor.y() ||
1156 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1157 sel_end_cursor = cursor;
1158 sel_start_cursor = sel_cursor;
1161 sel_end_cursor = sel_cursor;
1162 sel_start_cursor = cursor;
1165 // a selection with no contents is not a selection
1166 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1167 sel_start_cursor.pos() == sel_end_cursor.pos())
1170 if (inset_owner && (selection || lsel))
1171 inset_owner->SetUpdateStatus(bview, InsetText::SELECTION);
1175 string const LyXText::selectionAsString(Buffer const * buffer) const
1177 if (!selection) return string();
1180 // Special handling if the whole selection is within one paragraph
1181 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1182 result += sel_start_cursor.par()->String(buffer,
1183 sel_start_cursor.pos(),
1184 sel_end_cursor.pos());
1188 // The selection spans more than one paragraph
1190 // First paragraph in selection
1191 result += sel_start_cursor.par()->String(buffer,
1192 sel_start_cursor.pos(),
1193 sel_start_cursor.par()->Last())
1196 // The paragraphs in between (if any)
1197 LyXCursor tmpcur(sel_start_cursor);
1198 tmpcur.par(tmpcur.par()->Next());
1199 while (tmpcur.par() != sel_end_cursor.par()) {
1200 result += tmpcur.par()->String(buffer, 0, tmpcur.par()->Last()) + "\n\n";
1201 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1204 // Last paragraph in selection
1205 result += sel_end_cursor.par()->String(buffer, 0, sel_end_cursor.pos());
1211 void LyXText::ClearSelection(BufferView * bview) const
1218 void LyXText::CursorHome(BufferView * bview) const
1220 SetCursor(bview, cursor.par(), cursor.row()->pos());
1224 void LyXText::CursorEnd(BufferView * bview) const
1226 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1227 SetCursor(bview, cursor.par(), RowLast(cursor.row()) + 1);
1229 if (cursor.par()->Last() &&
1230 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1231 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1232 SetCursor(bview, cursor.par(), RowLast(cursor.row()));
1234 SetCursor(bview,cursor.par(), RowLast(cursor.row()) + 1);
1239 void LyXText::CursorTop(BufferView * bview) const
1241 while (cursor.par()->Previous())
1242 cursor.par(cursor.par()->Previous());
1243 SetCursor(bview, cursor.par(), 0);
1247 void LyXText::CursorBottom(BufferView * bview) const
1249 while (cursor.par()->Next())
1250 cursor.par(cursor.par()->Next());
1251 SetCursor(bview, cursor.par(), cursor.par()->Last());
1255 /* returns a pointer to the row near the specified y-coordinate
1256 * (relative to the whole text). y is set to the real beginning
1258 Row * LyXText::GetRowNearY(int & y) const
1260 Row * tmprow = firstrow;
1263 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1264 tmpy += tmprow->height();
1265 tmprow = tmprow->next();
1268 y = tmpy; // return the real y
1273 void LyXText::ToggleFree(BufferView * bview,
1274 LyXFont const & font, bool toggleall)
1276 // If the mask is completely neutral, tell user
1277 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1278 // Could only happen with user style
1279 bview->owner()->getMiniBuffer()
1280 ->Set(_("No font change defined. Use Character under"
1281 " the Layout menu to define font change."));
1285 // Try implicit word selection
1286 // If there is a change in the language the implicit word selection
1288 LyXCursor resetCursor = cursor;
1289 bool implicitSelection = (font.language() == ignore_language
1290 && font.number() == LyXFont::IGNORE)
1291 ? SelectWordWhenUnderCursor(bview) : false;
1294 SetFont(bview, font, toggleall);
1296 /* Implicit selections are cleared afterwards and cursor is set to the
1297 original position. */
1298 if (implicitSelection) {
1299 ClearSelection(bview);
1300 cursor = resetCursor;
1301 SetCursor(bview, cursor.par(), cursor.pos());
1302 sel_cursor = cursor;
1305 inset_owner->SetUpdateStatus(bview, InsetText::CURSOR_PAR);
1309 LyXParagraph::size_type
1310 LyXText::BeginningOfMainBody(Buffer const * buf,
1311 LyXParagraph const * par) const
1313 if (textclasslist.Style(buf->params.textclass,
1314 par->GetLayout()).labeltype != LABEL_MANUAL)
1317 return par->BeginningOfMainBody();
1322 /* if there is a selection, reset every environment you can find
1323 * in the selection, otherwise just the environment you are in */
1324 void LyXText::MeltFootnoteEnvironment(BufferView * bview)
1326 LyXParagraph * tmppar, * firsttmppar;
1328 ClearSelection(bview);
1330 /* is is only allowed, if the cursor is IN an open footnote.
1331 * Otherwise it is too dangerous */
1332 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1335 SetUndo(bview->buffer(), Undo::FINISH,
1336 cursor.par()->PreviousBeforeFootnote()->previous,
1337 cursor.par()->NextAfterFootnote()->next);
1339 /* ok, move to the beginning of the footnote. */
1340 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1341 cursor.par(cursor.par()->Previous());
1343 SetCursor(bview, cursor.par(), cursor.par()->Last());
1344 /* this is just faster than using CursorLeft(); */
1346 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1347 tmppar = firsttmppar;
1348 /* tmppar is now the paragraph right before the footnote */
1350 bool first_footnote_par_is_not_empty = tmppar->next->size();
1353 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1354 tmppar = tmppar->next; /* I use next instead of Next(),
1355 * because there cannot be any
1356 * footnotes in a footnote
1358 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1360 /* remember the captions and empty paragraphs */
1361 if ((textclasslist.Style(bview->buffer()->params.textclass,
1362 tmppar->GetLayout())
1363 .labeltype == LABEL_SENSITIVE)
1365 tmppar->SetLayout(bview->buffer()->params, 0);
1368 // now we will paste the ex-footnote, if the layouts allow it
1369 // first restore the layout of the paragraph right behind
1372 tmppar->next->MakeSameLayout(cursor.par());
1375 if (!tmppar->GetLayout()
1377 && (!tmppar->Next()->Last()
1378 || tmppar->Next()->HasSameLayout(tmppar)))) {
1379 if (tmppar->Next()->Last()
1380 && tmppar->Next()->IsLineSeparator(0))
1381 tmppar->Next()->Erase(0);
1382 tmppar->PasteParagraph(bview->buffer()->params);
1385 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1386 * by the pasting of the beginning */
1388 /* then the beginning */
1389 /* if there is no space between the text and the footnote, so we insert
1391 * (only if the previous par and the footnotepar are not empty!) */
1392 if (!firsttmppar->next->GetLayout()
1393 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1394 if (firsttmppar->size()
1395 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1396 && first_footnote_par_is_not_empty) {
1397 firsttmppar->next->InsertChar(0, ' ');
1399 firsttmppar->PasteParagraph(bview->buffer()->params);
1402 /* now redo the paragaphs */
1403 RedoParagraphs(bview, cursor, tmppar);
1405 SetCursor(bview, cursor.par(), cursor.pos());
1407 /* sometimes it can happen, that there is a counter change */
1408 Row * row = cursor.row();
1409 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1411 UpdateCounters(bview, row);
1414 ClearSelection(bview);
1419 /* the DTP switches for paragraphs. LyX will store them in the
1420 * first physicla paragraph. When a paragraph is broken, the top settings
1421 * rest, the bottom settings are given to the new one. So I can make shure,
1422 * they do not duplicate themself and you cannnot make dirty things with
1425 void LyXText::SetParagraph(BufferView * bview,
1426 bool line_top, bool line_bottom,
1427 bool pagebreak_top, bool pagebreak_bottom,
1428 VSpace const & space_top,
1429 VSpace const & space_bottom,
1431 string labelwidthstring,
1434 LyXCursor tmpcursor = cursor;
1436 sel_start_cursor = cursor;
1437 sel_end_cursor = cursor;
1440 // make sure that the depth behind the selection are restored, too
1442 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1444 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1446 LyXParagraph * undoendpar = endpar;
1448 if (endpar && endpar->GetDepth()) {
1449 while (endpar && endpar->GetDepth()) {
1451 endpar = endpar->LastPhysicalPar()->Next();
1453 endpar = endpar->Next();
1455 undoendpar = endpar;
1459 endpar = endpar->Next(); // because of parindents etc.
1462 SetUndo(bview->buffer(), Undo::EDIT,
1465 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1467 sel_start_cursor.par()->previous,
1472 LyXParagraph * tmppar = sel_end_cursor.par();
1474 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1475 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1477 while (tmppar != sel_start_cursor.par()->Previous()) {
1478 SetCursor(bview, tmppar, 0);
1480 status = LyXText::NEED_MORE_REFRESH;
1481 refresh_row = cursor.row();
1482 refresh_y = cursor.y() - cursor.row()->baseline();
1484 if (cursor.par()->footnoteflag ==
1485 sel_start_cursor.par()->footnoteflag) {
1487 cursor.par()->line_top = line_top;
1488 cursor.par()->line_bottom = line_bottom;
1489 cursor.par()->pagebreak_top = pagebreak_top;
1490 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1491 cursor.par()->added_space_top = space_top;
1492 cursor.par()->added_space_bottom = space_bottom;
1493 // does the layout allow the new alignment?
1494 if (align == LYX_ALIGN_LAYOUT)
1495 align = textclasslist
1496 .Style(bview->buffer()->params.textclass,
1497 cursor.par()->GetLayout()).align;
1498 if (align & textclasslist
1499 .Style(bview->buffer()->params.textclass,
1500 cursor.par()->GetLayout()).alignpossible) {
1501 if (align == textclasslist
1502 .Style(bview->buffer()->params.textclass,
1503 cursor.par()->GetLayout()).align)
1504 cursor.par()->align = LYX_ALIGN_LAYOUT;
1506 cursor.par()->align = align;
1508 cursor.par()->SetLabelWidthString(labelwidthstring);
1509 cursor.par()->noindent = noindent;
1513 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1515 tmppar = cursor.par()->Previous();
1519 RedoParagraphs(bview, sel_start_cursor, endpar);
1521 ClearSelection(bview);
1522 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1523 sel_cursor = cursor;
1524 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1525 SetSelection(bview);
1526 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1528 bview->updateInset(inset_owner, true);
1532 void LyXText::SetParagraphExtraOpt(BufferView * bview, int type,
1533 string const & width,
1534 string const & widthp,
1535 int alignment, bool hfill,
1536 bool start_minipage)
1538 LyXCursor tmpcursor = cursor;
1539 LyXParagraph * tmppar;
1541 sel_start_cursor = cursor;
1542 sel_end_cursor = cursor;
1545 // make sure that the depth behind the selection are restored, too
1547 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1549 LyXParagraph * endpar = sel_end_cursor.par()->Next();
1551 LyXParagraph * undoendpar = endpar;
1553 if (endpar && endpar->GetDepth()) {
1554 while (endpar && endpar->GetDepth()) {
1556 endpar = endpar->LastPhysicalPar()->Next();
1558 endpar = endpar->Next();
1560 undoendpar = endpar;
1564 endpar = endpar->Next(); // because of parindents etc.
1567 SetUndo(bview->buffer(), Undo::EDIT,
1570 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1572 sel_start_cursor.par()->previous,
1576 tmppar = sel_end_cursor.par();
1578 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1579 SetCursor(bview, tmppar->FirstPhysicalPar(), 0);
1581 while(tmppar != sel_start_cursor.par()->Previous()) {
1582 SetCursor(bview, tmppar, 0);
1584 status = LyXText::NEED_MORE_REFRESH;
1585 refresh_row = cursor.row();
1586 refresh_y = cursor.y() - cursor.row()->baseline();
1588 if (cursor.par()->footnoteflag ==
1589 sel_start_cursor.par()->footnoteflag) {
1591 if (type == LyXParagraph::PEXTRA_NONE) {
1592 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1593 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1594 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1597 cursor.par()->SetPExtraType(bview->buffer()->params,
1598 type, width, widthp);
1599 cursor.par()->pextra_hfill = hfill;
1600 cursor.par()->pextra_start_minipage = start_minipage;
1601 cursor.par()->pextra_alignment = alignment;
1605 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1607 tmppar = cursor.par()->Previous();
1610 RedoParagraphs(bview, sel_start_cursor, endpar);
1611 ClearSelection(bview);
1612 SetCursor(bview, sel_start_cursor.par(), sel_start_cursor.pos());
1613 sel_cursor = cursor;
1614 SetCursor(bview, sel_end_cursor.par(), sel_end_cursor.pos());
1615 SetSelection(bview);
1616 SetCursor(bview, tmpcursor.par(), tmpcursor.pos());
1620 char loweralphaCounter(int n)
1622 if (n < 1 || n > 26)
1630 char alphaCounter(int n)
1632 if (n < 1 || n > 26)
1640 char hebrewCounter(int n)
1642 static const char hebrew[22] = {
1643 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1644 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1645 '÷', 'ø', 'ù', 'ú'
1647 if (n < 1 || n > 22)
1655 string const romanCounter(int n)
1657 static char const * roman[20] = {
1658 "i", "ii", "iii", "iv", "v",
1659 "vi", "vii", "viii", "ix", "x",
1660 "xi", "xii", "xiii", "xiv", "xv",
1661 "xvi", "xvii", "xviii", "xix", "xx"
1663 if (n < 1 || n > 20)
1670 // set the counter of a paragraph. This includes the labels
1671 void LyXText::SetCounter(Buffer const * buf, LyXParagraph * par) const
1674 // this is only relevant for the beginning of paragraph
1675 par = par->FirstPhysicalPar();
1677 LyXLayout const & layout =
1678 textclasslist.Style(buf->params.textclass,
1681 LyXTextClass const & textclass =
1682 textclasslist.TextClass(buf->params.textclass);
1684 /* copy the prev-counters to this one, unless this is the start of a
1685 footnote or of a bibliography or the very first paragraph */
1688 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1689 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1690 && par->footnotekind == LyXParagraph::FOOTNOTE)
1692 && !(textclasslist.Style(buf->params.textclass,
1693 par->Previous()->GetLayout()
1694 ).labeltype != LABEL_BIBLIO
1695 && layout.labeltype == LABEL_BIBLIO)) {
1696 for (int i = 0; i < 10; ++i) {
1697 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1700 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1702 par->appendix = par->Previous()->appendix;
1704 if (!par->appendix && par->start_of_appendix){
1705 par->appendix = true;
1706 for (int i = 0; i < 10; ++i) {
1707 par->setCounter(i, 0);
1711 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1712 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1714 par->enumdepth = par->Previous()->enumdepth;
1715 par->itemdepth = par->Previous()->itemdepth;
1718 for (int i = 0; i < 10; ++i) {
1719 par->setCounter(i, 0);
1721 par->appendix = par->start_of_appendix;
1727 // if this is an open marginnote and this is the first
1728 // entry in the marginnote and the enclosing
1729 // environment is an enum/item then correct for the
1730 // LaTeX behaviour (ARRae)
1731 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1732 && par->footnotekind == LyXParagraph::MARGIN
1734 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1735 && (par->PreviousBeforeFootnote()
1736 && textclasslist.Style(buf->params.textclass,
1737 par->PreviousBeforeFootnote()->GetLayout()
1738 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1739 // Any itemize or enumerate environment in a marginnote
1740 // that is embedded in an itemize or enumerate
1741 // paragraph is seen by LaTeX as being at a deeper
1742 // level within that enclosing itemization/enumeration
1743 // even if there is a "standard" layout at the start of
1749 /* Maybe we have to increment the enumeration depth.
1750 * BUT, enumeration in a footnote is considered in isolation from its
1751 * surrounding paragraph so don't increment if this is the
1752 * first line of the footnote
1753 * AND, bibliographies can't have their depth changed ie. they
1754 * are always of depth 0
1757 && par->Previous()->GetDepth() < par->GetDepth()
1758 && textclasslist.Style(buf->params.textclass,
1759 par->Previous()->GetLayout()
1760 ).labeltype == LABEL_COUNTER_ENUMI
1761 && par->enumdepth < 3
1763 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1764 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1765 && par->footnotekind == LyXParagraph::FOOTNOTE)
1767 && layout.labeltype != LABEL_BIBLIO) {
1771 /* Maybe we have to decrement the enumeration depth, see note above */
1773 && par->Previous()->GetDepth() > par->GetDepth()
1775 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1776 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1777 && par->footnotekind == LyXParagraph::FOOTNOTE)
1779 && layout.labeltype != LABEL_BIBLIO) {
1780 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1781 par->setCounter(6 + par->enumdepth,
1782 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1783 /* reset the counters.
1784 * A depth change is like a breaking layout
1786 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1787 par->setCounter(i, 0);
1790 if (!par->labelstring.empty()) {
1791 par->labelstring.erase();
1794 if (layout.margintype == MARGIN_MANUAL) {
1795 if (par->labelwidthstring.empty()) {
1796 par->SetLabelWidthString(layout.labelstring());
1799 par->SetLabelWidthString(string());
1802 /* is it a layout that has an automatic label ? */
1803 if (layout.labeltype >= LABEL_COUNTER_CHAPTER) {
1805 int i = layout.labeltype - LABEL_COUNTER_CHAPTER;
1806 if (i >= 0 && i<= buf->params.secnumdepth) {
1807 par->incCounter(i); // increment the counter
1809 // Is there a label? Useful for Chapter layout
1810 if (!par->appendix){
1811 if (!layout.labelstring().empty())
1812 par->labelstring = layout.labelstring();
1814 par->labelstring.erase();
1816 if (!layout.labelstring_appendix().empty())
1817 par->labelstring = layout.labelstring_appendix();
1819 par->labelstring.erase();
1822 std::ostringstream s;
1824 if (!par->appendix) {
1825 switch (2 * LABEL_COUNTER_CHAPTER -
1826 textclass.maxcounter() + i) {
1827 case LABEL_COUNTER_CHAPTER:
1828 s << par->getCounter(i);
1830 case LABEL_COUNTER_SECTION:
1831 s << par->getCounter(i - 1) << '.'
1832 << par->getCounter(i);
1834 case LABEL_COUNTER_SUBSECTION:
1835 s << par->getCounter(i - 2) << '.'
1836 << par->getCounter(i - 1) << '.'
1837 << par->getCounter(i);
1839 case LABEL_COUNTER_SUBSUBSECTION:
1840 s << par->getCounter(i - 3) << '.'
1841 << par->getCounter(i - 2) << '.'
1842 << par->getCounter(i - 1) << '.'
1843 << par->getCounter(i);
1846 case LABEL_COUNTER_PARAGRAPH:
1847 s << par->getCounter(i - 4) << '.'
1848 << par->getCounter(i - 3) << '.'
1849 << par->getCounter(i - 2) << '.'
1850 << par->getCounter(i - 1) << '.'
1851 << par->getCounter(i);
1853 case LABEL_COUNTER_SUBPARAGRAPH:
1854 s << par->getCounter(i - 5) << '.'
1855 << par->getCounter(i - 4) << '.'
1856 << par->getCounter(i - 3) << '.'
1857 << par->getCounter(i - 2) << '.'
1858 << par->getCounter(i - 1) << '.'
1859 << par->getCounter(i);
1863 // Can this ever be reached? And in the
1864 // case it is, how can this be correct?
1866 s << par->getCounter(i) << '.';
1869 } else { // appendix
1870 switch (2 * LABEL_COUNTER_CHAPTER - textclass.maxcounter() + i) {
1871 case LABEL_COUNTER_CHAPTER:
1872 if (par->isRightToLeftPar(buf->params))
1873 s << hebrewCounter(par->getCounter(i));
1875 s << alphaCounter(par->getCounter(i));
1877 case LABEL_COUNTER_SECTION:
1878 if (par->isRightToLeftPar(buf->params))
1879 s << hebrewCounter(par->getCounter(i - 1));
1881 s << alphaCounter(par->getCounter(i - 1));
1884 << par->getCounter(i);
1887 case LABEL_COUNTER_SUBSECTION:
1888 if (par->isRightToLeftPar(buf->params))
1889 s << hebrewCounter(par->getCounter(i - 2));
1891 s << alphaCounter(par->getCounter(i - 2));
1894 << par->getCounter(i-1) << '.'
1895 << par->getCounter(i);
1898 case LABEL_COUNTER_SUBSUBSECTION:
1899 if (par->isRightToLeftPar(buf->params))
1900 s << hebrewCounter(par->getCounter(i-3));
1902 s << alphaCounter(par->getCounter(i-3));
1905 << par->getCounter(i-2) << '.'
1906 << par->getCounter(i-1) << '.'
1907 << par->getCounter(i);
1910 case LABEL_COUNTER_PARAGRAPH:
1911 if (par->isRightToLeftPar(buf->params))
1912 s << hebrewCounter(par->getCounter(i-4));
1914 s << alphaCounter(par->getCounter(i-4));
1917 << par->getCounter(i-3) << '.'
1918 << par->getCounter(i-2) << '.'
1919 << par->getCounter(i-1) << '.'
1920 << par->getCounter(i);
1923 case LABEL_COUNTER_SUBPARAGRAPH:
1924 if (par->isRightToLeftPar(buf->params))
1925 s << hebrewCounter(par->getCounter(i-5));
1927 s << alphaCounter(par->getCounter(i-5));
1930 << par->getCounter(i-4) << '.'
1931 << par->getCounter(i-3) << '.'
1932 << par->getCounter(i-2) << '.'
1933 << par->getCounter(i-1) << '.'
1934 << par->getCounter(i);
1938 // Can this ever be reached? And in the
1939 // case it is, how can this be correct?
1941 s << par->getCounter(i) << '.';
1947 par->labelstring += s.str().c_str();
1948 // We really want to remove the c_str as soon as
1951 for (i++; i < 10; ++i) {
1952 // reset the following counters
1953 par->setCounter(i, 0);
1955 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1956 for (i++; i < 10; ++i) {
1957 // reset the following counters
1958 par->setCounter(i, 0);
1960 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1961 par->incCounter(i + par->enumdepth);
1962 int number = par->getCounter(i + par->enumdepth);
1964 std::ostringstream s;
1966 switch (par->enumdepth) {
1968 if (par->isRightToLeftPar(buf->params))
1970 << hebrewCounter(number)
1974 << loweralphaCounter(number)
1978 if (par->isRightToLeftPar(buf->params))
1979 s << '.' << romanCounter(number);
1981 s << romanCounter(number) << '.';
1984 if (par->isRightToLeftPar(buf->params))
1986 << alphaCounter(number);
1988 s << alphaCounter(number)
1992 if (par->isRightToLeftPar(buf->params))
1999 par->labelstring = s.str().c_str();
2000 // we really want to get rid of that c_str()
2002 for (i += par->enumdepth + 1; i < 10; ++i)
2003 par->setCounter(i, 0); /* reset the following counters */
2006 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
2007 int i = LABEL_COUNTER_ENUMI - LABEL_COUNTER_CHAPTER + par->enumdepth;
2009 int number = par->getCounter(i);
2011 InsetCommandParams p( "bibitem" );
2012 par->bibkey = new InsetBibKey(p);
2014 par->bibkey->setCounter(number);
2015 par->labelstring = layout.labelstring();
2017 // In biblio should't be following counters but...
2019 string s = layout.labelstring();
2021 // the caption hack:
2022 if (layout.labeltype == LABEL_SENSITIVE) {
2023 bool isOK (par->InInset() && par->InInset()->owner() &&
2024 (par->InInset()->owner()->LyxCode() == Inset::FLOAT_CODE));
2026 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2027 && (par->footnotekind == LyXParagraph::FIG
2028 || par->footnotekind == LyXParagraph::WIDE_FIG)) {
2029 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2030 ? ":øåéà " : "Figure:";
2031 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2032 && (par->footnotekind == LyXParagraph::TAB
2033 || par->footnotekind == LyXParagraph::WIDE_TAB)) {
2034 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2035 ? ":äìáè" : "Table:";
2036 } else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2037 && par->footnotekind == LyXParagraph::ALGORITHM) {
2038 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2039 ? ":Ãúéøåâìà " : "Algorithm:";
2043 InsetFloat * tmp = static_cast<InsetFloat*>(par->InInset()->owner());
2045 = floatList.getType(tmp->type());
2046 // We should get the correct number here too.
2047 s = fl.name() + " #:";
2049 /* par->SetLayout(0);
2050 s = layout->labelstring; */
2051 s = (par->getParLanguage(buf->params)->lang() == "hebrew")
2052 ? " :úåòîùî øñç" : "Senseless: ";
2055 par->labelstring = s;
2057 /* reset the enumeration counter. They are always resetted
2058 * when there is any other layout between */
2059 for (int i = 6 + par->enumdepth; i < 10; ++i)
2060 par->setCounter(i, 0);
2065 /* Updates all counters BEHIND the row. Changed paragraphs
2066 * with a dynamic left margin will be rebroken. */
2067 void LyXText::UpdateCounters(BufferView * bview, Row * row) const
2074 if (row->par()->next
2076 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
2080 par = row->par()->LastPhysicalPar()->Next();
2082 par = row->par()->Next();
2085 par = row->par()->next;
2090 while (row->par() != par)
2093 SetCounter(bview->buffer(), par);
2095 /* now check for the headline layouts. remember that they
2096 * have a dynamic left margin */
2101 ( textclasslist.Style(bview->buffer()->params.textclass,
2102 par->layout).margintype == MARGIN_DYNAMIC
2103 || textclasslist.Style(bview->buffer()->params.textclass,
2104 par->layout).labeltype == LABEL_SENSITIVE)
2107 /* Rebreak the paragraph */
2108 RemoveParagraph(row);
2109 AppendParagraph(bview, row);
2112 /* think about the damned open footnotes! */
2113 while (par->Next() &&
2114 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
2115 || par->Next()->IsDummy())){
2117 if (par->IsDummy()) {
2118 while (row->par() != par)
2120 RemoveParagraph(row);
2121 AppendParagraph(bview, row);
2127 par = par->LastPhysicalPar()->Next();
2136 /* insets an inset. */
2137 void LyXText::InsertInset(BufferView * bview, Inset * inset)
2139 if (!cursor.par()->InsertInsetAllowed(inset))
2141 SetUndo(bview->buffer(), Undo::INSERT,
2143 cursor.par()->ParFromPos(cursor.pos())->previous,
2144 cursor.par()->ParFromPos(cursor.pos())->next
2146 cursor.par()->previous,
2150 cursor.par()->InsertInset(cursor.pos(), inset);
2151 InsertChar(bview, LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
2152 * The character will not be inserted a
2155 // If we enter a highly editable inset the cursor should be to before
2156 // the inset. This couldn't happen before as Undo was not handled inside
2157 // inset now after the Undo LyX tries to call inset->Edit(...) again
2158 // and cannot do this as the cursor is behind the inset and GetInset
2159 // does not return the inset!
2160 if (inset->Editable() == Inset::HIGHLY_EDITABLE) {
2161 CursorLeft(bview, true);
2167 void LyXText::copyEnvironmentType()
2169 copylayouttype = cursor.par()->GetLayout();
2173 void LyXText::pasteEnvironmentType(BufferView * bview)
2175 SetLayout(bview, copylayouttype);
2179 void LyXText::CutSelection(BufferView * bview, bool doclear)
2181 // Stuff what we got on the clipboard. Even if there is no selection.
2183 // There is a problem with having the stuffing here in that the
2184 // larger the selection the slower LyX will get. This can be
2185 // solved by running the line below only when the selection has
2186 // finished. The solution used currently just works, to make it
2187 // faster we need to be more clever and probably also have more
2188 // calls to stuffClipboard. (Lgb)
2189 bview->stuffClipboard(selectionAsString(bview->buffer()));
2191 // This doesn't make sense, if there is no selection
2195 // OK, we have a selection. This is always between sel_start_cursor
2196 // and sel_end_cursor
2198 // Check whether there are half footnotes in the selection
2199 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2200 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2201 LyXParagraph * tmppar = sel_start_cursor.par();
2202 while (tmppar != sel_end_cursor.par()){
2203 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2204 WriteAlert(_("Impossible operation"),
2205 _("Don't know what to do with half floats."),
2209 tmppar = tmppar->Next();
2214 // make sure that the depth behind the selection are restored, too
2216 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2218 LyXParagraph * endpar = sel_end_cursor.par()->Next();
2220 LyXParagraph * undoendpar = endpar;
2222 if (endpar && endpar->GetDepth()) {
2223 while (endpar && endpar->GetDepth()) {
2225 endpar = endpar->LastPhysicalPar()->Next();
2227 endpar = endpar->Next();
2229 undoendpar = endpar;
2231 } else if (endpar) {
2232 endpar = endpar->Next(); // because of parindents etc.
2235 SetUndo(bview->buffer(), Undo::DELETE,
2238 .par()->ParFromPos(sel_start_cursor.pos())->previous,
2240 sel_start_cursor.par()->previous,
2246 // there are two cases: cut only within one paragraph or
2247 // more than one paragraph
2249 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2250 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos()))
2252 if (sel_start_cursor.par() == sel_end_cursor.par())
2255 // only within one paragraph
2256 endpar = sel_start_cursor.par();
2257 int pos = sel_end_cursor.pos();
2258 cap.cutSelection(sel_start_cursor.par(), &endpar,
2259 sel_start_cursor.pos(), pos,
2260 bview->buffer()->params.textclass, doclear);
2261 sel_end_cursor.pos(pos);
2263 endpar = sel_end_cursor.par();
2265 int pos = sel_end_cursor.pos();
2266 cap.cutSelection(sel_start_cursor.par(), &endpar,
2267 sel_start_cursor.pos(), pos,
2268 bview->buffer()->params.textclass, doclear);
2270 sel_end_cursor.par(endpar);
2271 sel_end_cursor.pos(pos);
2272 cursor.pos(sel_end_cursor.pos());
2274 endpar = endpar->Next();
2276 // sometimes necessary
2278 sel_start_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass);
2280 RedoParagraphs(bview, sel_start_cursor, endpar);
2282 ClearSelection(bview);
2283 cursor = sel_start_cursor;
2284 SetCursor(bview, cursor.par(), cursor.pos());
2285 sel_cursor = cursor;
2286 UpdateCounters(bview, cursor.row());
2290 void LyXText::CopySelection(BufferView * bview)
2292 // Stuff what we got on the clipboard. Even if there is no selection.
2294 // There is a problem with having the stuffing here in that the
2295 // larger the selection the slower LyX will get. This can be
2296 // solved by running the line below only when the selection has
2297 // finished. The solution used currently just works, to make it
2298 // faster we need to be more clever and probably also have more
2299 // calls to stuffClipboard. (Lgb)
2300 bview->stuffClipboard(selectionAsString(bview->buffer()));
2302 // this doesnt make sense, if there is no selection
2306 // ok we have a selection. This is always between sel_start_cursor
2307 // and sel_end cursor
2310 /* check wether there are half footnotes in the selection */
2311 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2312 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2313 LyXParagraph * tmppar = sel_start_cursor.par();
2314 while (tmppar != sel_end_cursor.par()) {
2315 if (tmppar->footnoteflag !=
2316 sel_end_cursor.par()->footnoteflag) {
2317 WriteAlert(_("Impossible operation"),
2318 _("Don't know what to do"
2319 " with half floats."),
2323 tmppar = tmppar->Next();
2328 // copy behind a space if there is one
2329 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2330 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2331 && (sel_start_cursor.par() != sel_end_cursor.par()
2332 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2333 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2337 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2338 sel_start_cursor.pos(), sel_end_cursor.pos(),
2339 bview->buffer()->params.textclass);
2343 void LyXText::PasteSelection(BufferView * bview)
2347 // this does not make sense, if there is nothing to paste
2348 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2351 SetUndo(bview->buffer(), Undo::INSERT,
2353 cursor.par()->ParFromPos(cursor.pos())->previous,
2354 cursor.par()->ParFromPos(cursor.pos())->next
2356 cursor.par()->previous,
2361 LyXParagraph * endpar;
2362 LyXParagraph * actpar = cursor.par();
2364 int pos = cursor.pos();
2365 cap.pasteSelection(&actpar, &endpar, pos, bview->buffer()->params.textclass);
2367 RedoParagraphs(bview, cursor, endpar);
2369 SetCursor(bview, cursor.par(), cursor.pos());
2370 ClearSelection(bview);
2372 sel_cursor = cursor;
2373 SetCursor(bview, actpar, pos);
2374 SetSelection(bview);
2375 UpdateCounters(bview, cursor.row());
2379 // returns a pointer to the very first LyXParagraph
2380 LyXParagraph * LyXText::FirstParagraph() const
2382 return OwnerParagraph();
2386 // returns true if the specified string is at the specified position
2387 bool LyXText::IsStringInText(LyXParagraph * par,
2388 LyXParagraph::size_type pos,
2389 string const & str) const
2394 LyXParagraph::size_type i = 0;
2395 while (pos + i < par->Last()
2396 && string::size_type(i) < str.length()
2397 && str[i] == par->GetChar(pos + i)) {
2400 if (str.length() == string::size_type(i))
2406 // sets the selection over the number of characters of string, no check!!
2407 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2409 sel_cursor = cursor;
2410 for (int i = 0; str[i]; ++i)
2412 SetSelection(bview);
2416 // simple replacing. The font of the first selected character is used
2417 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2420 SetCursorParUndo(bview->buffer());
2423 if (!selection) { // create a dummy selection
2424 sel_end_cursor = cursor;
2425 sel_start_cursor = cursor;
2428 // Get font setting before we cut
2429 LyXParagraph::size_type pos = sel_end_cursor.pos();
2430 LyXFont const font = sel_start_cursor.par()
2431 ->GetFontSettings(bview->buffer()->params,
2432 sel_start_cursor.pos());
2434 // Insert the new string
2435 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2436 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2440 // Cut the selection
2441 CutSelection(bview);
2447 // if the string can be found: return true and set the cursor to
2449 bool LyXText::SearchForward(BufferView * bview, string const & str) const
2451 LyXParagraph * par = cursor.par();
2452 LyXParagraph::size_type pos = cursor.pos();
2453 while (par && !IsStringInText(par, pos, str)) {
2454 if (pos < par->Last() - 1)
2462 SetCursor(bview, par, pos);
2470 bool LyXText::SearchBackward(BufferView * bview, string const & str) const
2472 LyXParagraph * par = cursor.par();
2473 int pos = cursor.pos();
2479 // We skip empty paragraphs (Asger)
2481 par = par->Previous();
2483 pos = par->Last() - 1;
2484 } while (par && pos < 0);
2486 } while (par && !IsStringInText(par, pos, str));
2489 SetCursor(bview, par, pos);
2496 // needed to insert the selection
2497 void LyXText::InsertStringA(BufferView * bview, string const & str)
2499 LyXParagraph * par = cursor.par();
2500 LyXParagraph::size_type pos = cursor.pos();
2501 LyXParagraph::size_type a = 0;
2502 LyXParagraph * endpar = cursor.par()->Next();
2504 SetCursorParUndo(bview->buffer());
2507 textclasslist.Style(bview->buffer()->params.textclass,
2508 cursor.par()->GetLayout()).isEnvironment();
2509 // only to be sure, should not be neccessary
2510 ClearSelection(bview);
2512 // insert the string, don't insert doublespace
2513 string::size_type i = 0;
2514 while (i < str.length()) {
2515 if (str[i] != '\n') {
2517 && i + 1 < str.length() && str[i + 1] != ' '
2518 && pos && par->GetChar(pos - 1)!= ' ') {
2519 par->InsertChar(pos, ' ', current_font);
2521 } else if (str[i] == ' ') {
2522 InsetSpecialChar * new_inset =
2523 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2524 if (par->InsertInsetAllowed(new_inset)) {
2525 par->InsertInset(pos, new_inset,
2531 } else if (str[i] == '\t') {
2532 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2533 InsetSpecialChar * new_inset =
2534 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2535 if (par->InsertInsetAllowed(new_inset)) {
2536 par->InsertInset(pos, new_inset,
2543 } else if (str[i] != 13 &&
2544 // Ignore unprintables
2545 (str[i] & 127) >= ' ') {
2546 par->InsertChar(pos, str[i], current_font);
2550 if (!par->size()) { // par is empty
2551 InsetSpecialChar * new_inset =
2552 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2553 if (par->InsertInsetAllowed(new_inset)) {
2554 par->InsertInset(pos,
2562 par->BreakParagraph(bview->buffer()->params, pos, flag);
2569 RedoParagraphs(bview, cursor, endpar);
2570 SetCursor(bview, cursor.par(), cursor.pos());
2571 sel_cursor = cursor;
2572 SetCursor(bview, par, pos);
2573 SetSelection(bview);
2577 /* turns double-CR to single CR, others where converted into one blank and 13s
2578 * that are ignored .Double spaces are also converted into one. Spaces at
2579 * the beginning of a paragraph are forbidden. tabs are converted into one
2580 * space. then InsertStringA is called */
2581 void LyXText::InsertStringB(BufferView * bview, string const & s)
2584 string::size_type i = 1;
2585 while (i < str.length()) {
2588 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2590 if (str[i] == '\n' && i + 1 < str.length()) {
2591 if (str[i + 1] != '\n') {
2592 if (str[i - 1] != ' ')
2597 while (i + 1 < str.length()
2598 && (str[i + 1] == ' '
2599 || str[i + 1] == '\t'
2600 || str[i + 1] == '\n'
2601 || str[i + 1] == 13)) {
2608 InsertStringA(bview, str);
2612 bool LyXText::GotoNextInset(BufferView * bview,
2613 std::vector<Inset::Code> const & codes,
2614 string const & contents) const
2616 LyXCursor res = cursor;
2619 if (res.pos() < res.par()->Last() - 1) {
2620 res.pos(res.pos() + 1);
2622 res.par(res.par()->Next());
2626 } while (res.par() &&
2627 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2628 && (inset = res.par()->GetInset(res.pos())) != 0
2629 && find(codes.begin(), codes.end(), inset->LyxCode())
2631 && (contents.empty() ||
2632 static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
2636 SetCursor(bview, res.par(), res.pos());
2643 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2644 LyXParagraph::size_type pos)
2646 LyXCursor tmpcursor;
2649 LyXParagraph::size_type z;
2650 Row * row = GetRow(par, pos, y);
2652 // is there a break one row above
2653 if (row->previous() && row->previous()->par() == row->par()) {
2654 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2655 if (z >= row->pos()) {
2656 // set the dimensions of the row above
2657 y -= row->previous()->height();
2659 refresh_row = row->previous();
2660 status = LyXText::NEED_MORE_REFRESH;
2662 BreakAgain(bview, row->previous());
2664 // set the cursor again. Otherwise
2665 // dangling pointers are possible
2666 SetCursor(bview, cursor.par(), cursor.pos(),
2667 false, cursor.boundary());
2668 sel_cursor = cursor;
2673 int const tmpheight = row->height();
2674 LyXParagraph::size_type const tmplast = RowLast(row);
2678 BreakAgain(bview, row);
2679 if (row->height() == tmpheight && RowLast(row) == tmplast)
2680 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2682 status = LyXText::NEED_MORE_REFRESH;
2684 // check the special right address boxes
2685 if (textclasslist.Style(bview->buffer()->params.textclass,
2686 par->GetLayout()).margintype
2687 == MARGIN_RIGHT_ADDRESS_BOX) {
2694 RedoDrawingOfParagraph(bview, tmpcursor);
2697 // set the cursor again. Otherwise dangling pointers are possible
2698 // also set the selection
2702 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2703 false, sel_cursor.boundary());
2704 sel_cursor = cursor;
2705 SetCursorIntern(bview, sel_start_cursor.par(),
2706 sel_start_cursor.pos(),
2707 false, sel_start_cursor.boundary());
2708 sel_start_cursor = cursor;
2709 SetCursorIntern(bview, sel_end_cursor.par(),
2710 sel_end_cursor.pos(),
2711 false, sel_end_cursor.boundary());
2712 sel_end_cursor = cursor;
2713 SetCursorIntern(bview, last_sel_cursor.par(),
2714 last_sel_cursor.pos(),
2715 false, last_sel_cursor.boundary());
2716 last_sel_cursor = cursor;
2719 SetCursorIntern(bview, cursor.par(), cursor.pos(),
2720 false, cursor.boundary());
2724 // returns false if inset wasn't found
2725 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2727 // first check the current paragraph
2728 int pos = cursor.par()->GetPositionOfInset(inset);
2730 CheckParagraph(bview, cursor.par(), pos);
2734 // check every paragraph
2736 LyXParagraph * par = FirstParagraph();
2739 // make sure the paragraph is open
2740 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2742 pos = par->GetPositionOfInset(inset);
2744 CheckParagraph(bview, par, pos);
2757 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2758 LyXParagraph::size_type pos,
2759 bool setfont, bool boundary) const
2761 LyXCursor old_cursor = cursor;
2762 SetCursorIntern(bview, par, pos, setfont, boundary);
2763 DeleteEmptyParagraphMechanism(bview, old_cursor);
2767 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2768 LyXParagraph::size_type pos, bool boundary) const
2771 // correct the cursor position if impossible
2772 if (pos > par->Last()){
2773 LyXParagraph * tmppar = par->ParFromPos(pos);
2774 pos = par->PositionInParFromPos(pos);
2777 if (par->IsDummy() && par->previous &&
2778 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2779 while (par->previous &&
2780 ((par->previous->IsDummy() &&
2781 (par->previous->previous->footnoteflag ==
2782 LyXParagraph::CLOSED_FOOTNOTE)) ||
2783 (par->previous->footnoteflag ==
2784 LyXParagraph::CLOSED_FOOTNOTE))) {
2785 par = par->previous ;
2786 if (par->IsDummy() &&
2787 (par->previous->footnoteflag ==
2788 LyXParagraph::CLOSED_FOOTNOTE))
2789 pos += par->size() + 1;
2791 if (par->previous) {
2792 par = par->previous;
2794 pos += par->size() + 1;
2799 cur.boundary(boundary);
2801 /* get the cursor y position in text */
2803 Row * row = GetRow(par, pos, y);
2804 /* y is now the beginning of the cursor row */
2805 y += row->baseline();
2806 /* y is now the cursor baseline */
2809 /* now get the cursors x position */
2811 float fill_separator, fill_hfill, fill_label_hfill;
2812 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2814 LyXParagraph::size_type cursor_vpos = 0;
2815 LyXParagraph::size_type last = RowLastPrintable(row);
2817 if (pos > last + 1) // This shouldn't happen.
2819 else if (pos < row->pos())
2822 if (last < row->pos())
2823 cursor_vpos = row->pos();
2824 else if (pos > last && !boundary)
2825 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2826 ? row->pos() : last + 1;
2827 else if (pos > row->pos() &&
2828 (pos > last || boundary))
2829 /// Place cursor after char at (logical) position pos - 1
2830 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2831 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2833 /// Place cursor before char at (logical) position pos
2834 cursor_vpos = (bidi_level(pos) % 2 == 0)
2835 ? log2vis(pos) : log2vis(pos) + 1;
2837 LyXParagraph::size_type main_body =
2838 BeginningOfMainBody(bview->buffer(), row->par());
2839 if ((main_body > 0) &&
2840 ((main_body-1 > last) ||
2841 !row->par()->IsLineSeparator(main_body-1)))
2844 for (LyXParagraph::size_type vpos = row->pos();
2845 vpos < cursor_vpos; ++vpos) {
2846 pos = vis2log(vpos);
2847 if (main_body > 0 && pos == main_body - 1) {
2848 x += fill_label_hfill +
2849 lyxfont::width(textclasslist.Style(
2850 bview->buffer()->params.textclass,
2851 row->par()->GetLayout())
2853 GetFont(bview->buffer(), row->par(), -2));
2854 if (row->par()->IsLineSeparator(main_body-1))
2855 x -= SingleWidth(bview, row->par(),main_body-1);
2857 if (HfillExpansion(bview->buffer(), row, pos)) {
2858 x += SingleWidth(bview, row->par(), pos);
2859 if (pos >= main_body)
2862 x += fill_label_hfill;
2863 } else if (row->par()->IsSeparator(pos)) {
2864 x += SingleWidth(bview, row->par(), pos);
2865 if (pos >= main_body)
2866 x += fill_separator;
2868 x += SingleWidth(bview, row->par(), pos);
2877 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2878 LyXParagraph::size_type pos,
2879 bool setfont, bool boundary) const
2881 SetCursor(bview, cursor, par, pos, boundary);
2883 SetCurrentFont(bview);
2887 void LyXText::SetCurrentFont(BufferView * bview) const
2889 LyXParagraph::size_type pos = cursor.pos();
2890 if (cursor.boundary() && pos > 0)
2894 if (pos == cursor.par()->Last())
2896 else if (cursor.par()->IsSeparator(pos)) {
2897 if (pos > cursor.row()->pos() &&
2898 bidi_level(pos) % 2 ==
2899 bidi_level(pos - 1) % 2)
2901 else if (pos + 1 < cursor.par()->Last())
2907 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2908 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2910 if (cursor.pos() == cursor.par()->Last() &&
2911 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2912 !cursor.boundary()) {
2913 Language const * lang =
2914 cursor.par()->getParLanguage(bview->buffer()->params);
2915 current_font.setLanguage(lang);
2916 current_font.setNumber(LyXFont::OFF);
2917 real_current_font.setLanguage(lang);
2918 real_current_font.setNumber(LyXFont::OFF);
2923 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2925 LyXCursor old_cursor = cursor;
2927 /* get the row first */
2929 Row * row = GetRowNearY(y);
2930 cursor.par(row->par());
2933 int column = GetColumnNearX(bview, row, x, bound);
2934 cursor.pos(row->pos() + column);
2936 cursor.y(y + row->baseline());
2938 cursor.boundary(bound);
2939 SetCurrentFont(bview);
2940 DeleteEmptyParagraphMechanism(bview, old_cursor);
2944 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2947 /* get the row first */
2949 Row * row = GetRowNearY(y);
2951 int column = GetColumnNearX(bview, row, x, bound);
2953 cur.par(row->par());
2954 cur.pos(row->pos() + column);
2956 cur.y(y + row->baseline());
2958 cur.boundary(bound);
2962 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2964 if (cursor.pos() > 0) {
2965 bool boundary = cursor.boundary();
2966 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2967 if (!internal && !boundary &&
2968 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2969 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2970 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
2971 LyXParagraph * par = cursor.par()->Previous();
2972 SetCursor(bview, par, par->Last());
2977 void LyXText::CursorRight(BufferView * bview, bool internal) const
2979 if (!internal && cursor.boundary() &&
2980 !cursor.par()->IsNewline(cursor.pos()))
2981 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2982 else if (cursor.pos() < cursor.par()->Last()) {
2983 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2985 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2986 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2987 } else if (cursor.par()->Next())
2988 SetCursor(bview, cursor.par()->Next(), 0);
2992 void LyXText::CursorUp(BufferView * bview) const
2994 SetCursorFromCoordinates(bview, cursor.x_fix(),
2995 cursor.y() - cursor.row()->baseline() - 1);
2999 void LyXText::CursorDown(BufferView * bview) const
3001 SetCursorFromCoordinates(bview, cursor.x_fix(),
3002 cursor.y() - cursor.row()->baseline()
3003 + cursor.row()->height() + 1);
3007 void LyXText::CursorUpParagraph(BufferView * bview) const
3009 if (cursor.pos() > 0) {
3010 SetCursor(bview, cursor.par(), 0);
3012 else if (cursor.par()->Previous()) {
3013 SetCursor(bview, cursor.par()->Previous(), 0);
3018 void LyXText::CursorDownParagraph(BufferView * bview) const
3020 if (cursor.par()->Next()) {
3021 SetCursor(bview, cursor.par()->Next(), 0);
3023 SetCursor(bview, cursor.par(), cursor.par()->Last());
3028 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
3029 LyXCursor const & old_cursor) const
3031 // Would be wrong to delete anything if we have a selection.
3032 if (selection) return;
3034 // We allow all kinds of "mumbo-jumbo" when freespacing.
3035 if (textclasslist.Style(bview->buffer()->params.textclass,
3036 old_cursor.par()->GetLayout()).free_spacing)
3039 bool deleted = false;
3041 /* Ok I'll put some comments here about what is missing.
3042 I have fixed BackSpace (and thus Delete) to not delete
3043 double-spaces automagically. I have also changed Cut,
3044 Copy and Paste to hopefully do some sensible things.
3045 There are still some small problems that can lead to
3046 double spaces stored in the document file or space at
3047 the beginning of paragraphs. This happens if you have
3048 the cursor betwenn to spaces and then save. Or if you
3049 cut and paste and the selection have a space at the
3050 beginning and then save right after the paste. I am
3051 sure none of these are very hard to fix, but I will
3052 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3053 that I can get some feedback. (Lgb)
3056 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3057 // delete the LineSeparator.
3060 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3061 // delete the LineSeparator.
3064 // If the pos around the old_cursor were spaces, delete one of them.
3065 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3066 // Only if the cursor has really moved
3068 if (old_cursor.pos() > 0
3069 && old_cursor.pos() < old_cursor.par()->Last()
3070 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3071 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3072 old_cursor.par()->Erase(old_cursor.pos() - 1);
3073 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3075 if (old_cursor.par() == cursor.par() &&
3076 cursor.pos() > old_cursor.pos()) {
3077 SetCursorIntern(bview, cursor.par(),
3080 SetCursorIntern(bview, cursor.par(),
3086 // Do not delete empty paragraphs with keepempty set.
3087 if ((textclasslist.Style(bview->buffer()->params.textclass,
3088 old_cursor.par()->GetLayout())).keepempty)
3091 LyXCursor tmpcursor;
3093 if (old_cursor.par() != cursor.par()) {
3094 if ((old_cursor.par()->Last() == 0
3095 || (old_cursor.par()->Last() == 1
3096 && old_cursor.par()->IsLineSeparator(0)))
3098 && old_cursor.par()->FirstPhysicalPar()
3099 == old_cursor.par()->LastPhysicalPar()
3102 // ok, we will delete anything
3104 // make sure that you do not delete any environments
3107 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3108 !(old_cursor.row()->previous()
3109 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3110 && !(old_cursor.row()->next()
3111 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3112 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3113 && ((old_cursor.row()->previous()
3114 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3115 || (old_cursor.row()->next()
3116 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3119 status = LyXText::NEED_MORE_REFRESH;
3122 if (old_cursor.row()->previous()) {
3123 refresh_row = old_cursor.row()->previous();
3124 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3126 cursor = old_cursor; // that undo can restore the right cursor position
3127 LyXParagraph * endpar = old_cursor.par()->next;
3128 if (endpar && endpar->GetDepth()) {
3129 while (endpar && endpar->GetDepth()) {
3131 endpar = endpar->LastPhysicalPar()->Next();
3133 endpar = endpar->Next();
3137 SetUndo(bview->buffer(), Undo::DELETE,
3138 old_cursor.par()->previous,
3143 RemoveRow(old_cursor.row());
3144 if (OwnerParagraph() == old_cursor.par()) {
3145 OwnerParagraph(OwnerParagraph()->next);
3148 delete old_cursor.par();
3150 /* Breakagain the next par. Needed
3151 * because of the parindent that
3152 * can occur or dissappear. The
3153 * next row can change its height,
3154 * if there is another layout before */
3155 if (refresh_row->next()) {
3156 BreakAgain(bview, refresh_row->next());
3157 UpdateCounters(bview, refresh_row);
3159 SetHeightOfRow(bview, refresh_row);
3161 refresh_row = old_cursor.row()->next();
3162 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3165 cursor = old_cursor; // that undo can restore the right cursor position
3166 LyXParagraph * endpar = old_cursor.par()->next;
3167 if (endpar && endpar->GetDepth()) {
3168 while (endpar && endpar->GetDepth()) {
3170 endpar = endpar->LastPhysicalPar()->Next();
3172 endpar = endpar->Next();
3176 SetUndo(bview->buffer(), Undo::DELETE,
3177 old_cursor.par()->previous,
3182 RemoveRow(old_cursor.row());
3184 if (OwnerParagraph() == old_cursor.par()) {
3185 OwnerParagraph(OwnerParagraph()->next);
3187 delete old_cursor.par();
3189 /* Breakagain the next par. Needed
3190 because of the parindent that can
3191 occur or dissappear.
3192 The next row can change its height,
3193 if there is another layout before
3196 BreakAgain(bview, refresh_row);
3197 UpdateCounters(bview, refresh_row->previous());
3203 SetCursorIntern(bview, cursor.par(), cursor.pos());
3205 if (sel_cursor.par() == old_cursor.par()
3206 && sel_cursor.pos() == sel_cursor.pos()) {
3207 // correct selection
3208 sel_cursor = cursor;
3215 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3216 RedoParagraphs(bview, old_cursor, old_cursor.par()->Next());
3218 SetCursorIntern(bview, cursor.par(), cursor.pos());
3219 sel_cursor = cursor;
3226 LyXParagraph * LyXText::GetParFromID(int id)
3228 LyXParagraph * result = FirstParagraph();
3229 while (result && result->id() != id)
3230 result = result->next;
3236 bool LyXText::TextUndo(BufferView * bview)
3240 // returns false if no undo possible
3241 Undo * undo = bview->buffer()->undostack.pop();
3245 bview->buffer()->redostack
3246 .push(CreateUndo(bview->buffer(), undo->kind,
3247 GetParFromID(undo->number_of_before_par),
3248 GetParFromID(undo->number_of_behind_par)));
3250 return TextHandleUndo(bview, undo);
3254 bool LyXText::TextRedo(BufferView * bview)
3258 // returns false if no redo possible
3259 Undo * undo = bview->buffer()->redostack.pop();
3263 bview->buffer()->undostack
3264 .push(CreateUndo(bview->buffer(), undo->kind,
3265 GetParFromID(undo->number_of_before_par),
3266 GetParFromID(undo->number_of_behind_par)));
3268 return TextHandleUndo(bview, undo);
3272 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3276 // returns false if no undo possible
3277 bool result = false;
3279 LyXParagraph * before =
3280 GetParFromID(undo->number_of_before_par);
3281 LyXParagraph * behind =
3282 GetParFromID(undo->number_of_behind_par);
3283 LyXParagraph * tmppar;
3284 LyXParagraph * tmppar2;
3285 LyXParagraph * endpar;
3286 LyXParagraph * tmppar5;
3288 // if there's no before take the beginning
3289 // of the document for redoing
3291 SetCursorIntern(bview, FirstParagraph(), 0);
3293 // replace the paragraphs with the undo informations
3295 LyXParagraph * tmppar3 = undo->par;
3296 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3297 LyXParagraph * tmppar4 = tmppar3;
3299 while (tmppar4->next)
3300 tmppar4 = tmppar4->next;
3301 } // get last undo par
3303 // now remove the old text if there is any
3304 if (before != behind || (!behind && !before)){
3306 tmppar5 = before->next;
3308 tmppar5 = OwnerParagraph();
3310 while (tmppar5 && tmppar5 != behind){
3312 tmppar5 = tmppar5->next;
3313 // a memory optimization for edit: Only layout information
3314 // is stored in the undo. So restore the text informations.
3315 if (undo->kind == Undo::EDIT) {
3316 tmppar2->setContentsFromPar(tmppar);
3317 tmppar->clearContents();
3318 tmppar2 = tmppar2->next;
3323 // put the new stuff in the list if there is one
3326 before->next = tmppar3;
3328 OwnerParagraph(tmppar3);
3329 tmppar3->previous = before;
3332 OwnerParagraph(behind);
3335 tmppar4->next = behind;
3337 behind->previous = tmppar4;
3341 // Set the cursor for redoing
3344 SetCursorIntern(bview, before->FirstSelfrowPar(), 0);
3346 SetCursorIntern(bview, before, 0);
3349 // check wether before points to a closed float and open it if necessary
3350 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3351 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3353 while (tmppar4->previous &&
3354 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3355 tmppar4 = tmppar4->previous;
3356 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3357 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3358 tmppar4 = tmppar4->next;
3365 // open a cosed footnote at the end if necessary
3366 if (behind && behind->previous &&
3367 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3368 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3369 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3370 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3371 behind = behind->next;
3376 // calculate the endpar for redoing the paragraphs.
3379 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3380 endpar = behind->LastPhysicalPar()->Next();
3382 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3384 endpar = behind->Next();
3389 tmppar = GetParFromID(undo->number_of_cursor_par);
3390 RedoParagraphs(bview, cursor, endpar);
3392 SetCursorIntern(bview, tmppar, undo->cursor_pos);
3393 UpdateCounters(bview, cursor.row());
3403 void LyXText::FinishUndo()
3407 // makes sure the next operation will be stored
3408 undo_finished = true;
3412 void LyXText::FreezeUndo()
3416 // this is dangerous and for internal use only
3421 void LyXText::UnFreezeUndo()
3425 // this is dangerous and for internal use only
3426 undo_frozen = false;
3430 void LyXText::SetUndo(Buffer * buf, Undo::undo_kind kind,
3431 LyXParagraph const * before,
3432 LyXParagraph const * behind) const
3437 buf->undostack.push(CreateUndo(buf, kind, before, behind));
3438 buf->redostack.clear();
3442 void LyXText::SetRedo(Buffer * buf, Undo::undo_kind kind,
3443 LyXParagraph const * before, LyXParagraph const * behind)
3447 buf->redostack.push(CreateUndo(buf, kind, before, behind));
3451 Undo * LyXText::CreateUndo(Buffer * buf, Undo::undo_kind kind,
3452 LyXParagraph const * before,
3453 LyXParagraph const * behind) const
3458 int before_number = -1;
3459 int behind_number = -1;
3461 before_number = before->id();
3463 behind_number = behind->id();
3464 // Undo::EDIT and Undo::FINISH are
3465 // always finished. (no overlapping there)
3466 // overlapping only with insert and delete inside one paragraph:
3467 // Nobody wants all removed character
3468 // appear one by one when undoing.
3469 // EDIT is special since only layout information, not the
3470 // contents of a paragaph are stored.
3471 if (!undo_finished && (kind != Undo::EDIT) && (kind != Undo::FINISH)){
3472 // check wether storing is needed
3473 if (!buf->undostack.empty() &&
3474 buf->undostack.top()->kind == kind &&
3475 buf->undostack.top()->number_of_before_par == before_number &&
3476 buf->undostack.top()->number_of_behind_par == behind_number ){
3481 // create a new Undo
3482 LyXParagraph * undopar;
3483 LyXParagraph * tmppar;
3484 LyXParagraph * tmppar2;
3486 LyXParagraph * start = 0;
3487 LyXParagraph * end = 0;
3490 start = before->next;
3492 start = FirstParagraph();
3494 end = behind->previous;
3496 end = FirstParagraph();
3501 if (start && end && (start != end->next) &&
3502 ((before != behind) || (!before && !behind)))
3505 tmppar2 = tmppar->Clone();
3506 tmppar2->id(tmppar->id());
3508 // a memory optimization: Just store the layout information
3510 if (kind == Undo::EDIT){
3511 //tmppar2->text.clear();
3512 tmppar2->clearContents();
3517 while (tmppar != end && tmppar->next) {
3518 tmppar = tmppar->next;
3519 tmppar2->next = tmppar->Clone();
3520 tmppar2->next->id(tmppar->id());
3521 // a memory optimization: Just store the layout
3522 // information when only edit
3523 if (kind == Undo::EDIT){
3524 //tmppar2->next->text.clear();
3525 tmppar2->clearContents();
3527 tmppar2->next->previous = tmppar2;
3528 tmppar2 = tmppar2->next;
3532 undopar = 0; // nothing to replace (undo of delete maybe)
3535 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3536 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3538 int cursor_par = cursor.par()->id();
3539 int cursor_pos = cursor.pos();
3542 Undo * undo = new Undo(kind,
3543 before_number, behind_number,
3544 cursor_par, cursor_pos,
3547 undo_finished = false;
3552 void LyXText::SetCursorParUndo(Buffer * buf)
3556 SetUndo(buf, Undo::FINISH,
3558 cursor.par()->ParFromPos(cursor.pos())->previous,
3559 cursor.par()->ParFromPos(cursor.pos())->next
3561 cursor.par()->previous,
3568 void LyXText::toggleAppendix(BufferView * bview)
3571 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3573 LyXParagraph * par = cursor.par();
3575 bool start = !par->start_of_appendix;
3577 // ensure that we have only one start_of_appendix in this document
3578 LyXParagraph * tmp = FirstParagraph();
3579 for (; tmp; tmp = tmp->next)
3580 tmp->start_of_appendix = 0;
3581 par->start_of_appendix = start;
3583 // we can set the refreshing parameters now
3584 status = LyXText::NEED_MORE_REFRESH;
3586 refresh_row = 0; // not needed for full update
3587 UpdateCounters(bview, 0);
3588 SetCursor(bview, cursor.par(), cursor.pos());
3592 LyXParagraph * LyXText::OwnerParagraph() const
3595 return inset_owner->par;
3597 return bv_owner->buffer()->paragraph;
3601 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3604 inset_owner->par = p;
3606 bv_owner->buffer()->paragraph = p;