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->params.spaceTop(lyxlayout.fill_top ?
594 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
595 fppar->params.spaceBottom(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->params.spaceTop(lyxlayout.fill_top ?
620 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE));
621 fppar->params.spaceBottom(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()->params.depth(cursor.par()->FirstPhysicalPar()->params.depth() + 1);
740 cursor.par()->params.depth(cursor.par()->params.depth() + 1);
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()->params.depth(0);
757 cursor.par()->params.depth(0);
759 cursor.par(cursor.par()->next());
762 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
763 cursor.par()->FirstPhysicalPar()->params.depth(0);
765 cursor.par()->params.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()->params.depth())
835 cursor.par()->FirstPhysicalPar()->params.depth(cursor.par()->FirstPhysicalPar()->params.depth() - 1);
838 if (cursor.par()->params.depth())
839 cursor.par()->params.depth(cursor.par()->params.depth() - 1);
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();
1352 while (tmppar->next_
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()->params.lineTop(line_top);
1488 cursor.par()->params.lineBottom(line_bottom);
1489 cursor.par()->params.pagebreakTop(pagebreak_top);
1490 cursor.par()->params.pagebreakBottom(pagebreak_bottom);
1491 cursor.par()->params.spaceTop(space_top);
1492 cursor.par()->params.spaceBottom(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()->params.align(LYX_ALIGN_LAYOUT);
1506 cursor.par()->params.align(align);
1508 cursor.par()->SetLabelWidthString(labelwidthstring);
1509 cursor.par()->params.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()->params.pextraType() != LyXParagraph::PEXTRA_NONE) {
1593 cursor.par()->UnsetPExtraType(bview->buffer()->params);
1594 cursor.par()->params.pextraType(LyXParagraph::PEXTRA_NONE);
1597 cursor.par()->SetPExtraType(bview->buffer()->params,
1598 type, width, widthp);
1599 cursor.par()->params.pextraHfill(hfill);
1600 cursor.par()->params.pextraStartMinipage(start_minipage);
1601 cursor.par()->params.pextraAlignment(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->params.appendix(par->previous()->FirstPhysicalPar()->params.appendix());
1702 par->params.appendix(par->previous()->params.appendix());
1704 if (!par->params.appendix() && par->params.startOfAppendix()) {
1705 par->params.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->params.appendix(par->params.startOfAppendix());
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->params.labelString().empty()) {
1791 par->params.labelString(string());
1794 if (layout.margintype == MARGIN_MANUAL) {
1795 if (par->params.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->params.appendix()) {
1811 if (!layout.labelstring().empty())
1812 par->params.labelString(layout.labelstring());
1814 par->params.labelString(string());
1816 if (!layout.labelstring_appendix().empty())
1817 par->params.labelString(layout.labelstring_appendix());
1819 par->params.labelString(string());
1822 std::ostringstream s;
1824 if (!par->params.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->params.labelString(par->params.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->params.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->params.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->params.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 } else if (row->par()->next_
2075 && row->par()->next_->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
2076 par = row->par()->LastPhysicalPar()->next();
2078 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(),
2147 cursor.par()->next()
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(),
2357 cursor.par()->next()
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 // sets the selection over the number of characters of string, no check!!
2387 void LyXText::SetSelectionOverString(BufferView * bview, string const & str)
2389 sel_cursor = cursor;
2390 for (int i = 0; str[i]; ++i)
2392 SetSelection(bview);
2396 // simple replacing. The font of the first selected character is used
2397 void LyXText::ReplaceSelectionWithString(BufferView * bview,
2400 SetCursorParUndo(bview->buffer());
2403 if (!selection) { // create a dummy selection
2404 sel_end_cursor = cursor;
2405 sel_start_cursor = cursor;
2408 // Get font setting before we cut
2409 LyXParagraph::size_type pos = sel_end_cursor.pos();
2410 LyXFont const font = sel_start_cursor.par()
2411 ->GetFontSettings(bview->buffer()->params,
2412 sel_start_cursor.pos());
2414 // Insert the new string
2415 for (string::const_iterator cit = str.begin(); cit != str.end(); ++cit) {
2416 sel_end_cursor.par()->InsertChar(pos, (*cit), font);
2420 // Cut the selection
2421 CutSelection(bview);
2427 // needed to insert the selection
2428 void LyXText::InsertStringA(BufferView * bview, string const & str)
2430 LyXParagraph * par = cursor.par();
2431 LyXParagraph::size_type pos = cursor.pos();
2432 LyXParagraph::size_type a = 0;
2433 LyXParagraph * endpar = cursor.par()->next();
2435 SetCursorParUndo(bview->buffer());
2438 textclasslist.Style(bview->buffer()->params.textclass,
2439 cursor.par()->GetLayout()).isEnvironment();
2440 // only to be sure, should not be neccessary
2441 ClearSelection(bview);
2443 // insert the string, don't insert doublespace
2444 string::size_type i = 0;
2445 while (i < str.length()) {
2446 if (str[i] != '\n') {
2448 && i + 1 < str.length() && str[i + 1] != ' '
2449 && pos && par->GetChar(pos - 1)!= ' ') {
2450 par->InsertChar(pos, ' ', current_font);
2452 } else if (str[i] == ' ') {
2453 InsetSpecialChar * new_inset =
2454 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2455 if (par->InsertInsetAllowed(new_inset)) {
2456 par->InsertInset(pos, new_inset,
2462 } else if (str[i] == '\t') {
2463 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2464 InsetSpecialChar * new_inset =
2465 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2466 if (par->InsertInsetAllowed(new_inset)) {
2467 par->InsertInset(pos, new_inset,
2474 } else if (str[i] != 13 &&
2475 // Ignore unprintables
2476 (str[i] & 127) >= ' ') {
2477 par->InsertChar(pos, str[i], current_font);
2481 if (!par->size()) { // par is empty
2482 InsetSpecialChar * new_inset =
2483 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2484 if (par->InsertInsetAllowed(new_inset)) {
2485 par->InsertInset(pos,
2493 par->BreakParagraph(bview->buffer()->params, pos, flag);
2500 RedoParagraphs(bview, cursor, endpar);
2501 SetCursor(bview, cursor.par(), cursor.pos());
2502 sel_cursor = cursor;
2503 SetCursor(bview, par, pos);
2504 SetSelection(bview);
2508 /* turns double-CR to single CR, others where converted into one blank and 13s
2509 * that are ignored .Double spaces are also converted into one. Spaces at
2510 * the beginning of a paragraph are forbidden. tabs are converted into one
2511 * space. then InsertStringA is called */
2512 void LyXText::InsertStringB(BufferView * bview, string const & s)
2515 string::size_type i = 1;
2516 while (i < str.length()) {
2519 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2521 if (str[i] == '\n' && i + 1 < str.length()) {
2522 if (str[i + 1] != '\n') {
2523 if (str[i - 1] != ' ')
2528 while (i + 1 < str.length()
2529 && (str[i + 1] == ' '
2530 || str[i + 1] == '\t'
2531 || str[i + 1] == '\n'
2532 || str[i + 1] == 13)) {
2539 InsertStringA(bview, str);
2543 bool LyXText::GotoNextInset(BufferView * bview,
2544 std::vector<Inset::Code> const & codes,
2545 string const & contents) const
2547 LyXCursor res = cursor;
2550 if (res.pos() < res.par()->Last() - 1) {
2551 res.pos(res.pos() + 1);
2553 res.par(res.par()->next());
2557 } while (res.par() &&
2558 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
2559 && (inset = res.par()->GetInset(res.pos())) != 0
2560 && find(codes.begin(), codes.end(), inset->LyxCode())
2562 && (contents.empty() ||
2563 static_cast<InsetCommand *>(res.par()->GetInset(res.pos()))->getContents()
2567 SetCursor(bview, res.par(), res.pos());
2574 void LyXText::CheckParagraph(BufferView * bview, LyXParagraph * par,
2575 LyXParagraph::size_type pos)
2577 LyXCursor tmpcursor;
2580 LyXParagraph::size_type z;
2581 Row * row = GetRow(par, pos, y);
2583 // is there a break one row above
2584 if (row->previous() && row->previous()->par() == row->par()) {
2585 z = NextBreakPoint(bview, row->previous(), workWidth(bview));
2586 if (z >= row->pos()) {
2587 // set the dimensions of the row above
2588 y -= row->previous()->height();
2590 refresh_row = row->previous();
2591 status = LyXText::NEED_MORE_REFRESH;
2593 BreakAgain(bview, row->previous());
2595 // set the cursor again. Otherwise
2596 // dangling pointers are possible
2597 SetCursor(bview, cursor.par(), cursor.pos(),
2598 false, cursor.boundary());
2599 sel_cursor = cursor;
2604 int const tmpheight = row->height();
2605 LyXParagraph::size_type const tmplast = RowLast(row);
2609 BreakAgain(bview, row);
2610 if (row->height() == tmpheight && RowLast(row) == tmplast)
2611 status = LyXText::NEED_VERY_LITTLE_REFRESH;
2613 status = LyXText::NEED_MORE_REFRESH;
2615 // check the special right address boxes
2616 if (textclasslist.Style(bview->buffer()->params.textclass,
2617 par->GetLayout()).margintype
2618 == MARGIN_RIGHT_ADDRESS_BOX) {
2625 RedoDrawingOfParagraph(bview, tmpcursor);
2628 // set the cursor again. Otherwise dangling pointers are possible
2629 // also set the selection
2633 SetCursorIntern(bview, sel_cursor.par(), sel_cursor.pos(),
2634 false, sel_cursor.boundary());
2635 sel_cursor = cursor;
2636 SetCursorIntern(bview, sel_start_cursor.par(),
2637 sel_start_cursor.pos(),
2638 false, sel_start_cursor.boundary());
2639 sel_start_cursor = cursor;
2640 SetCursorIntern(bview, sel_end_cursor.par(),
2641 sel_end_cursor.pos(),
2642 false, sel_end_cursor.boundary());
2643 sel_end_cursor = cursor;
2644 SetCursorIntern(bview, last_sel_cursor.par(),
2645 last_sel_cursor.pos(),
2646 false, last_sel_cursor.boundary());
2647 last_sel_cursor = cursor;
2650 SetCursorIntern(bview, cursor.par(), cursor.pos(),
2651 false, cursor.boundary());
2655 // returns false if inset wasn't found
2656 bool LyXText::UpdateInset(BufferView * bview, Inset * inset)
2658 // first check the current paragraph
2659 int pos = cursor.par()->GetPositionOfInset(inset);
2661 CheckParagraph(bview, cursor.par(), pos);
2665 // check every paragraph
2667 LyXParagraph * par = FirstParagraph();
2670 // make sure the paragraph is open
2671 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
2673 pos = par->GetPositionOfInset(inset);
2675 CheckParagraph(bview, par, pos);
2688 void LyXText::SetCursor(BufferView * bview, LyXParagraph * par,
2689 LyXParagraph::size_type pos,
2690 bool setfont, bool boundary) const
2692 LyXCursor old_cursor = cursor;
2693 SetCursorIntern(bview, par, pos, setfont, boundary);
2694 DeleteEmptyParagraphMechanism(bview, old_cursor);
2698 void LyXText::SetCursor(BufferView *bview, LyXCursor & cur, LyXParagraph * par,
2699 LyXParagraph::size_type pos, bool boundary) const
2702 // correct the cursor position if impossible
2703 if (pos > par->Last()){
2704 LyXParagraph * tmppar = par->ParFromPos(pos);
2705 pos = par->PositionInParFromPos(pos);
2708 if (par->IsDummy() && par->previous_ &&
2709 par->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2710 while (par->previous_ &&
2711 ((par->previous_->IsDummy() &&
2712 (par->previous_->previous_->footnoteflag ==
2713 LyXParagraph::CLOSED_FOOTNOTE)) ||
2714 (par->previous_->footnoteflag ==
2715 LyXParagraph::CLOSED_FOOTNOTE))) {
2716 par = par->previous_;
2717 if (par->IsDummy() &&
2718 (par->previous_->footnoteflag ==
2719 LyXParagraph::CLOSED_FOOTNOTE))
2720 pos += par->size() + 1;
2722 if (par->previous_) {
2723 par = par->previous_;
2725 pos += par->size() + 1;
2730 cur.boundary(boundary);
2732 /* get the cursor y position in text */
2734 Row * row = GetRow(par, pos, y);
2735 /* y is now the beginning of the cursor row */
2736 y += row->baseline();
2737 /* y is now the cursor baseline */
2740 /* now get the cursors x position */
2742 float fill_separator, fill_hfill, fill_label_hfill;
2743 PrepareToPrint(bview, row, x, fill_separator, fill_hfill,
2745 LyXParagraph::size_type cursor_vpos = 0;
2746 LyXParagraph::size_type last = RowLastPrintable(row);
2748 if (pos > last + 1) // This shouldn't happen.
2750 else if (pos < row->pos())
2753 if (last < row->pos())
2754 cursor_vpos = row->pos();
2755 else if (pos > last && !boundary)
2756 cursor_vpos = (row->par()->isRightToLeftPar(bview->buffer()->params))
2757 ? row->pos() : last + 1;
2758 else if (pos > row->pos() &&
2759 (pos > last || boundary))
2760 /// Place cursor after char at (logical) position pos - 1
2761 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
2762 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
2764 /// Place cursor before char at (logical) position pos
2765 cursor_vpos = (bidi_level(pos) % 2 == 0)
2766 ? log2vis(pos) : log2vis(pos) + 1;
2768 LyXParagraph::size_type main_body =
2769 BeginningOfMainBody(bview->buffer(), row->par());
2770 if ((main_body > 0) &&
2771 ((main_body-1 > last) ||
2772 !row->par()->IsLineSeparator(main_body-1)))
2775 for (LyXParagraph::size_type vpos = row->pos();
2776 vpos < cursor_vpos; ++vpos) {
2777 pos = vis2log(vpos);
2778 if (main_body > 0 && pos == main_body - 1) {
2779 x += fill_label_hfill +
2780 lyxfont::width(textclasslist.Style(
2781 bview->buffer()->params.textclass,
2782 row->par()->GetLayout())
2784 GetFont(bview->buffer(), row->par(), -2));
2785 if (row->par()->IsLineSeparator(main_body-1))
2786 x -= SingleWidth(bview, row->par(),main_body-1);
2788 if (HfillExpansion(bview->buffer(), row, pos)) {
2789 x += SingleWidth(bview, row->par(), pos);
2790 if (pos >= main_body)
2793 x += fill_label_hfill;
2794 } else if (row->par()->IsSeparator(pos)) {
2795 x += SingleWidth(bview, row->par(), pos);
2796 if (pos >= main_body)
2797 x += fill_separator;
2799 x += SingleWidth(bview, row->par(), pos);
2808 void LyXText::SetCursorIntern(BufferView * bview, LyXParagraph * par,
2809 LyXParagraph::size_type pos,
2810 bool setfont, bool boundary) const
2812 SetCursor(bview, cursor, par, pos, boundary);
2814 SetCurrentFont(bview);
2818 void LyXText::SetCurrentFont(BufferView * bview) const
2820 LyXParagraph::size_type pos = cursor.pos();
2821 if (cursor.boundary() && pos > 0)
2825 if (pos == cursor.par()->Last())
2827 else if (cursor.par()->IsSeparator(pos)) {
2828 if (pos > cursor.row()->pos() &&
2829 bidi_level(pos) % 2 ==
2830 bidi_level(pos - 1) % 2)
2832 else if (pos + 1 < cursor.par()->Last())
2838 cursor.par()->GetFontSettings(bview->buffer()->params, pos);
2839 real_current_font = GetFont(bview->buffer(), cursor.par(), pos);
2841 if (cursor.pos() == cursor.par()->Last() &&
2842 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()) &&
2843 !cursor.boundary()) {
2844 Language const * lang =
2845 cursor.par()->getParLanguage(bview->buffer()->params);
2846 current_font.setLanguage(lang);
2847 current_font.setNumber(LyXFont::OFF);
2848 real_current_font.setLanguage(lang);
2849 real_current_font.setNumber(LyXFont::OFF);
2854 void LyXText::SetCursorFromCoordinates(BufferView * bview, int x, int y) const
2856 LyXCursor old_cursor = cursor;
2858 /* get the row first */
2860 Row * row = GetRowNearY(y);
2861 cursor.par(row->par());
2864 int column = GetColumnNearX(bview, row, x, bound);
2865 cursor.pos(row->pos() + column);
2867 cursor.y(y + row->baseline());
2869 cursor.boundary(bound);
2870 SetCurrentFont(bview);
2871 DeleteEmptyParagraphMechanism(bview, old_cursor);
2875 void LyXText::SetCursorFromCoordinates(BufferView * bview, LyXCursor & cur,
2878 /* get the row first */
2880 Row * row = GetRowNearY(y);
2882 int column = GetColumnNearX(bview, row, x, bound);
2884 cur.par(row->par());
2885 cur.pos(row->pos() + column);
2887 cur.y(y + row->baseline());
2889 cur.boundary(bound);
2893 void LyXText::CursorLeft(BufferView * bview, bool internal) const
2895 if (cursor.pos() > 0) {
2896 bool boundary = cursor.boundary();
2897 SetCursor(bview, cursor.par(), cursor.pos() - 1, true, false);
2898 if (!internal && !boundary &&
2899 IsBoundary(bview->buffer(), cursor.par(), cursor.pos() + 1))
2900 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, true);
2901 } else if (cursor.par()->previous()) { // steps into the above paragraph.
2902 LyXParagraph * par = cursor.par()->previous();
2903 SetCursor(bview, par, par->Last());
2908 void LyXText::CursorRight(BufferView * bview, bool internal) const
2910 if (!internal && cursor.boundary() &&
2911 !cursor.par()->IsNewline(cursor.pos()))
2912 SetCursor(bview, cursor.par(), cursor.pos(), true, false);
2913 else if (cursor.pos() < cursor.par()->Last()) {
2914 SetCursor(bview, cursor.par(), cursor.pos() + 1, true, false);
2916 IsBoundary(bview->buffer(), cursor.par(), cursor.pos()))
2917 SetCursor(bview, cursor.par(), cursor.pos(), true, true);
2918 } else if (cursor.par()->next())
2919 SetCursor(bview, cursor.par()->next(), 0);
2923 void LyXText::CursorUp(BufferView * bview) const
2925 SetCursorFromCoordinates(bview, cursor.x_fix(),
2926 cursor.y() - cursor.row()->baseline() - 1);
2930 void LyXText::CursorDown(BufferView * bview) const
2932 SetCursorFromCoordinates(bview, cursor.x_fix(),
2933 cursor.y() - cursor.row()->baseline()
2934 + cursor.row()->height() + 1);
2938 void LyXText::CursorUpParagraph(BufferView * bview) const
2940 if (cursor.pos() > 0) {
2941 SetCursor(bview, cursor.par(), 0);
2943 else if (cursor.par()->previous()) {
2944 SetCursor(bview, cursor.par()->previous(), 0);
2949 void LyXText::CursorDownParagraph(BufferView * bview) const
2951 if (cursor.par()->next()) {
2952 SetCursor(bview, cursor.par()->next(), 0);
2954 SetCursor(bview, cursor.par(), cursor.par()->Last());
2959 void LyXText::DeleteEmptyParagraphMechanism(BufferView * bview,
2960 LyXCursor const & old_cursor) const
2962 // Would be wrong to delete anything if we have a selection.
2963 if (selection) return;
2965 // We allow all kinds of "mumbo-jumbo" when freespacing.
2966 if (textclasslist.Style(bview->buffer()->params.textclass,
2967 old_cursor.par()->GetLayout()).free_spacing)
2970 bool deleted = false;
2972 /* Ok I'll put some comments here about what is missing.
2973 I have fixed BackSpace (and thus Delete) to not delete
2974 double-spaces automagically. I have also changed Cut,
2975 Copy and Paste to hopefully do some sensible things.
2976 There are still some small problems that can lead to
2977 double spaces stored in the document file or space at
2978 the beginning of paragraphs. This happens if you have
2979 the cursor betwenn to spaces and then save. Or if you
2980 cut and paste and the selection have a space at the
2981 beginning and then save right after the paste. I am
2982 sure none of these are very hard to fix, but I will
2983 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
2984 that I can get some feedback. (Lgb)
2987 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
2988 // delete the LineSeparator.
2991 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
2992 // delete the LineSeparator.
2995 // If the pos around the old_cursor were spaces, delete one of them.
2996 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
2997 // Only if the cursor has really moved
2999 if (old_cursor.pos() > 0
3000 && old_cursor.pos() < old_cursor.par()->Last()
3001 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3002 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3003 old_cursor.par()->Erase(old_cursor.pos() - 1);
3004 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3006 if (old_cursor.par() == cursor.par() &&
3007 cursor.pos() > old_cursor.pos()) {
3008 SetCursorIntern(bview, cursor.par(),
3011 SetCursorIntern(bview, cursor.par(),
3017 // Do not delete empty paragraphs with keepempty set.
3018 if ((textclasslist.Style(bview->buffer()->params.textclass,
3019 old_cursor.par()->GetLayout())).keepempty)
3022 LyXCursor tmpcursor;
3024 if (old_cursor.par() != cursor.par()) {
3025 if ((old_cursor.par()->Last() == 0
3026 || (old_cursor.par()->Last() == 1
3027 && old_cursor.par()->IsLineSeparator(0)))
3029 && old_cursor.par()->FirstPhysicalPar()
3030 == old_cursor.par()->LastPhysicalPar()
3033 // ok, we will delete anything
3035 // make sure that you do not delete any environments
3038 old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3039 !(old_cursor.row()->previous()
3040 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3041 && !(old_cursor.row()->next()
3042 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3043 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3044 && ((old_cursor.row()->previous()
3045 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3046 || (old_cursor.row()->next()
3047 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3050 status = LyXText::NEED_MORE_REFRESH;
3053 if (old_cursor.row()->previous()) {
3054 refresh_row = old_cursor.row()->previous();
3055 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3057 cursor = old_cursor; // that undo can restore the right cursor position
3059 LyXParagraph * endpar = old_cursor.par()->next_;
3060 if (endpar && endpar->GetDepth()) {
3061 while (endpar && endpar->GetDepth()) {
3062 endpar = endpar->LastPhysicalPar()->next();
3065 SetUndo(bview->buffer(), Undo::DELETE,
3066 old_cursor.par()->previous_,
3071 RemoveRow(old_cursor.row());
3072 if (OwnerParagraph() == old_cursor.par()) {
3073 OwnerParagraph(OwnerParagraph()->next_);
3076 LyXParagraph * endpar = old_cursor.par()->next();
3077 if (endpar && endpar->GetDepth()) {
3078 while (endpar && endpar->GetDepth()) {
3079 endpar = endpar->next();
3082 SetUndo(bview->buffer(), Undo::DELETE,
3083 old_cursor.par()->previous(),
3088 RemoveRow(old_cursor.row());
3089 if (OwnerParagraph() == old_cursor.par()) {
3090 OwnerParagraph(OwnerParagraph()->next());
3094 delete old_cursor.par();
3096 /* Breakagain the next par. Needed
3097 * because of the parindent that
3098 * can occur or dissappear. The
3099 * next row can change its height,
3100 * if there is another layout before */
3101 if (refresh_row->next()) {
3102 BreakAgain(bview, refresh_row->next());
3103 UpdateCounters(bview, refresh_row);
3105 SetHeightOfRow(bview, refresh_row);
3107 refresh_row = old_cursor.row()->next();
3108 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3111 cursor = old_cursor; // that undo can restore the right cursor position
3113 LyXParagraph * endpar = old_cursor.par()->next_;
3114 if (endpar && endpar->GetDepth()) {
3115 while (endpar && endpar->GetDepth()) {
3116 endpar = endpar->LastPhysicalPar()->next();
3119 SetUndo(bview->buffer(), Undo::DELETE,
3120 old_cursor.par()->previous_,
3125 RemoveRow(old_cursor.row());
3127 if (OwnerParagraph() == old_cursor.par()) {
3128 OwnerParagraph(OwnerParagraph()->next_);
3131 LyXParagraph * endpar = old_cursor.par()->next();
3132 if (endpar && endpar->GetDepth()) {
3133 while (endpar && endpar->GetDepth()) {
3134 endpar = endpar->next();
3137 SetUndo(bview->buffer(), Undo::DELETE,
3138 old_cursor.par()->previous(),
3143 RemoveRow(old_cursor.row());
3145 if (OwnerParagraph() == old_cursor.par()) {
3146 OwnerParagraph(OwnerParagraph()->next());
3149 delete old_cursor.par();
3151 /* Breakagain the next par. Needed
3152 because of the parindent that can
3153 occur or dissappear.
3154 The next row can change its height,
3155 if there is another layout before
3158 BreakAgain(bview, refresh_row);
3159 UpdateCounters(bview, refresh_row->previous());
3165 SetCursorIntern(bview, cursor.par(), cursor.pos());
3167 if (sel_cursor.par() == old_cursor.par()
3168 && sel_cursor.pos() == sel_cursor.pos()) {
3169 // correct selection
3170 sel_cursor = cursor;
3177 if (old_cursor.par()->StripLeadingSpaces(bview->buffer()->params.textclass)) {
3178 RedoParagraphs(bview, old_cursor, old_cursor.par()->next());
3180 SetCursorIntern(bview, cursor.par(), cursor.pos());
3181 sel_cursor = cursor;
3189 LyXParagraph * LyXText::GetParFromID(int id)
3191 LyXParagraph * result = FirstParagraph();
3192 while (result && result->id() != id)
3193 result = result->next_;
3197 LyXParagraph * LyXText::GetParFromID(int id)
3199 LyXParagraph * result = FirstParagraph();
3200 while (result && result->id() != id)
3201 result = result->next();
3208 bool LyXText::TextUndo(BufferView * bview)
3212 // returns false if no undo possible
3213 Undo * undo = bview->buffer()->undostack.pop();
3217 bview->buffer()->redostack
3218 .push(CreateUndo(bview->buffer(), undo->kind,
3219 GetParFromID(undo->number_of_before_par),
3220 GetParFromID(undo->number_of_behind_par)));
3222 return TextHandleUndo(bview, undo);
3226 bool LyXText::TextRedo(BufferView * bview)
3230 // returns false if no redo possible
3231 Undo * undo = bview->buffer()->redostack.pop();
3235 bview->buffer()->undostack
3236 .push(CreateUndo(bview->buffer(), undo->kind,
3237 GetParFromID(undo->number_of_before_par),
3238 GetParFromID(undo->number_of_behind_par)));
3240 return TextHandleUndo(bview, undo);
3244 bool LyXText::TextHandleUndo(BufferView * bview, Undo * undo)
3248 // returns false if no undo possible
3249 bool result = false;
3251 LyXParagraph * before =
3252 GetParFromID(undo->number_of_before_par);
3253 LyXParagraph * behind =
3254 GetParFromID(undo->number_of_behind_par);
3255 LyXParagraph * tmppar;
3256 LyXParagraph * tmppar2;
3257 LyXParagraph * endpar;
3258 LyXParagraph * tmppar5;
3260 // if there's no before take the beginning
3261 // of the document for redoing
3263 SetCursorIntern(bview, FirstParagraph(), 0);
3265 // replace the paragraphs with the undo informations
3267 LyXParagraph * tmppar3 = undo->par;
3268 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3269 LyXParagraph * tmppar4 = tmppar3;
3272 while (tmppar4->next_)
3273 tmppar4 = tmppar4->next_;
3274 } // get last undo par
3276 // now remove the old text if there is any
3277 if (before != behind || (!behind && !before)) {
3279 tmppar5 = before->next();
3281 tmppar5 = OwnerParagraph();
3283 while (tmppar5 && tmppar5 != behind) {
3285 tmppar5 = tmppar5->next();
3286 // a memory optimization for edit: Only layout information
3287 // is stored in the undo. So restore the text informations.
3288 if (undo->kind == Undo::EDIT) {
3289 tmppar2->setContentsFromPar(tmppar);
3290 tmppar->clearContents();
3291 tmppar2 = tmppar2->next();
3298 while (tmppar4->next())
3299 tmppar4 = tmppar4->next();
3300 } // get last undo par
3302 // now remove the old text if there is any
3303 if (before != behind || (!behind && !before)) {
3305 tmppar5 = before->next();
3307 tmppar5 = OwnerParagraph();
3309 while (tmppar5 && tmppar5 != behind) {
3311 tmppar5 = tmppar5->next();
3312 // a memory optimization for edit: Only layout information
3313 // is stored in the undo. So restore the text informations.
3314 if (undo->kind == Undo::EDIT) {
3315 tmppar2->setContentsFromPar(tmppar);
3316 tmppar->clearContents();
3317 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;
3491 start = before->next_;
3493 start = FirstParagraph();
3495 end = behind->previous_;
3497 end = FirstParagraph();
3501 if (start && end && (start != end->next_) &&
3502 ((before != behind) || (!before && !behind))) {
3504 tmppar2 = tmppar->Clone();
3505 tmppar2->id(tmppar->id());
3507 // a memory optimization: Just store the layout information
3509 if (kind == Undo::EDIT){
3510 //tmppar2->text.clear();
3511 tmppar2->clearContents();
3516 while (tmppar != end && tmppar->next_) {
3517 tmppar = tmppar->next_;
3518 tmppar2->next(tmppar->Clone());
3519 tmppar2->next_->id(tmppar->id());
3520 // a memory optimization: Just store the layout
3521 // information when only edit
3522 if (kind == Undo::EDIT){
3523 //tmppar2->next->text.clear();
3524 tmppar2->clearContents();
3526 tmppar2->next_->previous(tmppar2);
3527 tmppar2 = tmppar2->next_;
3531 undopar = 0; // nothing to replace (undo of delete maybe)
3533 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
3534 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
3537 start = const_cast<LyXParagraph*>(before->next());
3539 start = FirstParagraph();
3541 end = const_cast<LyXParagraph*>(behind->previous());
3543 end = FirstParagraph();
3547 if (start && end && (start != end->next()) &&
3548 ((before != behind) || (!before && !behind))) {
3550 tmppar2 = tmppar->Clone();
3551 tmppar2->id(tmppar->id());
3553 // a memory optimization: Just store the layout information
3555 if (kind == Undo::EDIT){
3556 //tmppar2->text.clear();
3557 tmppar2->clearContents();
3562 while (tmppar != end && tmppar->next()) {
3563 tmppar = tmppar->next();
3564 tmppar2->next(tmppar->Clone());
3565 tmppar2->next()->id(tmppar->id());
3566 // a memory optimization: Just store the layout
3567 // information when only edit
3568 if (kind == Undo::EDIT){
3569 //tmppar2->next->text.clear();
3570 tmppar2->clearContents();
3572 tmppar2->next()->previous(tmppar2);
3573 tmppar2 = tmppar2->next();
3577 undopar = 0; // nothing to replace (undo of delete maybe)
3579 int cursor_par = cursor.par()->id();
3580 int cursor_pos = cursor.pos();
3583 Undo * undo = new Undo(kind,
3584 before_number, behind_number,
3585 cursor_par, cursor_pos,
3588 undo_finished = false;
3593 void LyXText::SetCursorParUndo(Buffer * buf)
3597 SetUndo(buf, Undo::FINISH,
3599 cursor.par()->ParFromPos(cursor.pos())->previous_,
3600 cursor.par()->ParFromPos(cursor.pos())->next_
3602 cursor.par()->previous(),
3603 cursor.par()->next()
3609 void LyXText::toggleAppendix(BufferView * bview)
3612 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
3614 LyXParagraph * par = cursor.par();
3616 bool start = !par->params.startOfAppendix();
3618 // ensure that we have only one start_of_appendix in this document
3619 LyXParagraph * tmp = FirstParagraph();
3621 for (; tmp; tmp = tmp->next_)
3622 tmp->params.startOfAppendix(false);
3624 for (; tmp; tmp = tmp->next())
3625 tmp->params.startOfAppendix(false);
3627 par->params.startOfAppendix(start);
3629 // we can set the refreshing parameters now
3630 status = LyXText::NEED_MORE_REFRESH;
3632 refresh_row = 0; // not needed for full update
3633 UpdateCounters(bview, 0);
3634 SetCursor(bview, cursor.par(), cursor.pos());
3638 LyXParagraph * LyXText::OwnerParagraph() const
3641 return inset_owner->par;
3643 return bv_owner->buffer()->paragraph;
3647 LyXParagraph * LyXText::OwnerParagraph(LyXParagraph * p) const
3650 inset_owner->par = p;
3652 bv_owner->buffer()->paragraph = p;