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"
27 #include "support/textutils.h"
29 #include "minibuffer.h"
31 #include "bufferparams.h"
32 #include "lyx_gui_misc.h"
35 #include "BufferView.h"
38 #include "CutAndPaste.h"
43 //#define USE_OLD_CUT_AND_PASTE 1
49 LyXText::LyXText(BufferView * bv, int pw, Buffer * p)
58 status = LyXText::UNCHANGED;
59 LyXParagraph * par = p->paragraph;
60 current_font = GetFont(par, 0);
65 InsertParagraph(par, lastrow);
69 // set cursor at the very top position
70 selection = true; /* these setting is necessary
71 because of the delete-empty-
72 paragraph mechanism in
74 SetCursor(firstrow->par, 0);
79 // no rebreak necessary
85 // Default layouttype for copy environment type
89 // Dump all rowinformation:
90 Row * tmprow = firstrow;
91 lyxerr << "Baseline Paragraph Pos Height Ascent Fill\n";
93 lyxerr << tmprow->baseline << '\t'
94 << tmprow->par << '\t'
95 << tmprow->pos << '\t'
96 << tmprow->height << '\t'
97 << tmprow->ascent_of_text << '\t'
98 << tmprow->fill << '\n';
99 tmprow = tmprow->next;
108 // Delete all rows, this does not touch the paragraphs!
109 Row * tmprow = firstrow;
111 tmprow = firstrow->next;
118 void LyXText::owner(BufferView * bv)
120 if (owner_ && bv) lyxerr << "LyXText::owner_ already set!" << endl;
124 // Gets the fully instantiated font at a given position in a paragraph
125 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
126 // The difference is that this one is used for displaying, and thus we
127 // are allowed to make cosmetic improvements. For instance make footnotes
129 // If position is -1, we get the layout font of the paragraph.
130 // If position is -2, we get the font of the manual label of the paragraph.
131 LyXFont LyXText::GetFont(LyXParagraph * par,
132 LyXParagraph::size_type pos) const
134 LyXLayout const & layout =
135 textclasslist.Style(buffer->params.textclass,
138 char par_depth = par->GetDepth();
139 // We specialize the 95% common case:
140 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
143 if (layout.labeltype == LABEL_MANUAL
144 && pos < BeginningOfMainBody(par)) {
146 return par->GetFontSettings(pos).
147 realize(layout.reslabelfont);
149 return par->GetFontSettings(pos).
150 realize(layout.resfont);
153 // process layoutfont for pos == -1 and labelfont for pos < -1
155 return layout.resfont;
157 return layout.reslabelfont;
161 // The uncommon case need not be optimized as much
163 LyXFont layoutfont, tmpfont;
167 if (pos < BeginningOfMainBody(par)) {
169 layoutfont = layout.labelfont;
172 layoutfont = layout.font;
174 tmpfont = par->GetFontSettings(pos);
175 tmpfont.realize(layoutfont);
178 // process layoutfont for pos == -1 and labelfont for pos < -1
180 tmpfont = layout.font;
182 tmpfont = layout.labelfont;
185 // Resolve against environment font information
186 while (par && par_depth && !tmpfont.resolved()) {
187 par = par->DepthHook(par_depth - 1);
189 tmpfont.realize(textclasslist.
190 Style(buffer->params.textclass,
191 par->GetLayout()).font);
192 par_depth = par->GetDepth();
196 tmpfont.realize(textclasslist.TextClass(buffer->params.textclass).defaultfont());
198 // Cosmetic improvement: If this is an open footnote, make the font
200 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
201 && par->footnotekind == LyXParagraph::FOOTNOTE) {
209 void LyXText::SetCharFont(LyXParagraph * par,
210 LyXParagraph::size_type pos,
214 // Let the insets convert their font
215 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
216 if (par->GetInset(pos))
217 font = par->GetInset(pos)->ConvertFont(font);
220 LyXLayout const & layout =
221 textclasslist.Style(buffer->params.textclass,
224 // Get concrete layout font to reduce against
227 if (pos < BeginningOfMainBody(par))
228 layoutfont = layout.labelfont;
230 layoutfont = layout.font;
232 // Realize against environment font information
233 if (par->GetDepth()){
234 LyXParagraph * tp = par;
235 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
236 tp = tp->DepthHook(tp->GetDepth()-1);
238 layoutfont.realize(textclasslist.
239 Style(buffer->params.textclass,
240 tp->GetLayout()).font);
244 layoutfont.realize(textclasslist.TextClass(buffer->params.textclass).defaultfont());
246 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
247 && par->footnotekind == LyXParagraph::FOOTNOTE) {
248 layoutfont.decSize();
251 // Now, reduce font against full layout font
252 font.reduce(layoutfont);
254 par->SetFont(pos, font);
258 /* inserts a new row behind the specified row, increments
259 * the touched counters */
260 void LyXText::InsertRow(Row * row, LyXParagraph * par,
261 LyXParagraph::size_type pos) const
263 Row * tmprow = new Row;
265 tmprow->previous = 0;
266 tmprow->next = firstrow;
269 tmprow->previous = row;
270 tmprow->next = row->next;
275 tmprow->next->previous = tmprow;
277 if (tmprow->previous)
278 tmprow->previous->next = tmprow;
286 ++number_of_rows; // one more row
290 // removes the row and reset the touched counters
291 void LyXText::RemoveRow(Row * row) const
293 /* this must not happen before the currentrow for clear reasons.
294 so the trick is just to set the current row onto the previous
297 GetRow(row->par, row->pos, unused_y);
300 row->next->previous = row->previous;
301 if (!row->previous) {
302 firstrow = row->next;
304 row->previous->next = row->next;
307 lastrow = row->previous;
309 height -= row->height; // the text becomes smaller
312 --number_of_rows; // one row less
316 // remove all following rows of the paragraph of the specified row.
317 void LyXText::RemoveParagraph(Row * row) const
319 LyXParagraph * tmppar = row->par;
323 while (row && row->par == tmppar) {
331 // insert the specified paragraph behind the specified row
332 void LyXText::InsertParagraph(LyXParagraph * par, Row * row) const
334 InsertRow(row, par, 0); /* insert a new row, starting
337 SetCounter(par); // set the counters
339 // and now append the whole paragraph behind the new row
341 firstrow->height = 0;
342 AppendParagraph(firstrow);
344 row->next->height = 0;
345 AppendParagraph(row->next);
350 void LyXText::ToggleFootnote()
352 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
354 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
356 owner_->owner()->getMiniBuffer()->Set(_("Opened float"));
358 owner_->owner()->getMiniBuffer()->Set(_("Closed float"));
364 void LyXText::OpenStuff()
366 if (cursor.pos == 0 && cursor.par->bibkey){
367 cursor.par->bibkey->Edit(owner_, 0, 0, 0);
369 else if (cursor.pos < cursor.par->Last()
370 && cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
371 && cursor.par->GetInset(cursor.pos)->Editable()) {
372 owner_->owner()->getMiniBuffer()
373 ->Set(cursor.par->GetInset(cursor.pos)->EditMessage());
374 if (cursor.par->GetInset(cursor.pos)->Editable() != Inset::HIGHLY_EDITABLE)
376 cursor.par->GetInset(cursor.pos)->Edit(owner_, 0, 0, 0);
383 void LyXText::CloseFootnote()
385 LyXParagraph * tmppar;
386 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
388 // if the cursor is not in an open footnote, or
389 // there is no open footnote in this paragraph, just return.
390 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
393 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
394 owner_->owner()->getMiniBuffer()
395 ->Set(_("Nothing to do"));
399 // ok, move the cursor right before the footnote
400 // just a little faster than using CursorRight()
402 cursor.par->ParFromPos(cursor.pos) != par;
406 // now the cursor is at the beginning of the physical par
407 SetCursor(cursor.par,
409 cursor.par->ParFromPos(cursor.pos)->size());
411 /* we are in a footnote, so let us move at the beginning */
412 /* this is just faster than using just CursorLeft() */
415 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
416 // just a little bit faster than movin the cursor
417 tmppar = tmppar->Previous();
419 SetCursor(tmppar, tmppar->Last());
422 // the cursor must be exactly before the footnote
423 par = cursor.par->ParFromPos(cursor.pos);
425 status = LyXText::NEED_MORE_REFRESH;
426 refresh_row = cursor.row;
427 refresh_y = cursor.y - cursor.row->baseline;
430 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
431 Row * row = cursor.row;
433 tmppar->CloseFootnote(cursor.pos);
435 while (tmppar != endpar) {
436 RemoveRow(row->next);
438 tmppar = row->next->par;
443 AppendParagraph(cursor.row);
445 SetCursor(cursor.par, cursor.pos);
449 if (cursor.row->next)
450 SetHeightOfRow(cursor.row->next);
454 /* used in setlayout */
455 // Asger is not sure we want to do this...
456 void LyXText::MakeFontEntriesLayoutSpecific(LyXParagraph * par)
459 LyXLayout const & layout =
460 textclasslist.Style(buffer->params.textclass,
463 LyXFont layoutfont, tmpfont;
464 for (LyXParagraph::size_type pos = 0;
465 pos < par->Last(); ++pos) {
466 if (pos < BeginningOfMainBody(par))
467 layoutfont = layout.labelfont;
469 layoutfont = layout.font;
471 tmpfont = par->GetFontSettings(pos);
472 tmpfont.reduce(layoutfont);
473 par->SetFont(pos, tmpfont);
477 LyXParagraph * LyXText::SetLayout(LyXCursor & cur, LyXCursor & sstart_cur,
478 LyXCursor & send_cur,
479 LyXTextClass::size_type layout)
481 LyXParagraph * endpar = send_cur.par->LastPhysicalPar()->Next();
482 LyXParagraph * undoendpar = endpar;
484 if (endpar && endpar->GetDepth()) {
485 while (endpar && endpar->GetDepth()) {
486 endpar = endpar->LastPhysicalPar()->Next();
490 endpar = endpar->Next(); // because of parindents etc.
494 sstart_cur.par->ParFromPos(sstart_cur.pos)->previous,
497 /* ok we have a selection. This is always between sstart_cur
498 * and sel_end cursor */
501 LyXLayout const & lyxlayout =
502 textclasslist.Style(buffer->params.textclass, layout);
504 while (cur.par != send_cur.par) {
505 if (cur.par->footnoteflag == sstart_cur.par->footnoteflag) {
506 cur.par->SetLayout(layout);
507 MakeFontEntriesLayoutSpecific(cur.par);
508 LyXParagraph* fppar = cur.par->FirstPhysicalPar();
509 fppar->added_space_top = lyxlayout.fill_top ?
510 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
511 fppar->added_space_bottom = lyxlayout.fill_bottom ?
512 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
513 if (lyxlayout.margintype == MARGIN_MANUAL)
514 cur.par->SetLabelWidthString(lyxlayout.labelstring());
515 if (lyxlayout.labeltype != LABEL_BIBLIO
517 delete fppar->bibkey;
521 cur.par = cur.par->Next();
523 if (cur.par->footnoteflag == sstart_cur.par->footnoteflag) {
524 cur.par->SetLayout(layout);
525 MakeFontEntriesLayoutSpecific(cur.par);
526 LyXParagraph* fppar = cur.par->FirstPhysicalPar();
527 fppar->added_space_top = lyxlayout.fill_top ?
528 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
529 fppar->added_space_bottom = lyxlayout.fill_bottom ?
530 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
531 if (lyxlayout.margintype == MARGIN_MANUAL)
532 cur.par->SetLabelWidthString(lyxlayout.labelstring());
533 if (lyxlayout.labeltype != LABEL_BIBLIO
535 delete fppar->bibkey;
542 // set layout over selection and make a total rebreak of those paragraphs
543 void LyXText::SetLayout(LyXTextClass::size_type layout)
546 tmpcursor = cursor; /* store the current cursor */
548 #ifdef USE_OLD_SET_LAYOUT
549 // if there is no selection just set the layout
550 // of the current paragraph */
552 sel_start_cursor = cursor; // dummy selection
553 sel_end_cursor = cursor;
556 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
557 LyXParagraph * undoendpar = endpar;
559 if (endpar && endpar->GetDepth()) {
560 while (endpar && endpar->GetDepth()) {
561 endpar = endpar->LastPhysicalPar()->Next();
566 endpar = endpar->Next(); // because of parindents etc.
570 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
573 /* ok we have a selection. This is always between sel_start_cursor
574 * and sel_end cursor */
575 cursor = sel_start_cursor;
577 LyXLayout const & lyxlayout =
578 textclasslist.Style(buffer->params.textclass, layout);
580 while (cursor.par != sel_end_cursor.par) {
581 if (cursor.par->footnoteflag ==
582 sel_start_cursor.par->footnoteflag) {
583 cursor.par->SetLayout(layout);
584 MakeFontEntriesLayoutSpecific(cursor.par);
585 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
586 fppar->added_space_top = lyxlayout.fill_top ?
587 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
588 fppar->added_space_bottom = lyxlayout.fill_bottom ?
589 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
590 if (lyxlayout.margintype == MARGIN_MANUAL)
591 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
592 if (lyxlayout.labeltype != LABEL_BIBLIO
594 delete fppar->bibkey;
598 cursor.par = cursor.par->Next();
600 if (cursor.par->footnoteflag ==
601 sel_start_cursor.par->footnoteflag) {
602 cursor.par->SetLayout(layout);
603 MakeFontEntriesLayoutSpecific(cursor.par);
604 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
605 fppar->added_space_top = lyxlayout.fill_top ?
606 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
607 fppar->added_space_bottom = lyxlayout.fill_bottom ?
608 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
609 if (lyxlayout.margintype == MARGIN_MANUAL)
610 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
611 if (lyxlayout.labeltype != LABEL_BIBLIO
613 delete fppar->bibkey;
618 // if there is no selection just set the layout
619 // of the current paragraph */
621 sel_start_cursor = cursor; // dummy selection
622 sel_end_cursor = cursor;
625 endpar = SetLayout(cursor, sel_start_cursor, sel_end_cursor, layout);
627 RedoParagraphs(sel_start_cursor, endpar);
629 // we have to reset the selection, because the
630 // geometry could have changed */
631 SetCursor(sel_start_cursor.par, sel_start_cursor.pos, false);
633 SetCursor(sel_end_cursor.par, sel_end_cursor.pos, false);
634 UpdateCounters(cursor.row);
637 SetCursor(tmpcursor.par, tmpcursor.pos, true);
641 // increment depth over selection and
642 // make a total rebreak of those paragraphs
643 void LyXText::IncDepth()
645 // If there is no selection, just use the current paragraph
647 sel_start_cursor = cursor; // dummy selection
648 sel_end_cursor = cursor;
651 // We end at the next paragraph with depth 0
652 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
653 LyXParagraph * undoendpar = endpar;
655 if (endpar && endpar->GetDepth()) {
656 while (endpar && endpar->GetDepth()) {
657 endpar = endpar->LastPhysicalPar()->Next();
662 endpar = endpar->Next(); // because of parindents etc.
667 .par->ParFromPos(sel_start_cursor.pos)->previous,
670 LyXCursor tmpcursor = cursor; // store the current cursor
672 // ok we have a selection. This is always between sel_start_cursor
673 // and sel_end cursor
674 cursor = sel_start_cursor;
676 bool anything_changed = false;
679 // NOTE: you can't change the depth of a bibliography entry
680 if (cursor.par->footnoteflag ==
681 sel_start_cursor.par->footnoteflag
682 && textclasslist.Style(buffer->params.textclass,
683 cursor.par->GetLayout()
684 ).labeltype != LABEL_BIBLIO) {
685 LyXParagraph * prev =
686 cursor.par->FirstPhysicalPar()->Previous();
688 && (prev->GetDepth() - cursor.par->GetDepth() > 0
689 || (prev->GetDepth() == cursor.par->GetDepth()
690 && textclasslist.Style(buffer->params.textclass,
691 prev->GetLayout()).isEnvironment()))) {
692 cursor.par->FirstPhysicalPar()->depth++;
693 anything_changed = true;
696 if (cursor.par == sel_end_cursor.par)
698 cursor.par = cursor.par->Next();
701 // if nothing changed set all depth to 0
702 if (!anything_changed) {
703 cursor = sel_start_cursor;
704 while (cursor.par != sel_end_cursor.par) {
705 cursor.par->FirstPhysicalPar()->depth = 0;
706 cursor.par = cursor.par->Next();
708 if (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag)
709 cursor.par->FirstPhysicalPar()->depth = 0;
712 RedoParagraphs(sel_start_cursor, endpar);
714 // we have to reset the selection, because the
715 // geometry could have changed
716 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
718 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
719 UpdateCounters(cursor.row);
722 SetCursor(tmpcursor.par, tmpcursor.pos);
726 // decrement depth over selection and
727 // make a total rebreak of those paragraphs
728 void LyXText::DecDepth()
730 // if there is no selection just set the layout
731 // of the current paragraph
733 sel_start_cursor = cursor; // dummy selection
734 sel_end_cursor = cursor;
737 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
738 LyXParagraph * undoendpar = endpar;
740 if (endpar && endpar->GetDepth()) {
741 while (endpar && endpar->GetDepth()) {
742 endpar = endpar->LastPhysicalPar()->Next();
747 endpar = endpar->Next(); // because of parindents etc.
752 .par->ParFromPos(sel_start_cursor.pos)->previous,
755 LyXCursor tmpcursor = cursor; // store the current cursor
757 // ok we have a selection. This is always between sel_start_cursor
758 // and sel_end cursor
759 cursor = sel_start_cursor;
762 if (cursor.par->footnoteflag ==
763 sel_start_cursor.par->footnoteflag) {
764 if (cursor.par->FirstPhysicalPar()->depth)
765 cursor.par->FirstPhysicalPar()->depth--;
767 if (cursor.par == sel_end_cursor.par)
769 cursor.par = cursor.par->Next();
772 RedoParagraphs(sel_start_cursor, endpar);
774 // we have to reset the selection, because the
775 // geometry could have changed
776 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
778 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
779 UpdateCounters(cursor.row);
782 SetCursor(tmpcursor.par, tmpcursor.pos);
786 // set font over selection and make a total rebreak of those paragraphs
787 void LyXText::SetFont(LyXFont const & font, bool toggleall)
789 // if there is no selection just set the current_font
791 // Determine basis font
793 if (cursor.pos < BeginningOfMainBody(cursor.par))
794 layoutfont = GetFont(cursor.par, -2);
796 layoutfont = GetFont(cursor.par, -1);
797 // Update current font
798 real_current_font.update(font,
799 buffer->params.language_info,
802 // Reduce to implicit settings
803 current_font = real_current_font;
804 current_font.reduce(layoutfont);
805 // And resolve it completely
806 real_current_font.realize(layoutfont);
810 LyXCursor tmpcursor = cursor; // store the current cursor
812 // ok we have a selection. This is always between sel_start_cursor
813 // and sel_end cursor
816 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
817 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
818 cursor = sel_start_cursor;
819 while (cursor.par != sel_end_cursor.par ||
820 (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag
821 && cursor.pos < sel_end_cursor.pos))
823 if (cursor.pos < cursor.par->Last()
824 && cursor.par->footnoteflag
825 == sel_start_cursor.par->footnoteflag) {
826 // an open footnote should behave
828 LyXFont newfont = GetFont(cursor.par, cursor.pos);
830 buffer->params.language_info,
832 SetCharFont(cursor.par, cursor.pos, newfont);
836 cursor.par = cursor.par->Next();
840 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
842 // we have to reset the selection, because the
843 // geometry could have changed
844 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
846 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
849 SetCursor(tmpcursor.par, tmpcursor.pos);
853 void LyXText::RedoHeightOfParagraph(LyXCursor const & cur)
855 Row * tmprow = cur.row;
856 long y = cur.y - tmprow->baseline;
858 SetHeightOfRow(tmprow);
859 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
860 // find the first row of the paragraph
861 if (first_phys_par != tmprow->par)
862 while (tmprow->previous
863 && tmprow->previous->par != first_phys_par) {
864 tmprow = tmprow->previous;
866 SetHeightOfRow(tmprow);
868 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
869 tmprow = tmprow->previous;
871 SetHeightOfRow(tmprow);
874 // we can set the refreshing parameters now
875 status = LyXText::NEED_MORE_REFRESH;
877 refresh_row = tmprow;
878 SetCursor(cur.par, cur.pos);
882 void LyXText::RedoDrawingOfParagraph(LyXCursor const & cur)
884 Row * tmprow = cur.row;
886 long y = cur.y - tmprow->baseline;
887 SetHeightOfRow(tmprow);
888 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
889 // find the first row of the paragraph
890 if (first_phys_par != tmprow->par)
891 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
892 tmprow = tmprow->previous;
895 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
896 tmprow = tmprow->previous;
900 // we can set the refreshing parameters now
901 if (status == LyXText::UNCHANGED || y < refresh_y) {
903 refresh_row = tmprow;
905 status = LyXText::NEED_MORE_REFRESH;
906 SetCursor(cur.par, cur.pos);
910 /* deletes and inserts again all paragaphs between the cursor
911 * and the specified par
912 * This function is needed after SetLayout and SetFont etc. */
913 void LyXText::RedoParagraphs(LyXCursor const & cur,
914 LyXParagraph const * endpar) const
917 LyXParagraph * tmppar, * first_phys_par;
919 Row * tmprow = cur.row;
921 long y = cur.y - tmprow->baseline;
923 if (!tmprow->previous){
924 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
926 first_phys_par = tmprow->par->FirstPhysicalPar();
927 // find the first row of the paragraph
928 if (first_phys_par != tmprow->par)
929 while (tmprow->previous &&
930 (tmprow->previous->par != first_phys_par)) {
931 tmprow = tmprow->previous;
934 while (tmprow->previous
935 && tmprow->previous->par == first_phys_par) {
936 tmprow = tmprow->previous;
941 // we can set the refreshing parameters now
942 status = LyXText::NEED_MORE_REFRESH;
944 refresh_row = tmprow->previous; /* the real refresh row will
945 be deleted, so I store
949 tmppar = tmprow->next->par;
952 while (tmppar != endpar) {
953 RemoveRow(tmprow->next);
955 tmppar = tmprow->next->par;
960 // remove the first one
961 tmprow2 = tmprow; /* this is because tmprow->previous
963 tmprow = tmprow->previous;
966 tmppar = first_phys_par;
970 InsertParagraph(tmppar, tmprow);
973 while (tmprow->next && tmprow->next->par == tmppar)
974 tmprow = tmprow->next;
975 tmppar = tmppar->Next();
977 } while (tmppar != endpar);
979 // this is because of layout changes
981 refresh_y -= refresh_row->height;
982 SetHeightOfRow(refresh_row);
984 refresh_row = firstrow;
986 SetHeightOfRow(refresh_row);
989 if (tmprow && tmprow->next)
990 SetHeightOfRow(tmprow->next);
994 bool LyXText::FullRebreak()
996 if (need_break_row) {
997 BreakAgain(need_break_row);
1005 /* important for the screen */
1008 /* the cursor set functions have a special mechanism. When they
1009 * realize, that you left an empty paragraph, they will delete it.
1010 * They also delet the corresponding row */
1012 // need the selection cursor:
1013 void LyXText::SetSelection()
1016 last_sel_cursor = sel_cursor;
1017 sel_start_cursor = sel_cursor;
1018 sel_end_cursor = sel_cursor;
1023 // first the toggling area
1024 if (cursor.y < last_sel_cursor.y ||
1025 (cursor.y == last_sel_cursor.y && cursor.x < last_sel_cursor.x)) {
1026 toggle_end_cursor = last_sel_cursor;
1027 toggle_cursor = cursor;
1030 toggle_end_cursor = cursor;
1031 toggle_cursor = last_sel_cursor;
1034 last_sel_cursor = cursor;
1036 // and now the whole selection
1038 if (sel_cursor.par == cursor.par)
1039 if (sel_cursor.pos < cursor.pos) {
1040 sel_end_cursor = cursor;
1041 sel_start_cursor = sel_cursor;
1043 sel_end_cursor = sel_cursor;
1044 sel_start_cursor = cursor;
1046 else if (sel_cursor.y < cursor.y ||
1047 (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
1048 sel_end_cursor = cursor;
1049 sel_start_cursor = sel_cursor;
1052 sel_end_cursor = sel_cursor;
1053 sel_start_cursor = cursor;
1056 // a selection with no contents is not a selection
1057 if (sel_start_cursor.x == sel_end_cursor.x &&
1058 sel_start_cursor.y == sel_end_cursor.y)
1063 void LyXText::ClearSelection() const
1070 void LyXText::CursorHome() const
1072 SetCursor(cursor.par, cursor.row->pos);
1076 void LyXText::CursorEnd() const
1078 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1079 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1081 if (cursor.par->Last() &&
1082 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1083 || cursor.par->IsNewline(RowLast(cursor.row))))
1084 SetCursor(cursor.par, RowLast(cursor.row));
1086 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1088 if (cursor.par->table) {
1089 int cell = NumberOfCell(cursor.par, cursor.pos);
1090 if (cursor.par->table->RowHasContRow(cell) &&
1091 cursor.par->table->CellHasContRow(cell)<0) {
1092 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1093 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1095 if (cursor.par->Last() &&
1096 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1097 || cursor.par->IsNewline(RowLast(cursor.row))))
1098 SetCursor(cursor.par, RowLast(cursor.row));
1100 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1107 void LyXText::CursorTop() const
1109 while (cursor.par->Previous())
1110 cursor.par = cursor.par->Previous();
1111 SetCursor(cursor.par, 0);
1115 void LyXText::CursorBottom() const
1117 while (cursor.par->Next())
1118 cursor.par = cursor.par->Next();
1119 SetCursor(cursor.par, cursor.par->Last());
1123 /* returns a pointer to the row near the specified y-coordinate
1124 * (relative to the whole text). y is set to the real beginning
1126 Row * LyXText::GetRowNearY(long & y) const
1128 Row * tmprow = firstrow;
1131 while (tmprow->next && tmpy + tmprow->height <= y) {
1132 tmpy += tmprow->height;
1133 tmprow = tmprow->next;
1136 y = tmpy; // return the real y
1141 void LyXText::ToggleFree(LyXFont const & font, bool toggleall)
1143 // If the mask is completely neutral, tell user
1144 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1145 // Could only happen with user style
1146 owner_->owner()->getMiniBuffer()
1147 ->Set(_("No font change defined. Use Character under"
1148 " the Layout menu to define font change."));
1152 // Try implicit word selection
1153 // If there is a change in the language the implicit word selection
1155 LyXCursor resetCursor = cursor;
1156 bool implicitSelection = (font.language() == ignore_language)
1157 ? SelectWordWhenUnderCursor() : false;
1160 SetFont(font, toggleall);
1162 /* Implicit selections are cleared afterwards and cursor is set to the
1163 original position. */
1164 if (implicitSelection) {
1166 cursor = resetCursor;
1167 SetCursor( cursor.par, cursor.pos );
1168 sel_cursor = cursor;
1173 LyXParagraph::size_type LyXText::BeginningOfMainBody(LyXParagraph * par) const
1175 if (textclasslist.Style(buffer->params.textclass,
1176 par->GetLayout()).labeltype != LABEL_MANUAL)
1179 return par->BeginningOfMainBody();
1183 /* if there is a selection, reset every environment you can find
1184 * in the selection, otherwise just the environment you are in */
1185 void LyXText::MeltFootnoteEnvironment()
1187 LyXParagraph * tmppar, * firsttmppar;
1191 /* is is only allowed, if the cursor is IN an open footnote.
1192 * Otherwise it is too dangerous */
1193 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1196 SetUndo(Undo::FINISH,
1197 cursor.par->PreviousBeforeFootnote()->previous,
1198 cursor.par->NextAfterFootnote()->next);
1200 /* ok, move to the beginning of the footnote. */
1201 while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1202 cursor.par = cursor.par->Previous();
1204 SetCursor(cursor.par, cursor.par->Last());
1205 /* this is just faster than using CursorLeft(); */
1207 firsttmppar = cursor.par->ParFromPos(cursor.pos);
1208 tmppar = firsttmppar;
1209 /* tmppar is now the paragraph right before the footnote */
1211 bool first_footnote_par_is_not_empty = tmppar->next->size();
1214 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1215 tmppar = tmppar->next; /* I use next instead of Next(),
1216 * because there cannot be any
1217 * footnotes in a footnote
1219 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1221 /* remember the captions and empty paragraphs */
1222 if ((textclasslist.Style(buffer->params.textclass,
1223 tmppar->GetLayout())
1224 .labeltype == LABEL_SENSITIVE)
1226 tmppar->SetLayout(0);
1229 // now we will paste the ex-footnote, if the layouts allow it
1230 // first restore the layout of the paragraph right behind
1233 tmppar->next->MakeSameLayout(cursor.par);
1236 if ((!tmppar->GetLayout() && !tmppar->table)
1238 && (!tmppar->Next()->Last()
1239 || tmppar->Next()->HasSameLayout(tmppar)))) {
1240 if (tmppar->Next()->Last()
1241 && tmppar->Next()->IsLineSeparator(0))
1242 tmppar->Next()->Erase(0);
1243 tmppar->PasteParagraph();
1246 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1247 * by the pasting of the beginning */
1249 /* then the beginning */
1250 /* if there is no space between the text and the footnote, so we insert
1252 * (only if the previous par and the footnotepar are not empty!) */
1253 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1254 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1255 if (firsttmppar->size()
1256 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1257 && first_footnote_par_is_not_empty) {
1258 firsttmppar->next->InsertChar(0, ' ');
1260 firsttmppar->PasteParagraph();
1263 /* now redo the paragaphs */
1264 RedoParagraphs(cursor, tmppar);
1266 SetCursor(cursor.par, cursor.pos);
1268 /* sometimes it can happen, that there is a counter change */
1269 Row * row = cursor.row;
1270 while (row->next && row->par != tmppar && row->next->par != tmppar)
1272 UpdateCounters(row);
1279 /* the DTP switches for paragraphs. LyX will store them in the
1280 * first physicla paragraph. When a paragraph is broken, the top settings
1281 * rest, the bottom settings are given to the new one. So I can make shure,
1282 * they do not duplicate themself and you cannnot make dirty things with
1285 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1286 bool pagebreak_top, bool pagebreak_bottom,
1287 VSpace const & space_top,
1288 VSpace const & space_bottom,
1290 string labelwidthstring,
1293 LyXCursor tmpcursor = cursor;
1295 sel_start_cursor = cursor;
1296 sel_end_cursor = cursor;
1299 // make sure that the depth behind the selection are restored, too
1300 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1301 LyXParagraph * undoendpar = endpar;
1303 if (endpar && endpar->GetDepth()) {
1304 while (endpar && endpar->GetDepth()) {
1305 endpar = endpar->LastPhysicalPar()->Next();
1306 undoendpar = endpar;
1310 endpar = endpar->Next(); // because of parindents etc.
1315 .par->ParFromPos(sel_start_cursor.pos)->previous,
1319 LyXParagraph * tmppar = sel_end_cursor.par;
1320 while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1321 SetCursor(tmppar->FirstPhysicalPar(), 0);
1322 status = LyXText::NEED_MORE_REFRESH;
1323 refresh_row = cursor.row;
1324 refresh_y = cursor.y - cursor.row->baseline;
1325 if (cursor.par->footnoteflag ==
1326 sel_start_cursor.par->footnoteflag) {
1327 cursor.par->line_top = line_top;
1328 cursor.par->line_bottom = line_bottom;
1329 cursor.par->pagebreak_top = pagebreak_top;
1330 cursor.par->pagebreak_bottom = pagebreak_bottom;
1331 cursor.par->added_space_top = space_top;
1332 cursor.par->added_space_bottom = space_bottom;
1333 // does the layout allow the new alignment?
1334 if (align == LYX_ALIGN_LAYOUT)
1335 align = textclasslist
1336 .Style(buffer->params.textclass,
1337 cursor.par->GetLayout()).align;
1338 if (align & textclasslist
1339 .Style(buffer->params.textclass,
1340 cursor.par->GetLayout()).alignpossible) {
1341 if (align == textclasslist
1342 .Style(buffer->params.textclass,
1343 cursor.par->GetLayout()).align)
1344 cursor.par->align = LYX_ALIGN_LAYOUT;
1346 cursor.par->align = align;
1348 cursor.par->SetLabelWidthString(labelwidthstring);
1349 cursor.par->noindent = noindent;
1352 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1355 RedoParagraphs(sel_start_cursor, endpar);
1358 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1359 sel_cursor = cursor;
1360 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1362 SetCursor(tmpcursor.par, tmpcursor.pos);
1366 void LyXText::SetParagraphExtraOpt(int type,
1368 char const * widthp,
1369 int alignment, bool hfill,
1370 bool start_minipage)
1372 LyXCursor tmpcursor = cursor;
1373 LyXParagraph * tmppar;
1375 sel_start_cursor = cursor;
1376 sel_end_cursor = cursor;
1379 // make sure that the depth behind the selection are restored, too
1380 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1381 LyXParagraph * undoendpar = endpar;
1383 if (endpar && endpar->GetDepth()) {
1384 while (endpar && endpar->GetDepth()) {
1385 endpar = endpar->LastPhysicalPar()->Next();
1386 undoendpar = endpar;
1390 endpar = endpar->Next(); // because of parindents etc.
1395 .par->ParFromPos(sel_start_cursor.pos)->previous,
1398 tmppar = sel_end_cursor.par;
1399 while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1400 SetCursor(tmppar->FirstPhysicalPar(), 0);
1401 status = LyXText::NEED_MORE_REFRESH;
1402 refresh_row = cursor.row;
1403 refresh_y = cursor.y - cursor.row->baseline;
1404 if (cursor.par->footnoteflag ==
1405 sel_start_cursor.par->footnoteflag) {
1406 if (type == LyXParagraph::PEXTRA_NONE) {
1407 if (cursor.par->pextra_type != LyXParagraph::PEXTRA_NONE) {
1408 cursor.par->UnsetPExtraType();
1409 cursor.par->pextra_type = LyXParagraph::PEXTRA_NONE;
1412 cursor.par->SetPExtraType(type, width, widthp);
1413 cursor.par->pextra_hfill = hfill;
1414 cursor.par->pextra_start_minipage = start_minipage;
1415 cursor.par->pextra_alignment = alignment;
1418 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1420 RedoParagraphs(sel_start_cursor, endpar);
1422 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1423 sel_cursor = cursor;
1424 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1426 SetCursor(tmpcursor.par, tmpcursor.pos);
1430 char loweralphaCounter(int n)
1432 if (n < 1 || n > 26)
1438 char alphaCounter(int n)
1440 if (n < 1 || n > 26)
1446 char hebrewCounter(int n)
1448 static const char hebrew[22] = {
1449 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1450 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1451 '÷', 'ø', 'ù', 'ú'
1453 if (n < 1 || n > 22)
1459 static char const * romanCounter(int n)
1461 static char const * roman[20] = {
1462 "i", "ii", "iii", "iv", "v",
1463 "vi", "vii", "viii", "ix", "x",
1464 "xi", "xii", "xiii", "xiv", "xv",
1465 "xvi", "xvii", "xviii", "xix", "xx"
1467 if (n < 1 || n > 20)
1473 // set the counter of a paragraph. This includes the labels
1474 void LyXText::SetCounter(LyXParagraph * par) const
1476 // this is only relevant for the beginning of paragraph
1477 par = par->FirstPhysicalPar();
1479 LyXLayout const & layout =
1480 textclasslist.Style(buffer->params.textclass,
1483 LyXTextClass const & textclass =
1484 textclasslist.TextClass(buffer->params.textclass);
1486 /* copy the prev-counters to this one, unless this is the start of a
1487 footnote or of a bibliography or the very first paragraph */
1489 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1490 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1491 && par->footnotekind == LyXParagraph::FOOTNOTE)
1492 && !(textclasslist.Style(buffer->params.textclass,
1493 par->Previous()->GetLayout()
1494 ).labeltype != LABEL_BIBLIO
1495 && layout.labeltype == LABEL_BIBLIO)) {
1496 for (int i = 0; i < 10; ++i) {
1497 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1499 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1500 if (!par->appendix && par->start_of_appendix){
1501 par->appendix = true;
1502 for (int i = 0; i < 10; ++i) {
1503 par->setCounter(i, 0);
1506 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1507 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1510 for (int i = 0; i < 10; ++i) {
1511 par->setCounter(i, 0);
1513 par->appendix = par->start_of_appendix;
1518 // if this is an open marginnote and this is the first
1519 // entry in the marginnote and the enclosing
1520 // environment is an enum/item then correct for the
1521 // LaTeX behaviour (ARRae)
1522 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1523 && par->footnotekind == LyXParagraph::MARGIN
1525 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1526 && (par->PreviousBeforeFootnote()
1527 && textclasslist.Style(buffer->params.textclass,
1528 par->PreviousBeforeFootnote()->GetLayout()
1529 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1530 // Any itemize or enumerate environment in a marginnote
1531 // that is embedded in an itemize or enumerate
1532 // paragraph is seen by LaTeX as being at a deeper
1533 // level within that enclosing itemization/enumeration
1534 // even if there is a "standard" layout at the start of
1540 /* Maybe we have to increment the enumeration depth.
1541 * BUT, enumeration in a footnote is considered in isolation from its
1542 * surrounding paragraph so don't increment if this is the
1543 * first line of the footnote
1544 * AND, bibliographies can't have their depth changed ie. they
1545 * are always of depth 0
1548 && par->Previous()->GetDepth() < par->GetDepth()
1549 && textclasslist.Style(buffer->params.textclass,
1550 par->Previous()->GetLayout()
1551 ).labeltype == LABEL_COUNTER_ENUMI
1552 && par->enumdepth < 3
1553 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1554 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1555 && par->footnotekind == LyXParagraph::FOOTNOTE)
1556 && layout.labeltype != LABEL_BIBLIO) {
1560 /* Maybe we have to decrement the enumeration depth, see note above */
1562 && par->Previous()->GetDepth() > par->GetDepth()
1563 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1564 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1565 && par->footnotekind == LyXParagraph::FOOTNOTE)
1566 && layout.labeltype != LABEL_BIBLIO) {
1567 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1568 par->setCounter(6 + par->enumdepth,
1569 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1570 /* reset the counters.
1571 * A depth change is like a breaking layout
1573 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1574 par->setCounter(i, 0);
1577 if (!par->labelstring.empty()) {
1578 par->labelstring.erase();
1581 if (layout.margintype == MARGIN_MANUAL) {
1582 if (par->labelwidthstring.empty()) {
1583 par->SetLabelWidthString(layout.labelstring());
1586 par->SetLabelWidthString(string());
1589 /* is it a layout that has an automatic label ? */
1590 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1592 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1593 if (i >= 0 && i<= buffer->params.secnumdepth) {
1594 par->incCounter(i); // increment the counter
1596 // Is there a label? Useful for Chapter layout
1597 if (!par->appendix){
1598 if (!layout.labelstring().empty())
1599 par->labelstring = layout.labelstring();
1601 par->labelstring.erase();
1603 if (!layout.labelstring_appendix().empty())
1604 par->labelstring = layout.labelstring_appendix();
1606 par->labelstring.erase();
1610 std::ostringstream s;
1614 if (!par->appendix) {
1615 switch (2 * LABEL_FIRST_COUNTER -
1616 textclass.maxcounter() + i) {
1617 case LABEL_COUNTER_CHAPTER:
1618 s << par->getCounter(i);
1620 case LABEL_COUNTER_SECTION:
1621 s << par->getCounter(i - 1) << '.'
1622 << par->getCounter(i);
1624 case LABEL_COUNTER_SUBSECTION:
1625 s << par->getCounter(i - 2) << '.'
1626 << par->getCounter(i - 1) << '.'
1627 << par->getCounter(i);
1629 case LABEL_COUNTER_SUBSUBSECTION:
1630 s << par->getCounter(i - 3) << '.'
1631 << par->getCounter(i - 2) << '.'
1632 << par->getCounter(i - 1) << '.'
1633 << par->getCounter(i);
1636 case LABEL_COUNTER_PARAGRAPH:
1637 s << par->getCounter(i - 4) << '.'
1638 << par->getCounter(i - 3) << '.'
1639 << par->getCounter(i - 2) << '.'
1640 << par->getCounter(i - 1) << '.'
1641 << par->getCounter(i);
1643 case LABEL_COUNTER_SUBPARAGRAPH:
1644 s << par->getCounter(i - 5) << '.'
1645 << par->getCounter(i - 4) << '.'
1646 << par->getCounter(i - 3) << '.'
1647 << par->getCounter(i - 2) << '.'
1648 << par->getCounter(i - 1) << '.'
1649 << par->getCounter(i);
1653 s << par->getCounter(i) << '.';
1656 } else { // appendix
1657 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1658 case LABEL_COUNTER_CHAPTER:
1659 if (par->isRightToLeftPar())
1660 s << hebrewCounter(par->getCounter(i));
1662 s << alphaCounter(par->getCounter(i));
1664 case LABEL_COUNTER_SECTION:
1665 if (par->isRightToLeftPar())
1666 s << hebrewCounter(par->getCounter(i - 1));
1668 s << alphaCounter(par->getCounter(i - 1));
1671 << par->getCounter(i);
1674 case LABEL_COUNTER_SUBSECTION:
1675 if (par->isRightToLeftPar())
1676 s << hebrewCounter(par->getCounter(i - 2));
1678 s << alphaCounter(par->getCounter(i - 2));
1681 << par->getCounter(i-1) << '.'
1682 << par->getCounter(i);
1685 case LABEL_COUNTER_SUBSUBSECTION:
1686 if (par->isRightToLeftPar())
1687 s << hebrewCounter(par->getCounter(i-3));
1689 s << alphaCounter(par->getCounter(i-3));
1692 << par->getCounter(i-2) << '.'
1693 << par->getCounter(i-1) << '.'
1694 << par->getCounter(i);
1697 case LABEL_COUNTER_PARAGRAPH:
1698 if (par->isRightToLeftPar())
1699 s << hebrewCounter(par->getCounter(i-4));
1701 s << alphaCounter(par->getCounter(i-4));
1704 << par->getCounter(i-3) << '.'
1705 << par->getCounter(i-2) << '.'
1706 << par->getCounter(i-1) << '.'
1707 << par->getCounter(i);
1710 case LABEL_COUNTER_SUBPARAGRAPH:
1711 if (par->isRightToLeftPar())
1712 s << hebrewCounter(par->getCounter(i-5));
1714 s << alphaCounter(par->getCounter(i-5));
1717 << par->getCounter(i-4) << '.'
1718 << par->getCounter(i-3) << '.'
1719 << par->getCounter(i-2) << '.'
1720 << par->getCounter(i-1) << '.'
1721 << par->getCounter(i);
1725 // Can this ever be reached? And in the
1726 // case it is, how can this be correct?
1728 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1734 par->labelstring += s.str().c_str();
1735 // We really want to remove the c_str as soon as
1739 char * tmps = s.str();
1740 par->labelstring += tmps;
1744 for (i++; i < 10; ++i) {
1745 // reset the following counters
1746 par->setCounter(i, 0);
1748 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1749 for (i++; i < 10; ++i) {
1750 // reset the following counters
1751 par->setCounter(i, 0);
1753 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1754 par->incCounter(i + par->enumdepth);
1755 int number = par->getCounter(i + par->enumdepth);
1758 std::ostringstream s;
1762 switch (par->enumdepth) {
1764 if (par->isRightToLeftPar())
1766 << hebrewCounter(number)
1770 << loweralphaCounter(number)
1774 if (par->isRightToLeftPar())
1775 s << '.' << romanCounter(number);
1777 s << romanCounter(number) << '.';
1780 if (par->isRightToLeftPar())
1782 << alphaCounter(number);
1784 s << alphaCounter(number)
1788 if (par->isRightToLeftPar())
1795 par->labelstring = s.str().c_str();
1796 // we really want to get rid of that c_str()
1799 char * tmps = s.str();
1800 par->labelstring = tmps;
1804 for (i += par->enumdepth + 1; i < 10; ++i)
1805 par->setCounter(i, 0); /* reset the following counters */
1808 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1809 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1811 int number = par->getCounter(i);
1813 par->bibkey = new InsetBibKey();
1814 par->bibkey->setCounter(number);
1815 par->labelstring = layout.labelstring();
1817 // In biblio should't be following counters but...
1819 string s = layout.labelstring();
1821 // the caption hack:
1823 if (layout.labeltype == LABEL_SENSITIVE) {
1824 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1825 && (par->footnotekind == LyXParagraph::FIG
1826 || par->footnotekind == LyXParagraph::WIDE_FIG))
1827 s = (par->getParLanguage()->lang == "hebrew")
1828 ? ":øåéà " : "Figure:";
1829 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1830 && (par->footnotekind == LyXParagraph::TAB
1831 || par->footnotekind == LyXParagraph::WIDE_TAB))
1832 s = (par->getParLanguage()->lang == "hebrew")
1833 ? ":äìáè" : "Table:";
1834 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1835 && par->footnotekind == LyXParagraph::ALGORITHM)
1836 s = (par->getParLanguage()->lang == "hebrew")
1837 ? ":Ãúéøåâìà " : "Algorithm:";
1839 /* par->SetLayout(0);
1840 s = layout->labelstring; */
1841 s = (par->getParLanguage()->lang == "hebrew")
1842 ? " :úåòîùî øñç" : "Senseless: ";
1845 par->labelstring = s;
1847 /* reset the enumeration counter. They are always resetted
1848 * when there is any other layout between */
1849 for (int i = 6 + par->enumdepth; i < 10; ++i)
1850 par->setCounter(i, 0);
1855 /* Updates all counters BEHIND the row. Changed paragraphs
1856 * with a dynamic left margin will be rebroken. */
1857 void LyXText::UpdateCounters(Row * row) const
1866 && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1867 par = row->par->LastPhysicalPar()->Next();
1869 par = row->par->next;
1874 while (row->par != par)
1879 /* now check for the headline layouts. remember that they
1880 * have a dynamic left margin */
1882 && ( textclasslist.Style(buffer->params.textclass,
1883 par->layout).margintype == MARGIN_DYNAMIC
1884 || textclasslist.Style(buffer->params.textclass,
1885 par->layout).labeltype == LABEL_SENSITIVE)
1888 /* Rebreak the paragraph */
1889 RemoveParagraph(row);
1890 AppendParagraph(row);
1892 /* think about the damned open footnotes! */
1893 while (par->Next() &&
1894 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1895 || par->Next()->IsDummy())){
1897 if (par->IsDummy()) {
1898 while (row->par != par)
1900 RemoveParagraph(row);
1901 AppendParagraph(row);
1906 par = par->LastPhysicalPar()->Next();
1912 /* insets an inset. */
1913 void LyXText::InsertInset(Inset *inset)
1915 if (!cursor.par->InsertInsetAllowed(inset))
1917 SetUndo(Undo::INSERT,
1918 cursor.par->ParFromPos(cursor.pos)->previous,
1919 cursor.par->ParFromPos(cursor.pos)->next);
1920 cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1921 cursor.par->InsertInset(cursor.pos, inset);
1922 InsertChar(LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
1923 * The character will not be inserted a
1928 #ifdef USE_OLD_CUT_AND_PASTE
1929 // this is for the simple cut and paste mechanism
1930 static LyXParagraph * simple_cut_buffer = 0;
1931 static char simple_cut_buffer_textclass = 0;
1933 void DeleteSimpleCutBuffer()
1935 if (!simple_cut_buffer)
1937 LyXParagraph * tmppar;
1939 while (simple_cut_buffer) {
1940 tmppar = simple_cut_buffer;
1941 simple_cut_buffer = simple_cut_buffer->next;
1944 simple_cut_buffer = 0;
1948 void LyXText::copyEnvironmentType()
1950 copylayouttype = cursor.par->GetLayout();
1954 void LyXText::pasteEnvironmentType()
1956 SetLayout(copylayouttype);
1959 #ifdef USE_OLD_CUT_AND_PASTE
1960 void LyXText::CutSelection(bool doclear)
1962 // This doesn't make sense, if there is no selection
1966 // OK, we have a selection. This is always between sel_start_cursor
1967 // and sel_end cursor
1968 LyXParagraph * tmppar;
1970 // Check whether there are half footnotes in the selection
1971 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1972 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1973 tmppar = sel_start_cursor.par;
1974 while (tmppar != sel_end_cursor.par){
1975 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
1976 WriteAlert(_("Impossible operation"),
1977 _("Don't know what to do with half floats."),
1981 tmppar = tmppar->Next();
1985 /* table stuff -- begin */
1986 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
1987 if ( sel_start_cursor.par != sel_end_cursor.par) {
1988 WriteAlert(_("Impossible operation"),
1989 _("Don't know what to do with half tables."),
1993 sel_start_cursor.par->table->Reinit();
1995 /* table stuff -- end */
1997 // make sure that the depth behind the selection are restored, too
1998 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1999 LyXParagraph * undoendpar = endpar;
2001 if (endpar && endpar->GetDepth()) {
2002 while (endpar && endpar->GetDepth()) {
2003 endpar = endpar->LastPhysicalPar()->Next();
2004 undoendpar = endpar;
2006 } else if (endpar) {
2007 endpar = endpar->Next(); // because of parindents etc.
2010 SetUndo(Undo::DELETE,
2012 .par->ParFromPos(sel_start_cursor.pos)->previous,
2015 // clear the simple_cut_buffer
2016 DeleteSimpleCutBuffer();
2018 // set the textclass
2019 simple_cut_buffer_textclass = buffer->params.textclass;
2021 #ifdef WITH_WARNINGS
2022 #warning Asger: Make cut more intelligent here.
2025 White paper for "intelligent" cutting:
2027 Example: "This is our text."
2028 Using " our " as selection, cutting will give "This istext.".
2029 Using "our" as selection, cutting will give "This is text.".
2030 Using " our" as selection, cutting will give "This is text.".
2031 Using "our " as selection, cutting will give "This is text.".
2033 All those four selections will (however) paste identically:
2034 Pasting with the cursor right after the "is" will give the
2035 original text with all four selections.
2037 The rationale is to be intelligent such that words are copied,
2038 cut and pasted in a functional manner.
2040 This is not implemented yet. (Asger)
2042 The changes below sees to do a lot of what you want. However
2043 I have not verified that all cases work as they should:
2045 - cut in multiple row
2047 - cut across footnotes and paragraph
2048 My simplistic tests show that the idea are basically sound but
2049 there are some items to fix up...we only need to find them
2052 As do redo Asger's example above (with | beeing the cursor in the
2053 result after cutting.):
2055 Example: "This is our text."
2056 Using " our " as selection, cutting will give "This is|text.".
2057 Using "our" as selection, cutting will give "This is | text.".
2058 Using " our" as selection, cutting will give "This is| text.".
2059 Using "our " as selection, cutting will give "This is |text.".
2064 // there are two cases: cut only within one paragraph or
2065 // more than one paragraph
2067 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2068 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2069 // only within one paragraph
2070 simple_cut_buffer = new LyXParagraph;
2071 LyXParagraph::size_type i =
2072 sel_start_cursor.pos;
2073 for (; i < sel_end_cursor.pos; ++i) {
2074 /* table stuff -- begin */
2075 if (sel_start_cursor.par->table
2076 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)) {
2077 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2078 sel_start_cursor.pos++;
2080 /* table stuff -- end */
2081 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2082 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2084 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
2086 endpar = sel_end_cursor.par->Next();
2088 // cut more than one paragraph
2091 ->BreakParagraphConservative(sel_end_cursor.pos);
2092 sel_end_cursor.par = sel_end_cursor.par->Next();
2093 sel_end_cursor.pos = 0;
2095 cursor = sel_end_cursor;
2097 sel_start_cursor.par
2098 ->BreakParagraphConservative(sel_start_cursor.pos);
2099 // store the endparagraph for redoing later
2100 endpar = sel_end_cursor.par->Next(); /* needed because
2105 // store the selection
2106 simple_cut_buffer = sel_start_cursor.par
2107 ->ParFromPos(sel_start_cursor.pos)->next;
2108 simple_cut_buffer->previous = 0;
2109 sel_end_cursor.par->previous->next = 0;
2111 // cut the selection
2112 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
2113 = sel_end_cursor.par;
2115 sel_end_cursor.par->previous
2116 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2118 // care about footnotes
2119 if (simple_cut_buffer->footnoteflag) {
2120 LyXParagraph * tmppar = simple_cut_buffer;
2122 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2123 tmppar = tmppar->next;
2127 // the cut selection should begin with standard layout
2128 simple_cut_buffer->Clear();
2130 // paste the paragraphs again, if possible
2132 sel_start_cursor.par->Next()->ClearParagraph();
2133 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
2135 !sel_start_cursor.par->Next()->Last())
2136 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
2139 // sometimes necessary
2141 sel_start_cursor.par->ClearParagraph();
2143 RedoParagraphs(sel_start_cursor, endpar);
2146 cursor = sel_start_cursor;
2147 SetCursor(cursor.par, cursor.pos);
2148 sel_cursor = cursor;
2149 UpdateCounters(cursor.row);
2152 #else ///////////////////////////////////////////////////////////////////
2154 void LyXText::CutSelection(bool doclear)
2156 // This doesn't make sense, if there is no selection
2160 // OK, we have a selection. This is always between sel_start_cursor
2161 // and sel_end cursor
2162 LyXParagraph * tmppar;
2164 // Check whether there are half footnotes in the selection
2165 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2166 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2167 tmppar = sel_start_cursor.par;
2168 while (tmppar != sel_end_cursor.par){
2169 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
2170 WriteAlert(_("Impossible operation"),
2171 _("Don't know what to do with half floats."),
2175 tmppar = tmppar->Next();
2179 /* table stuff -- begin */
2180 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
2181 if ( sel_start_cursor.par != sel_end_cursor.par) {
2182 WriteAlert(_("Impossible operation"),
2183 _("Don't know what to do with half tables."),
2187 sel_start_cursor.par->table->Reinit();
2189 /* table stuff -- end */
2191 // make sure that the depth behind the selection are restored, too
2192 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
2193 LyXParagraph * undoendpar = endpar;
2195 if (endpar && endpar->GetDepth()) {
2196 while (endpar && endpar->GetDepth()) {
2197 endpar = endpar->LastPhysicalPar()->Next();
2198 undoendpar = endpar;
2200 } else if (endpar) {
2201 endpar = endpar->Next(); // because of parindents etc.
2204 SetUndo(Undo::DELETE, sel_start_cursor
2205 .par->ParFromPos(sel_start_cursor.pos)->previous, undoendpar);
2209 // there are two cases: cut only within one paragraph or
2210 // more than one paragraph
2211 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2212 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2213 // only within one paragraph
2214 endpar = sel_start_cursor.par;
2215 cap.cutSelection(sel_start_cursor.par, &endpar,
2216 sel_start_cursor.pos, sel_end_cursor.pos,
2217 buffer->params.textclass, doclear);
2219 endpar = sel_end_cursor.par;
2221 cap.cutSelection(sel_start_cursor.par, &endpar,
2222 sel_start_cursor.pos, sel_end_cursor.pos,
2223 buffer->params.textclass, doclear);
2224 cursor.par = sel_end_cursor.par = endpar;
2225 cursor.pos = sel_end_cursor.pos;
2227 endpar = endpar->Next();
2229 // sometimes necessary
2231 sel_start_cursor.par->ClearParagraph();
2233 RedoParagraphs(sel_start_cursor, endpar);
2236 cursor = sel_start_cursor;
2237 SetCursor(cursor.par, cursor.pos);
2238 sel_cursor = cursor;
2239 UpdateCounters(cursor.row);
2243 #ifdef USE_OLD_CUT_AND_PASTE
2244 void LyXText::CopySelection()
2246 // this doesnt make sense, if there is no selection
2250 // ok we have a selection. This is always between sel_start_cursor
2251 // and sel_end cursor
2252 LyXParagraph * tmppar;
2254 /* check wether there are half footnotes in the selection */
2255 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2256 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2257 tmppar = sel_start_cursor.par;
2258 while (tmppar != sel_end_cursor.par) {
2259 if (tmppar->footnoteflag !=
2260 sel_end_cursor.par->footnoteflag) {
2261 WriteAlert(_("Impossible operation"),
2262 _("Don't know what to do"
2263 " with half floats."),
2267 tmppar = tmppar->Next();
2271 /* table stuff -- begin */
2272 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2273 if ( sel_start_cursor.par != sel_end_cursor.par){
2274 WriteAlert(_("Impossible operation"),
2275 _("Don't know what to do with half tables."),
2280 /* table stuff -- end */
2282 // delete the simple_cut_buffer
2283 DeleteSimpleCutBuffer();
2285 // set the textclass
2286 simple_cut_buffer_textclass = buffer->params.textclass;
2288 // copy behind a space if there is one
2289 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2290 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2291 && (sel_start_cursor.par != sel_end_cursor.par
2292 || sel_start_cursor.pos < sel_end_cursor.pos))
2293 sel_start_cursor.pos++;
2295 // there are two cases: copy only within one paragraph
2296 // or more than one paragraph
2297 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2298 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2299 // only within one paragraph
2300 simple_cut_buffer = new LyXParagraph;
2301 LyXParagraph::size_type i = 0;
2302 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2303 sel_start_cursor.par->CopyIntoMinibuffer(i);
2304 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2307 // copy more than one paragraph
2308 // clone the paragraphs within the selection
2310 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2311 simple_cut_buffer = tmppar->Clone();
2312 LyXParagraph *tmppar2 = simple_cut_buffer;
2314 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2316 tmppar = tmppar->next;
2317 tmppar2->next = tmppar->Clone();
2318 tmppar2->next->previous = tmppar2;
2319 tmppar2 = tmppar2->next;
2323 // care about footnotes
2324 if (simple_cut_buffer->footnoteflag) {
2325 tmppar = simple_cut_buffer;
2327 tmppar->footnoteflag =
2328 LyXParagraph::NO_FOOTNOTE;
2329 tmppar = tmppar->next;
2333 // the simple_cut_buffer paragraph is too big
2334 LyXParagraph::size_type tmpi2 =
2335 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2336 for (; tmpi2; --tmpi2)
2337 simple_cut_buffer->Erase(0);
2339 // now tmppar 2 is too big, delete all after sel_end_cursor.pos
2341 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2342 while (tmppar2->size() > tmpi2) {
2343 tmppar2->Erase(tmppar2->size() - 1);
2348 #else //////////////////////////////////////////////////////////////////////
2350 void LyXText::CopySelection()
2352 // this doesnt make sense, if there is no selection
2356 // ok we have a selection. This is always between sel_start_cursor
2357 // and sel_end cursor
2358 LyXParagraph * tmppar;
2360 /* check wether there are half footnotes in the selection */
2361 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2362 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2363 tmppar = sel_start_cursor.par;
2364 while (tmppar != sel_end_cursor.par) {
2365 if (tmppar->footnoteflag !=
2366 sel_end_cursor.par->footnoteflag) {
2367 WriteAlert(_("Impossible operation"),
2368 _("Don't know what to do"
2369 " with half floats."),
2373 tmppar = tmppar->Next();
2377 /* table stuff -- begin */
2378 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2379 if ( sel_start_cursor.par != sel_end_cursor.par){
2380 WriteAlert(_("Impossible operation"),
2381 _("Don't know what to do with half tables."),
2386 /* table stuff -- end */
2388 // copy behind a space if there is one
2389 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2390 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2391 && (sel_start_cursor.par != sel_end_cursor.par
2392 || sel_start_cursor.pos < sel_end_cursor.pos))
2393 sel_start_cursor.pos++;
2397 cap.copySelection(sel_start_cursor.par, sel_end_cursor.par,
2398 sel_start_cursor.pos, sel_end_cursor.pos,
2399 buffer->params.textclass);
2403 #ifdef USE_OLD_CUT_AND_PASTE
2404 void LyXText::PasteSelection()
2406 // this does not make sense, if there is nothing to paste
2407 if (!simple_cut_buffer)
2410 LyXParagraph * tmppar;
2411 LyXParagraph * endpar;
2413 LyXCursor tmpcursor;
2415 // be carefull with footnotes in footnotes
2416 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2418 // check whether the cut_buffer includes a footnote
2419 tmppar = simple_cut_buffer;
2421 && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2422 tmppar = tmppar->next;
2425 WriteAlert(_("Impossible operation"),
2426 _("Can't paste float into float!"),
2432 /* table stuff -- begin */
2433 if (cursor.par->table) {
2434 if (simple_cut_buffer->next) {
2435 WriteAlert(_("Impossible operation"),
2436 _("Table cell cannot include more than one paragraph!"),
2441 /* table stuff -- end */
2443 SetUndo(Undo::INSERT,
2444 cursor.par->ParFromPos(cursor.pos)->previous,
2445 cursor.par->ParFromPos(cursor.pos)->next);
2449 // There are two cases: cutbuffer only one paragraph or many
2450 if (!simple_cut_buffer->next) {
2451 // only within a paragraph
2453 tmppar = simple_cut_buffer->Clone();
2454 /* table stuff -- begin */
2455 bool table_too_small = false;
2456 if (tmpcursor.par->table) {
2457 while (simple_cut_buffer->size()
2458 && !table_too_small) {
2459 if (simple_cut_buffer->IsNewline(0)){
2460 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2462 simple_cut_buffer->Erase(0);
2463 if (tmpcursor.pos < tmpcursor.par->Last())
2466 table_too_small = true;
2468 // This is an attempt to fix the
2469 // "never insert a space at the
2470 // beginning of a paragraph" problem.
2471 if (tmpcursor.pos == 0
2472 && simple_cut_buffer->IsLineSeparator(0)) {
2473 simple_cut_buffer->Erase(0);
2475 simple_cut_buffer->CutIntoMinibuffer(0);
2476 simple_cut_buffer->Erase(0);
2477 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2483 /* table stuff -- end */
2484 // Some provisions should be done here for checking
2485 // if we are inserting at the beginning of a
2486 // paragraph. If there are a space at the beginning
2487 // of the text to insert and we are inserting at
2488 // the beginning of the paragraph the space should
2490 while (simple_cut_buffer->size()) {
2491 // This is an attempt to fix the
2492 // "never insert a space at the
2493 // beginning of a paragraph" problem.
2494 if (tmpcursor.pos == 0
2495 && simple_cut_buffer->IsLineSeparator(0)) {
2496 simple_cut_buffer->Erase(0);
2498 simple_cut_buffer->CutIntoMinibuffer(0);
2499 simple_cut_buffer->Erase(0);
2500 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2505 delete simple_cut_buffer;
2506 simple_cut_buffer = tmppar;
2507 endpar = tmpcursor.par->Next();
2512 // make a copy of the simple cut_buffer
2513 tmppar = simple_cut_buffer;
2514 LyXParagraph * simple_cut_clone = tmppar->Clone();
2515 LyXParagraph * tmppar2 = simple_cut_clone;
2516 if (cursor.par->footnoteflag){
2517 tmppar->footnoteflag = cursor.par->footnoteflag;
2518 tmppar->footnotekind = cursor.par->footnotekind;
2520 while (tmppar->next) {
2521 tmppar = tmppar->next;
2522 tmppar2->next = tmppar->Clone();
2523 tmppar2->next->previous = tmppar2;
2524 tmppar2 = tmppar2->next;
2525 if (cursor.par->footnoteflag){
2526 tmppar->footnoteflag = cursor.par->footnoteflag;
2527 tmppar->footnotekind = cursor.par->footnotekind;
2531 // make sure there is no class difference
2532 cap.SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2533 buffer->params.textclass,
2536 // make the simple_cut_buffer exactly the same layout than
2537 // the cursor paragraph
2538 simple_cut_buffer->MakeSameLayout(cursor.par);
2540 // find the end of the buffer
2541 LyXParagraph * lastbuffer = simple_cut_buffer;
2542 while (lastbuffer->Next())
2543 lastbuffer = lastbuffer->Next();
2545 bool paste_the_end = false;
2547 // open the paragraph for inserting the simple_cut_buffer
2549 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2550 cursor.par->BreakParagraphConservative(cursor.pos);
2551 paste_the_end = true;
2554 // set the end for redoing later
2555 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2558 lastbuffer->ParFromPos(lastbuffer->Last())->next =
2559 cursor.par->ParFromPos(cursor.pos)->next;
2560 cursor.par->ParFromPos(cursor.pos)->next->previous =
2561 lastbuffer->ParFromPos(lastbuffer->Last());
2563 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2564 simple_cut_buffer->previous =
2565 cursor.par->ParFromPos(cursor.pos);
2567 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2568 lastbuffer = cursor.par;
2570 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2572 // store the new cursor position
2573 tmpcursor.par = lastbuffer;
2574 tmpcursor.pos = lastbuffer->Last();
2576 // maybe some pasting
2577 if (lastbuffer->Next() && paste_the_end) {
2578 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2579 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2581 } else if (!lastbuffer->Next()->Last()) {
2582 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2583 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2585 } else if (!lastbuffer->Last()) {
2586 lastbuffer->MakeSameLayout(lastbuffer->next);
2587 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2590 lastbuffer->Next()->ClearParagraph();
2593 // restore the simple cut buffer
2594 simple_cut_buffer = simple_cut_clone;
2597 RedoParagraphs(cursor, endpar);
2599 SetCursor(cursor.par, cursor.pos);
2602 sel_cursor = cursor;
2603 SetCursor(tmpcursor.par, tmpcursor.pos);
2605 UpdateCounters(cursor.row);
2608 #else ////////////////////////////////////////////////////////////////////
2610 void LyXText::PasteSelection()
2614 // this does not make sense, if there is nothing to paste
2615 if (!cap.checkPastePossible(cursor.par, cursor.pos))
2618 SetUndo(Undo::INSERT,
2619 cursor.par->ParFromPos(cursor.pos)->previous,
2620 cursor.par->ParFromPos(cursor.pos)->next);
2622 LyXParagraph *endpar;
2623 LyXParagraph *actpar = cursor.par;
2624 int endpos = cursor.pos;
2626 cap.pasteSelection(&actpar, &endpar, endpos, buffer->params.textclass);
2628 RedoParagraphs(cursor, endpar);
2630 SetCursor(cursor.par, cursor.pos);
2633 sel_cursor = cursor;
2634 SetCursor(actpar, endpos);
2636 UpdateCounters(cursor.row);
2640 // returns a pointer to the very first LyXParagraph
2641 LyXParagraph * LyXText::FirstParagraph() const
2643 return buffer->paragraph;
2647 // returns true if the specified string is at the specified position
2648 bool LyXText::IsStringInText(LyXParagraph * par,
2649 LyXParagraph::size_type pos,
2650 char const * str) const
2654 while (pos + i < par->Last() && str[i] &&
2655 str[i] == par->GetChar(pos + i)) {
2665 // sets the selection over the number of characters of string, no check!!
2666 void LyXText::SetSelectionOverString(char const * string)
2668 sel_cursor = cursor;
2669 for (int i = 0; string[i]; ++i)
2675 // simple replacing. The font of the first selected character is used
2676 void LyXText::ReplaceSelectionWithString(char const * str)
2681 if (!selection) { // create a dummy selection
2682 sel_end_cursor = cursor;
2683 sel_start_cursor = cursor;
2686 // Get font setting before we cut
2687 LyXParagraph::size_type pos = sel_end_cursor.pos;
2688 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2690 // Insert the new string
2691 for (int i = 0; str[i]; ++i) {
2692 sel_end_cursor.par->InsertChar(pos, str[i]);
2693 sel_end_cursor.par->SetFont(pos, font);
2697 // Cut the selection
2704 // if the string can be found: return true and set the cursor to
2706 bool LyXText::SearchForward(char const * str) const
2708 LyXParagraph * par = cursor.par;
2709 LyXParagraph::size_type pos = cursor.pos;
2710 while (par && !IsStringInText(par, pos, str)) {
2711 if (pos < par->Last() - 1)
2719 SetCursor(par, pos);
2727 bool LyXText::SearchBackward(char const * string) const
2729 LyXParagraph * par = cursor.par;
2730 int pos = cursor.pos;
2736 // We skip empty paragraphs (Asger)
2738 par = par->Previous();
2740 pos = par->Last() - 1;
2741 } while (par && pos < 0);
2743 } while (par && !IsStringInText(par, pos, string));
2746 SetCursor(par, pos);
2753 // needed to insert the selection
2754 void LyXText::InsertStringA(string const & str)
2756 LyXParagraph * par = cursor.par;
2757 LyXParagraph::size_type pos = cursor.pos;
2758 LyXParagraph::size_type a = 0;
2760 LyXParagraph * endpar = cursor.par->Next();
2765 textclasslist.Style(buffer->params.textclass,
2766 cursor.par->GetLayout()).isEnvironment();
2767 // only to be sure, should not be neccessary
2770 // insert the string, don't insert doublespace
2771 string::size_type i = 0;
2772 while (i < str.length()) {
2773 if (str[i] != '\n') {
2775 && i + 1 < str.length() && str[i + 1] != ' '
2776 && pos && par->GetChar(pos - 1)!= ' ') {
2777 par->InsertChar(pos,' ');
2778 par->SetFont(pos, current_font);
2780 } else if (par->table) {
2781 if (str[i] == '\t') {
2782 while((pos < par->size()) &&
2783 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2785 if (pos < par->size())
2787 else // no more fields to fill skip the rest
2789 } else if ((str[i] != 13) &&
2790 ((str[i] & 127) >= ' ')) {
2791 par->InsertChar(pos, str[i]);
2792 par->SetFont(pos, current_font);
2795 } else if (str[i] == ' ') {
2796 InsetSpecialChar * new_inset =
2797 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2798 if (par->InsertInsetAllowed(new_inset)) {
2799 par->InsertChar(pos, LyXParagraph::META_INSET);
2800 par->SetFont(pos, current_font);
2801 par->InsertInset(pos, new_inset);
2806 } else if (str[i] == '\t') {
2807 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2808 InsetSpecialChar * new_inset =
2809 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2810 if (par->InsertInsetAllowed(new_inset)) {
2811 par->InsertChar(pos, LyXParagraph::META_INSET);
2812 par->SetFont(pos, current_font);
2813 par->InsertInset(pos, new_inset);
2819 } else if (str[i] != 13 &&
2820 // Ignore unprintables
2821 (str[i] & 127) >= ' ') {
2822 par->InsertChar(pos, str[i]);
2823 par->SetFont(pos, current_font);
2828 if (i + 1 >= str.length()) {
2832 while((pos < par->size()) &&
2833 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2836 cell = NumberOfCell(par, pos);
2837 while((pos < par->size()) &&
2838 !(par->table->IsFirstCell(cell))) {
2840 while((pos < par->size()) &&
2841 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2844 cell = NumberOfCell(par, pos);
2846 if (pos >= par->size())
2847 // no more fields to fill skip the rest
2850 if (!par->size()) { // par is empty
2851 InsetSpecialChar * new_inset =
2852 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2853 if (par->InsertInsetAllowed(new_inset)) {
2854 par->InsertChar(pos, LyXParagraph::META_INSET);
2855 par->SetFont(pos, current_font);
2856 par->InsertInset(pos, new_inset);
2862 par->BreakParagraph(pos, flag);
2870 RedoParagraphs(cursor, endpar);
2871 SetCursor(cursor.par, cursor.pos);
2872 sel_cursor = cursor;
2873 SetCursor(par, pos);
2878 /* turns double-CR to single CR, others where converted into one blank and 13s
2879 * that are ignored .Double spaces are also converted into one. Spaces at
2880 * the beginning of a paragraph are forbidden. tabs are converted into one
2881 * space. then InsertStringA is called */
2882 void LyXText::InsertStringB(string const & s)
2885 LyXParagraph * par = cursor.par;
2886 string::size_type i = 1;
2887 while (i < str.length()) {
2888 if (str[i] == '\t' && !par->table)
2890 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2892 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2893 if (str[i + 1] != '\n') {
2894 if (str[i - 1] != ' ')
2899 while (i + 1 < str.length()
2900 && (str[i + 1] == ' '
2901 || str[i + 1] == '\t'
2902 || str[i + 1] == '\n'
2903 || str[i + 1] == 13)) {
2914 bool LyXText::GotoNextError() const
2916 LyXCursor res = cursor;
2918 if (res.pos < res.par->Last() - 1) {
2922 res.par = res.par->Next();
2927 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2928 && res.par->GetInset(res.pos)->AutoDelete()));
2931 SetCursor(res.par, res.pos);
2938 bool LyXText::GotoNextNote() const
2940 LyXCursor res = cursor;
2942 if (res.pos < res.par->Last() - 1) {
2945 res.par = res.par->Next();
2950 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2951 && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
2954 SetCursor(res.par, res.pos);
2961 void LyXText::CheckParagraph(LyXParagraph * par,
2962 LyXParagraph::size_type pos)
2964 LyXCursor tmpcursor;
2967 /* table stuff -- begin*/
2970 CheckParagraphInTable(par, pos);
2973 /* table stuff -- end*/
2976 LyXParagraph::size_type z;
2977 Row * row = GetRow(par, pos, y);
2979 // is there a break one row above
2980 if (row->previous && row->previous->par == row->par) {
2981 z = NextBreakPoint(row->previous, paperwidth);
2982 if ( z >= row->pos) {
2983 // set the dimensions of the row above
2984 y -= row->previous->height;
2986 refresh_row = row->previous;
2987 status = LyXText::NEED_MORE_REFRESH;
2989 BreakAgain(row->previous);
2991 // set the cursor again. Otherwise
2992 // dangling pointers are possible
2993 SetCursor(cursor.par, cursor.pos);
2994 sel_cursor = cursor;
2999 int tmpheight = row->height;
3000 LyXParagraph::size_type tmplast = RowLast(row);
3005 if (row->height == tmpheight && RowLast(row) == tmplast)
3006 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3008 status = LyXText::NEED_MORE_REFRESH;
3010 // check the special right address boxes
3011 if (textclasslist.Style(buffer->params.textclass,
3012 par->GetLayout()).margintype
3013 == MARGIN_RIGHT_ADDRESS_BOX) {
3014 tmpcursor.par = par;
3015 tmpcursor.row = row;
3018 tmpcursor.x_fix = 0;
3019 tmpcursor.pos = pos;
3020 RedoDrawingOfParagraph(tmpcursor);
3025 // set the cursor again. Otherwise dangling pointers are possible
3026 // also set the selection
3030 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
3031 sel_cursor = cursor;
3032 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
3033 sel_start_cursor = cursor;
3034 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
3035 sel_end_cursor = cursor;
3036 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
3037 last_sel_cursor = cursor;
3040 SetCursorIntern(cursor.par, cursor.pos);
3044 // returns 0 if inset wasn't found
3045 int LyXText::UpdateInset(Inset * inset)
3047 // first check the current paragraph
3048 int pos = cursor.par->GetPositionOfInset(inset);
3050 CheckParagraph(cursor.par, pos);
3054 // check every paragraph
3056 LyXParagraph * par = FirstParagraph();
3058 // make sure the paragraph is open
3059 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
3060 pos = par->GetPositionOfInset(inset);
3062 CheckParagraph(par, pos);
3073 void LyXText::SetCursor(LyXParagraph * par,
3074 LyXParagraph::size_type pos, bool setfont) const
3076 LyXCursor old_cursor = cursor;
3077 SetCursorIntern(par, pos, setfont);
3078 DeleteEmptyParagraphMechanism(old_cursor);
3082 void LyXText::SetCursor(LyXCursor & cur, LyXParagraph * par,
3083 LyXParagraph::size_type pos) const
3085 // correct the cursor position if impossible
3086 if (pos > par->Last()){
3087 LyXParagraph * tmppar = par->ParFromPos(pos);
3088 pos = par->PositionInParFromPos(pos);
3091 if (par->IsDummy() && par->previous &&
3092 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3093 while (par->previous &&
3094 ((par->previous->IsDummy() &&
3095 (par->previous->previous->footnoteflag ==
3096 LyXParagraph::CLOSED_FOOTNOTE)) ||
3097 (par->previous->footnoteflag ==
3098 LyXParagraph::CLOSED_FOOTNOTE))) {
3099 par = par->previous ;
3100 if (par->IsDummy() &&
3101 (par->previous->footnoteflag ==
3102 LyXParagraph::CLOSED_FOOTNOTE))
3103 pos += par->size() + 1;
3105 if (par->previous) {
3106 par = par->previous;
3108 pos += par->size() + 1;
3114 /* get the cursor y position in text */
3116 Row * row = GetRow(par, pos, y);
3117 /* y is now the beginning of the cursor row */
3119 /* y is now the cursor baseline */
3122 /* now get the cursors x position */
3124 float fill_separator, fill_hfill, fill_label_hfill;
3125 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3126 LyXParagraph::size_type cursor_vpos;
3127 LyXParagraph::size_type last = RowLastPrintable(row);
3129 if (pos > last + 1) // This shouldn't happen.
3132 if (last < row->pos)
3134 else if ((pos > last) ||
3135 ((pos - 1 >= row->pos) &&
3136 (row->par->IsSeparator(pos) ||
3137 (row->par->table && row->par->IsNewline(pos)))))
3138 /// Place cursor after char at (logical) position pos-1
3139 cursor_vpos = !(bidi_level(pos-1) % 2)
3140 ? log2vis(pos-1) + 1 : log2vis(pos-1);
3142 /// Place cursor before char at (logical) position pos
3143 cursor_vpos = !(bidi_level(pos) % 2)
3144 ? log2vis(pos) : log2vis(pos) + 1;
3146 /* table stuff -- begin*/
3147 if (row->par->table) {
3148 int cell = NumberOfCell(row->par, row->pos);
3150 x += row->par->table->GetBeginningOfTextInCell(cell);
3151 for (LyXParagraph::size_type vpos = row->pos;
3152 vpos < cursor_vpos; ++vpos) {
3153 pos = vis2log(vpos);
3154 if (row->par->IsNewline(pos)) {
3155 x = x_old + row->par->table->WidthOfColumn(cell);
3158 x += row->par->table->GetBeginningOfTextInCell(cell);
3160 x += SingleWidth(row->par, pos);
3164 /* table stuff -- end*/
3165 LyXParagraph::size_type main_body =
3166 BeginningOfMainBody(row->par);
3167 if ((main_body > 0) &&
3168 ((main_body-1 > last) ||
3169 !row->par->IsLineSeparator(main_body-1)))
3172 for (LyXParagraph::size_type vpos = row->pos;
3173 vpos < cursor_vpos; ++vpos) {
3174 pos = vis2log(vpos);
3175 if (main_body > 0 && pos == main_body-1) {
3176 x += fill_label_hfill +
3177 lyxfont::width(textclasslist.Style(
3178 buffer->params.textclass,
3179 row->par->GetLayout())
3181 GetFont(row->par, -2));
3182 if (row->par->IsLineSeparator(main_body-1))
3183 x -= SingleWidth(row->par,main_body-1);
3185 if (HfillExpansion(row, pos)) {
3186 x += SingleWidth(row->par, pos);
3187 if (pos >= main_body)
3190 x += fill_label_hfill;
3191 } else if (row->par->IsSeparator(pos)) {
3192 x += SingleWidth(row->par, pos);
3193 if (pos >= main_body)
3194 x += fill_separator;
3196 x += SingleWidth(row->par, pos);
3206 void LyXText::SetCursorIntern(LyXParagraph * par,
3207 LyXParagraph::size_type pos, bool setfont) const
3209 SetCursor(cursor, par, pos);
3210 #warning Remove this when verified working (Jug 20000413)
3212 // correct the cursor position if impossible
3213 if (pos > par->Last()){
3214 LyXParagraph * tmppar = par->ParFromPos(pos);
3215 pos = par->PositionInParFromPos(pos);
3218 if (par->IsDummy() && par->previous &&
3219 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3220 while (par->previous &&
3221 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
3222 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
3223 par = par->previous ;
3224 if (par->IsDummy() &&
3225 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3226 pos += par->size() + 1;
3228 if (par->previous) {
3229 par = par->previous;
3231 pos += par->size() + 1;
3237 /* get the cursor y position in text */
3239 Row * row = GetRow(par, pos, y);
3240 /* y is now the beginning of the cursor row */
3242 /* y is now the cursor baseline */
3245 /* now get the cursors x position */
3247 float fill_separator, fill_hfill, fill_label_hfill;
3248 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3249 LyXParagraph::size_type cursor_vpos;
3250 LyXParagraph::size_type last = RowLastPrintable(row);
3252 if (pos > last + 1) // This shouldn't happen.
3255 if (last < row->pos)
3257 else if (pos > last ||
3258 (pos - 1 >= row->pos &&
3259 (row->par->IsSeparator(pos) ||
3260 (row->par->table && row->par->IsNewline(pos))
3262 /// Place cursor after char at (logical) position pos-1
3263 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
3264 ? log2vis(pos-1) + 1 : log2vis(pos-1);
3266 /// Place cursor before char at (logical) position pos
3267 cursor_vpos = (bidi_level(pos) % 2 == 0)
3268 ? log2vis(pos) : log2vis(pos) + 1;
3270 /* table stuff -- begin*/
3271 if (row->par->table) {
3272 int cell = NumberOfCell(row->par, row->pos);
3274 x += row->par->table->GetBeginningOfTextInCell(cell);
3275 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3276 pos = vis2log(vpos);
3277 if (row->par->IsNewline(pos)) {
3278 x = x_old + row->par->table->WidthOfColumn(cell);
3281 x += row->par->table->GetBeginningOfTextInCell(cell);
3283 x += SingleWidth(row->par, pos);
3287 /* table stuff -- end*/
3288 LyXParagraph::size_type main_body =
3289 BeginningOfMainBody(row->par);
3290 if (main_body > 0 &&
3291 (main_body-1 > last ||
3292 !row->par->IsLineSeparator(main_body-1)))
3295 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3296 pos = vis2log(vpos);
3297 if (main_body > 0 && pos == main_body-1) {
3298 x += fill_label_hfill +
3299 lyxfont::width(textclasslist
3300 .Style(buffer->params.textclass,
3301 row->par->GetLayout())
3303 GetFont(row->par, -2));
3304 if (row->par->IsLineSeparator(main_body-1))
3305 x -= SingleWidth(row->par, main_body-1);
3307 if (HfillExpansion(row, pos)) {
3308 x += SingleWidth(row->par, pos);
3309 if (pos >= main_body)
3312 x += fill_label_hfill;
3314 else if (row->par->IsSeparator(pos)) {
3315 x += SingleWidth(row->par, pos);
3316 if (pos >= main_body)
3317 x += fill_separator;
3319 x += SingleWidth(row->par, pos);
3325 cursor.x_fix = cursor.x;
3330 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
3331 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3333 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3334 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3336 current_font = cursor.par->GetFontSettings(cursor.pos);
3337 real_current_font = GetFont(cursor.par, cursor.pos);
3343 void LyXText::SetCursorFromCoordinates(int x, long y) const
3345 LyXCursor old_cursor = cursor;
3347 /* get the row first */
3349 Row * row = GetRowNearY(y);
3351 cursor.par = row->par;
3353 int column = GetColumnNearX(row, x);
3354 cursor.pos = row->pos + column;
3356 cursor.y = y + row->baseline;
3361 (cursor.pos == cursor.par->Last()
3362 || cursor.par->IsSeparator(cursor.pos)
3363 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3364 && !cursor.par->IsSeparator(cursor.pos))
3365 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3367 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3368 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3370 current_font = cursor.par->GetFontSettings(cursor.pos);
3371 real_current_font = GetFont(cursor.par, cursor.pos);
3373 DeleteEmptyParagraphMechanism(old_cursor);
3376 void LyXText::SetCursorFromCoordinates(LyXCursor & cur, int x, long y) const
3378 /* get the row first */
3380 Row * row = GetRowNearY(y);
3381 int column = GetColumnNearX(row, x);
3384 cur.pos = row->pos + column;
3386 cur.y = y + row->baseline;
3391 void LyXText::CursorLeft() const
3394 if (cursor.par->table) {
3395 int cell = NumberOfCell(cursor.par, cursor.pos);
3396 if (cursor.par->table->IsContRow(cell) &&
3397 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell)) < 0) {
3404 void LyXText::CursorLeftIntern() const
3406 if (cursor.pos > 0) {
3407 SetCursor(cursor.par, cursor.pos - 1);
3409 else if (cursor.par->Previous()) { // steps into the above paragraph.
3410 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3415 void LyXText::CursorRight() const
3417 CursorRightIntern();
3418 if (cursor.par->table) {
3419 int cell = NumberOfCell(cursor.par, cursor.pos);
3420 if (cursor.par->table->IsContRow(cell) &&
3421 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3428 void LyXText::CursorRightIntern() const
3430 if (cursor.pos < cursor.par->Last()) {
3431 SetCursor(cursor.par, cursor.pos + 1);
3433 else if (cursor.par->Next()) {
3434 SetCursor(cursor.par->Next(), 0);
3439 void LyXText::CursorUp() const
3441 SetCursorFromCoordinates(cursor.x_fix,
3442 cursor.y - cursor.row->baseline - 1);
3443 if (cursor.par->table) {
3444 int cell = NumberOfCell(cursor.par, cursor.pos);
3445 if (cursor.par->table->IsContRow(cell) &&
3446 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3453 void LyXText::CursorDown() const
3455 if (cursor.par->table &&
3456 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3459 SetCursorFromCoordinates(cursor.x_fix,
3460 cursor.y - cursor.row->baseline
3461 + cursor.row->height + 1);
3462 if (cursor.par->table) {
3463 int cell = NumberOfCell(cursor.par, cursor.pos);
3464 int cell_above = cursor.par->table->GetCellAbove(cell);
3465 while(cursor.par->table &&
3466 cursor.par->table->IsContRow(cell) &&
3467 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3468 SetCursorFromCoordinates(cursor.x_fix,
3469 cursor.y - cursor.row->baseline
3470 + cursor.row->height + 1);
3471 if (cursor.par->table) {
3472 cell = NumberOfCell(cursor.par, cursor.pos);
3473 cell_above = cursor.par->table->GetCellAbove(cell);
3480 void LyXText::CursorUpParagraph() const
3482 if (cursor.pos > 0) {
3483 SetCursor(cursor.par, 0);
3485 else if (cursor.par->Previous()) {
3486 SetCursor(cursor.par->Previous(), 0);
3491 void LyXText::CursorDownParagraph() const
3493 if (cursor.par->Next()) {
3494 SetCursor(cursor.par->Next(), 0);
3496 SetCursor(cursor.par, cursor.par->Last());
3502 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3504 // Would be wrong to delete anything if we have a selection.
3505 if (selection) return;
3507 // We allow all kinds of "mumbo-jumbo" when freespacing.
3508 if (textclasslist.Style(buffer->params.textclass,
3509 old_cursor.par->GetLayout()).free_spacing)
3512 bool deleted = false;
3514 /* Ok I'll put some comments here about what is missing.
3515 I have fixed BackSpace (and thus Delete) to not delete
3516 double-spaces automagically. I have also changed Cut,
3517 Copy and Paste to hopefully do some sensible things.
3518 There are still some small problems that can lead to
3519 double spaces stored in the document file or space at
3520 the beginning of paragraphs. This happens if you have
3521 the cursor betwenn to spaces and then save. Or if you
3522 cut and paste and the selection have a space at the
3523 beginning and then save right after the paste. I am
3524 sure none of these are very hard to fix, but I will
3525 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3526 that I can get some feedback. (Lgb)
3529 // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3530 // delete the LineSeparator.
3533 // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3534 // delete the LineSeparator.
3537 // If the pos around the old_cursor were spaces, delete one of them.
3538 if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) { // Only if the cursor has really moved
3540 if (old_cursor.pos > 0
3541 && old_cursor.pos < old_cursor.par->Last()
3542 && old_cursor.par->IsLineSeparator(old_cursor.pos)
3543 && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3544 old_cursor.par->Erase(old_cursor.pos - 1);
3545 RedoParagraphs(old_cursor, old_cursor.par->Next());
3547 if (old_cursor.par == cursor.par &&
3548 cursor.pos > old_cursor.pos) {
3549 SetCursorIntern(cursor.par, cursor.pos - 1);
3551 SetCursorIntern(cursor.par, cursor.pos);
3556 // Do not delete empty paragraphs with keepempty set.
3557 if ((textclasslist.Style(buffer->params.textclass,
3558 old_cursor.par->GetLayout())).keepempty)
3561 LyXCursor tmpcursor;
3563 if (old_cursor.par != cursor.par) {
3564 if ( (old_cursor.par->Last() == 0
3565 || (old_cursor.par->Last() == 1
3566 && old_cursor.par->IsLineSeparator(0)))
3567 && old_cursor.par->FirstPhysicalPar()
3568 == old_cursor.par->LastPhysicalPar()) {
3569 // ok, we will delete anything
3571 // make sure that you do not delete any environments
3572 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3573 !(old_cursor.row->previous
3574 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3575 && !(old_cursor.row->next
3576 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3577 || (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3578 && ((old_cursor.row->previous
3579 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3580 || (old_cursor.row->next
3581 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3583 status = LyXText::NEED_MORE_REFRESH;
3586 if (old_cursor.row->previous) {
3587 refresh_row = old_cursor.row->previous;
3588 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3590 cursor = old_cursor; // that undo can restore the right cursor position
3591 LyXParagraph * endpar = old_cursor.par->next;
3592 if (endpar && endpar->GetDepth()) {
3593 while (endpar && endpar->GetDepth()) {
3594 endpar = endpar->LastPhysicalPar()->Next();
3597 SetUndo(Undo::DELETE,
3598 old_cursor.par->previous,
3603 RemoveRow(old_cursor.row);
3604 if (buffer->paragraph == old_cursor.par) {
3605 buffer->paragraph = buffer->paragraph->next;
3608 delete old_cursor.par;
3610 /* Breakagain the next par. Needed
3611 * because of the parindent that
3612 * can occur or dissappear. The
3613 * next row can change its height,
3614 * if there is another layout before */
3615 if (refresh_row->next) {
3616 BreakAgain(refresh_row->next);
3617 UpdateCounters(refresh_row);
3619 SetHeightOfRow(refresh_row);
3621 refresh_row = old_cursor.row->next;
3622 refresh_y = old_cursor.y - old_cursor.row->baseline;
3625 cursor = old_cursor; // that undo can restore the right cursor position
3626 LyXParagraph *endpar = old_cursor.par->next;
3627 if (endpar && endpar->GetDepth()) {
3628 while (endpar && endpar->GetDepth()) {
3629 endpar = endpar->LastPhysicalPar()->Next();
3632 SetUndo(Undo::DELETE,
3633 old_cursor.par->previous,
3638 RemoveRow(old_cursor.row);
3640 if (buffer->paragraph == old_cursor.par) {
3641 buffer->paragraph = buffer->paragraph->next;
3643 delete old_cursor.par;
3645 /* Breakagain the next par. Needed
3646 because of the parindent that can
3647 occur or dissappear.
3648 The next row can change its height,
3649 if there is another layout before
3652 BreakAgain(refresh_row);
3653 UpdateCounters(refresh_row->previous);
3659 SetCursorIntern(cursor.par, cursor.pos);
3661 if (sel_cursor.par == old_cursor.par
3662 && sel_cursor.pos == sel_cursor.pos) {
3663 // correct selection
3664 sel_cursor = cursor;
3669 if (old_cursor.par->ClearParagraph()) {
3670 RedoParagraphs(old_cursor, old_cursor.par->Next());
3672 SetCursorIntern(cursor.par, cursor.pos);
3673 sel_cursor = cursor;
3680 LyXParagraph * LyXText::GetParFromID(int id)
3682 LyXParagraph * result = FirstParagraph();
3683 while (result && result->id() != id)
3684 result = result->next;
3690 bool LyXText::TextUndo()
3692 // returns false if no undo possible
3693 Undo * undo = buffer->undostack.pop();
3698 .push(CreateUndo(undo->kind,
3699 GetParFromID(undo->number_of_before_par),
3700 GetParFromID(undo->number_of_behind_par)));
3702 return TextHandleUndo(undo);
3706 bool LyXText::TextRedo()
3708 // returns false if no redo possible
3709 Undo * undo = buffer->redostack.pop();
3714 .push(CreateUndo(undo->kind,
3715 GetParFromID(undo->number_of_before_par),
3716 GetParFromID(undo->number_of_behind_par)));
3718 return TextHandleUndo(undo);
3722 bool LyXText::TextHandleUndo(Undo * undo)
3724 // returns false if no undo possible
3725 bool result = false;
3727 LyXParagraph * before =
3728 GetParFromID(undo->number_of_before_par);
3729 LyXParagraph * behind =
3730 GetParFromID(undo->number_of_behind_par);
3731 LyXParagraph * tmppar;
3732 LyXParagraph * tmppar2;
3733 LyXParagraph * endpar;
3734 LyXParagraph * tmppar5;
3736 // if there's no before take the beginning
3737 // of the document for redoing
3739 SetCursorIntern(FirstParagraph(), 0);
3741 // replace the paragraphs with the undo informations
3743 LyXParagraph * tmppar3 = undo->par;
3744 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3745 LyXParagraph * tmppar4 = tmppar3;
3747 while (tmppar4->next)
3748 tmppar4 = tmppar4->next;
3749 } // get last undo par
3751 // now remove the old text if there is any
3752 if (before != behind || (!behind && !before)){
3754 tmppar5 = before->next;
3756 tmppar5 = buffer->paragraph;
3758 while (tmppar5 && tmppar5 != behind){
3760 tmppar5 = tmppar5->next;
3761 // a memory optimization for edit: Only layout information
3762 // is stored in the undo. So restore the text informations.
3763 if (undo->kind == Undo::EDIT) {
3764 tmppar2->setContentsFromPar(tmppar);
3765 tmppar->clearContents();
3766 tmppar2 = tmppar2->next;
3771 // put the new stuff in the list if there is one
3774 before->next = tmppar3;
3776 buffer->paragraph = tmppar3;
3777 tmppar3->previous = before;
3781 buffer->paragraph = behind;
3784 tmppar4->next = behind;
3786 behind->previous = tmppar4;
3790 // Set the cursor for redoing
3792 SetCursorIntern(before->FirstSelfrowPar(), 0);
3793 // check wether before points to a closed float and open it if necessary
3794 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3795 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3797 while (tmppar4->previous &&
3798 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3799 tmppar4 = tmppar4->previous;
3800 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3801 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3802 tmppar4 = tmppar4->next;
3807 // open a cosed footnote at the end if necessary
3808 if (behind && behind->previous &&
3809 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3810 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3811 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3812 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3813 behind = behind->next;
3817 // calculate the endpar for redoing the paragraphs.
3819 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3820 endpar = behind->LastPhysicalPar()->Next();
3822 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3827 tmppar = GetParFromID(undo->number_of_cursor_par);
3828 RedoParagraphs(cursor, endpar);
3830 SetCursorIntern(tmppar, undo->cursor_pos);
3831 UpdateCounters(cursor.row);
3841 void LyXText::FinishUndo()
3843 // makes sure the next operation will be stored
3844 undo_finished = True;
3848 void LyXText::FreezeUndo()
3850 // this is dangerous and for internal use only
3855 void LyXText::UnFreezeUndo()
3857 // this is dangerous and for internal use only
3858 undo_frozen = false;
3862 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3863 LyXParagraph const * behind) const
3866 buffer->undostack.push(CreateUndo(kind, before, behind));
3867 buffer->redostack.clear();
3871 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3872 LyXParagraph const * behind)
3874 buffer->redostack.push(CreateUndo(kind, before, behind));
3878 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3879 LyXParagraph const * behind) const
3881 int before_number = -1;
3882 int behind_number = -1;
3884 before_number = before->id();
3886 behind_number = behind->id();
3887 // Undo::EDIT and Undo::FINISH are
3888 // always finished. (no overlapping there)
3889 // overlapping only with insert and delete inside one paragraph:
3890 // Nobody wants all removed character
3891 // appear one by one when undoing.
3892 // EDIT is special since only layout information, not the
3893 // contents of a paragaph are stored.
3894 if (!undo_finished && kind != Undo::EDIT &&
3895 kind != Undo::FINISH){
3896 // check wether storing is needed
3897 if (!buffer->undostack.empty() &&
3898 buffer->undostack.top()->kind == kind &&
3899 buffer->undostack.top()->number_of_before_par == before_number &&
3900 buffer->undostack.top()->number_of_behind_par == behind_number ){
3905 // create a new Undo
3906 LyXParagraph * undopar;
3907 LyXParagraph * tmppar;
3908 LyXParagraph * tmppar2;
3910 LyXParagraph * start = 0;
3911 LyXParagraph * end = 0;
3914 start = before->next;
3916 start = FirstParagraph();
3918 end = behind->previous;
3920 end = FirstParagraph();
3926 && start != end->next
3927 && (before != behind || (!before && !behind))) {
3929 tmppar2 = tmppar->Clone();
3930 tmppar2->id(tmppar->id());
3932 // a memory optimization: Just store the layout information
3934 if (kind == Undo::EDIT){
3935 //tmppar2->text.clear();
3936 tmppar2->clearContents();
3941 while (tmppar != end && tmppar->next) {
3942 tmppar = tmppar->next;
3943 tmppar2->next = tmppar->Clone();
3944 tmppar2->next->id(tmppar->id());
3945 // a memory optimization: Just store the layout
3946 // information when only edit
3947 if (kind == Undo::EDIT){
3948 //tmppar2->next->text.clear();
3949 tmppar2->clearContents();
3951 tmppar2->next->previous = tmppar2;
3952 tmppar2 = tmppar2->next;
3956 undopar = 0; // nothing to replace (undo of delete maybe)
3958 int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
3959 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
3961 Undo * undo = new Undo(kind,
3962 before_number, behind_number,
3963 cursor_par, cursor_pos,
3966 undo_finished = false;
3971 void LyXText::SetCursorParUndo()
3973 SetUndo(Undo::FINISH,
3974 cursor.par->ParFromPos(cursor.pos)->previous,
3975 cursor.par->ParFromPos(cursor.pos)->next);
3979 void LyXText::RemoveTableRow(LyXCursor * cur) const
3985 // move to the previous row
3986 int cell_act = NumberOfCell(cur->par, cur->pos);
3989 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3992 !cur->par->table->IsFirstCell(cell_act)) {
3994 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3999 // now we have to pay attention if the actual table is the
4000 // main row of TableContRows and if yes to delete all of them
4005 // delete up to the next row
4006 while (cur->pos < cur->par->Last() &&
4008 || !cur->par->table->IsFirstCell(cell_act))) {
4009 while (cur->pos < cur->par->Last() &&
4010 !cur->par->IsNewline(cur->pos))
4011 cur->par->Erase(cur->pos);
4014 if (cur->pos < cur->par->Last())
4015 cur->par->Erase(cur->pos);
4017 if (cur->pos && cur->pos == cur->par->Last()) {
4019 cur->par->Erase(cur->pos); // no newline at very end!
4021 } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
4022 !cur->par->table->IsContRow(cell_org) &&
4023 cur->par->table->IsContRow(cell));
4024 cur->par->table->DeleteRow(cell_org);
4029 bool LyXText::IsEmptyTableCell() const
4031 LyXParagraph::size_type pos = cursor.pos - 1;
4032 while (pos >= 0 && pos < cursor.par->Last()
4033 && !cursor.par->IsNewline(pos))
4035 return cursor.par->IsNewline(pos + 1);
4039 void LyXText::toggleAppendix(){
4040 LyXParagraph * par = cursor.par->FirstPhysicalPar();
4041 bool start = !par->start_of_appendix;
4043 // ensure that we have only one start_of_appendix in this document
4044 LyXParagraph * tmp = FirstParagraph();
4045 for (; tmp; tmp = tmp->next)
4046 tmp->start_of_appendix = 0;
4047 par->start_of_appendix = start;
4049 // we can set the refreshing parameters now
4050 status = LyXText::NEED_MORE_REFRESH;
4052 refresh_row = 0; // not needed for full update
4054 SetCursor(cursor.par, cursor.pos);