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 delete 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
1026 && cursor.x < last_sel_cursor.x)) {
1027 toggle_end_cursor = last_sel_cursor;
1028 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)
1061 // Stuff what we got on the clipboard. Even if there is no selection.
1063 // There is a problem with having the stuffing here in that the
1064 // larger the selection the slower LyX will get. This can be
1065 // solved by running the line below only when the selection has
1066 // finished. The solution used currently just works, to make it
1067 // faster we need to be more clever and probably also have more
1068 // calls to stuffClipboard. (Lgb)
1069 owner_->stuffClipboard(selectionAsString());
1073 string LyXText::selectionAsString() const
1075 if (!selection) return string();
1078 // Special handling if the whole selection is within one paragraph
1079 if (sel_start_cursor.par == sel_end_cursor.par) {
1080 result += sel_start_cursor.par->String(sel_start_cursor.pos,
1081 sel_end_cursor.pos);
1085 // The selection spans more than one paragraph
1087 // First paragraph in selection
1088 result += sel_start_cursor.par->String(sel_start_cursor.pos,
1089 sel_start_cursor.par->Last())
1092 // The paragraphs in between (if any)
1093 LyXCursor tmpcur(sel_start_cursor);
1094 tmpcur.par = tmpcur.par->Next();
1095 while (tmpcur.par != sel_end_cursor.par) {
1096 result += tmpcur.par->String(0, tmpcur.par->Last()) + "\n\n";
1097 tmpcur.par = tmpcur.par->Next(); // Or NextAfterFootnote??
1100 // Last paragraph in selection
1101 result += sel_end_cursor.par->String(0, sel_end_cursor.pos);
1107 void LyXText::ClearSelection() const
1114 void LyXText::CursorHome() const
1116 SetCursor(cursor.par, cursor.row->pos);
1120 void LyXText::CursorEnd() const
1122 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1123 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1125 if (cursor.par->Last() &&
1126 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1127 || cursor.par->IsNewline(RowLast(cursor.row))))
1128 SetCursor(cursor.par, RowLast(cursor.row));
1130 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1132 if (cursor.par->table) {
1133 int cell = NumberOfCell(cursor.par, cursor.pos);
1134 if (cursor.par->table->RowHasContRow(cell) &&
1135 cursor.par->table->CellHasContRow(cell)<0) {
1136 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1137 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1139 if (cursor.par->Last() &&
1140 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1141 || cursor.par->IsNewline(RowLast(cursor.row))))
1142 SetCursor(cursor.par, RowLast(cursor.row));
1144 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1151 void LyXText::CursorTop() const
1153 while (cursor.par->Previous())
1154 cursor.par = cursor.par->Previous();
1155 SetCursor(cursor.par, 0);
1159 void LyXText::CursorBottom() const
1161 while (cursor.par->Next())
1162 cursor.par = cursor.par->Next();
1163 SetCursor(cursor.par, cursor.par->Last());
1167 /* returns a pointer to the row near the specified y-coordinate
1168 * (relative to the whole text). y is set to the real beginning
1170 Row * LyXText::GetRowNearY(long & y) const
1172 Row * tmprow = firstrow;
1175 while (tmprow->next && tmpy + tmprow->height <= y) {
1176 tmpy += tmprow->height;
1177 tmprow = tmprow->next;
1180 y = tmpy; // return the real y
1185 void LyXText::ToggleFree(LyXFont const & font, bool toggleall)
1187 // If the mask is completely neutral, tell user
1188 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1189 // Could only happen with user style
1190 owner_->owner()->getMiniBuffer()
1191 ->Set(_("No font change defined. Use Character under"
1192 " the Layout menu to define font change."));
1196 // Try implicit word selection
1197 // If there is a change in the language the implicit word selection
1199 LyXCursor resetCursor = cursor;
1200 bool implicitSelection = (font.language() == ignore_language)
1201 ? SelectWordWhenUnderCursor() : false;
1204 SetFont(font, toggleall);
1206 /* Implicit selections are cleared afterwards and cursor is set to the
1207 original position. */
1208 if (implicitSelection) {
1210 cursor = resetCursor;
1211 SetCursor( cursor.par, cursor.pos );
1212 sel_cursor = cursor;
1217 LyXParagraph::size_type LyXText::BeginningOfMainBody(LyXParagraph * par) const
1219 if (textclasslist.Style(buffer->params.textclass,
1220 par->GetLayout()).labeltype != LABEL_MANUAL)
1223 return par->BeginningOfMainBody();
1227 /* if there is a selection, reset every environment you can find
1228 * in the selection, otherwise just the environment you are in */
1229 void LyXText::MeltFootnoteEnvironment()
1231 LyXParagraph * tmppar, * firsttmppar;
1235 /* is is only allowed, if the cursor is IN an open footnote.
1236 * Otherwise it is too dangerous */
1237 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1240 SetUndo(Undo::FINISH,
1241 cursor.par->PreviousBeforeFootnote()->previous,
1242 cursor.par->NextAfterFootnote()->next);
1244 /* ok, move to the beginning of the footnote. */
1245 while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1246 cursor.par = cursor.par->Previous();
1248 SetCursor(cursor.par, cursor.par->Last());
1249 /* this is just faster than using CursorLeft(); */
1251 firsttmppar = cursor.par->ParFromPos(cursor.pos);
1252 tmppar = firsttmppar;
1253 /* tmppar is now the paragraph right before the footnote */
1255 bool first_footnote_par_is_not_empty = tmppar->next->size();
1258 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1259 tmppar = tmppar->next; /* I use next instead of Next(),
1260 * because there cannot be any
1261 * footnotes in a footnote
1263 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1265 /* remember the captions and empty paragraphs */
1266 if ((textclasslist.Style(buffer->params.textclass,
1267 tmppar->GetLayout())
1268 .labeltype == LABEL_SENSITIVE)
1270 tmppar->SetLayout(0);
1273 // now we will paste the ex-footnote, if the layouts allow it
1274 // first restore the layout of the paragraph right behind
1277 tmppar->next->MakeSameLayout(cursor.par);
1280 if ((!tmppar->GetLayout() && !tmppar->table)
1282 && (!tmppar->Next()->Last()
1283 || tmppar->Next()->HasSameLayout(tmppar)))) {
1284 if (tmppar->Next()->Last()
1285 && tmppar->Next()->IsLineSeparator(0))
1286 tmppar->Next()->Erase(0);
1287 tmppar->PasteParagraph();
1290 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1291 * by the pasting of the beginning */
1293 /* then the beginning */
1294 /* if there is no space between the text and the footnote, so we insert
1296 * (only if the previous par and the footnotepar are not empty!) */
1297 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1298 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1299 if (firsttmppar->size()
1300 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1301 && first_footnote_par_is_not_empty) {
1302 firsttmppar->next->InsertChar(0, ' ');
1304 firsttmppar->PasteParagraph();
1307 /* now redo the paragaphs */
1308 RedoParagraphs(cursor, tmppar);
1310 SetCursor(cursor.par, cursor.pos);
1312 /* sometimes it can happen, that there is a counter change */
1313 Row * row = cursor.row;
1314 while (row->next && row->par != tmppar && row->next->par != tmppar)
1316 UpdateCounters(row);
1323 /* the DTP switches for paragraphs. LyX will store them in the
1324 * first physicla paragraph. When a paragraph is broken, the top settings
1325 * rest, the bottom settings are given to the new one. So I can make shure,
1326 * they do not duplicate themself and you cannnot make dirty things with
1329 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1330 bool pagebreak_top, bool pagebreak_bottom,
1331 VSpace const & space_top,
1332 VSpace const & space_bottom,
1334 string labelwidthstring,
1337 LyXCursor tmpcursor = cursor;
1339 sel_start_cursor = cursor;
1340 sel_end_cursor = cursor;
1343 // make sure that the depth behind the selection are restored, too
1344 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1345 LyXParagraph * undoendpar = endpar;
1347 if (endpar && endpar->GetDepth()) {
1348 while (endpar && endpar->GetDepth()) {
1349 endpar = endpar->LastPhysicalPar()->Next();
1350 undoendpar = endpar;
1354 endpar = endpar->Next(); // because of parindents etc.
1359 .par->ParFromPos(sel_start_cursor.pos)->previous,
1363 LyXParagraph * tmppar = sel_end_cursor.par;
1364 while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1365 SetCursor(tmppar->FirstPhysicalPar(), 0);
1366 status = LyXText::NEED_MORE_REFRESH;
1367 refresh_row = cursor.row;
1368 refresh_y = cursor.y - cursor.row->baseline;
1369 if (cursor.par->footnoteflag ==
1370 sel_start_cursor.par->footnoteflag) {
1371 cursor.par->line_top = line_top;
1372 cursor.par->line_bottom = line_bottom;
1373 cursor.par->pagebreak_top = pagebreak_top;
1374 cursor.par->pagebreak_bottom = pagebreak_bottom;
1375 cursor.par->added_space_top = space_top;
1376 cursor.par->added_space_bottom = space_bottom;
1377 // does the layout allow the new alignment?
1378 if (align == LYX_ALIGN_LAYOUT)
1379 align = textclasslist
1380 .Style(buffer->params.textclass,
1381 cursor.par->GetLayout()).align;
1382 if (align & textclasslist
1383 .Style(buffer->params.textclass,
1384 cursor.par->GetLayout()).alignpossible) {
1385 if (align == textclasslist
1386 .Style(buffer->params.textclass,
1387 cursor.par->GetLayout()).align)
1388 cursor.par->align = LYX_ALIGN_LAYOUT;
1390 cursor.par->align = align;
1392 cursor.par->SetLabelWidthString(labelwidthstring);
1393 cursor.par->noindent = noindent;
1396 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1399 RedoParagraphs(sel_start_cursor, endpar);
1402 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1403 sel_cursor = cursor;
1404 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1406 SetCursor(tmpcursor.par, tmpcursor.pos);
1410 void LyXText::SetParagraphExtraOpt(int type,
1412 char const * widthp,
1413 int alignment, bool hfill,
1414 bool start_minipage)
1416 LyXCursor tmpcursor = cursor;
1417 LyXParagraph * tmppar;
1419 sel_start_cursor = cursor;
1420 sel_end_cursor = cursor;
1423 // make sure that the depth behind the selection are restored, too
1424 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1425 LyXParagraph * undoendpar = endpar;
1427 if (endpar && endpar->GetDepth()) {
1428 while (endpar && endpar->GetDepth()) {
1429 endpar = endpar->LastPhysicalPar()->Next();
1430 undoendpar = endpar;
1434 endpar = endpar->Next(); // because of parindents etc.
1439 .par->ParFromPos(sel_start_cursor.pos)->previous,
1442 tmppar = sel_end_cursor.par;
1443 while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1444 SetCursor(tmppar->FirstPhysicalPar(), 0);
1445 status = LyXText::NEED_MORE_REFRESH;
1446 refresh_row = cursor.row;
1447 refresh_y = cursor.y - cursor.row->baseline;
1448 if (cursor.par->footnoteflag ==
1449 sel_start_cursor.par->footnoteflag) {
1450 if (type == LyXParagraph::PEXTRA_NONE) {
1451 if (cursor.par->pextra_type != LyXParagraph::PEXTRA_NONE) {
1452 cursor.par->UnsetPExtraType();
1453 cursor.par->pextra_type = LyXParagraph::PEXTRA_NONE;
1456 cursor.par->SetPExtraType(type, width, widthp);
1457 cursor.par->pextra_hfill = hfill;
1458 cursor.par->pextra_start_minipage = start_minipage;
1459 cursor.par->pextra_alignment = alignment;
1462 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1464 RedoParagraphs(sel_start_cursor, endpar);
1466 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1467 sel_cursor = cursor;
1468 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1470 SetCursor(tmpcursor.par, tmpcursor.pos);
1474 char loweralphaCounter(int n)
1476 if (n < 1 || n > 26)
1482 char alphaCounter(int n)
1484 if (n < 1 || n > 26)
1490 char hebrewCounter(int n)
1492 static const char hebrew[22] = {
1493 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1494 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1495 '÷', 'ø', 'ù', 'ú'
1497 if (n < 1 || n > 22)
1503 static char const * romanCounter(int n)
1505 static char const * roman[20] = {
1506 "i", "ii", "iii", "iv", "v",
1507 "vi", "vii", "viii", "ix", "x",
1508 "xi", "xii", "xiii", "xiv", "xv",
1509 "xvi", "xvii", "xviii", "xix", "xx"
1511 if (n < 1 || n > 20)
1517 // set the counter of a paragraph. This includes the labels
1518 void LyXText::SetCounter(LyXParagraph * par) const
1520 // this is only relevant for the beginning of paragraph
1521 par = par->FirstPhysicalPar();
1523 LyXLayout const & layout =
1524 textclasslist.Style(buffer->params.textclass,
1527 LyXTextClass const & textclass =
1528 textclasslist.TextClass(buffer->params.textclass);
1530 /* copy the prev-counters to this one, unless this is the start of a
1531 footnote or of a bibliography or the very first paragraph */
1533 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1534 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1535 && par->footnotekind == LyXParagraph::FOOTNOTE)
1536 && !(textclasslist.Style(buffer->params.textclass,
1537 par->Previous()->GetLayout()
1538 ).labeltype != LABEL_BIBLIO
1539 && layout.labeltype == LABEL_BIBLIO)) {
1540 for (int i = 0; i < 10; ++i) {
1541 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1543 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1544 if (!par->appendix && par->start_of_appendix){
1545 par->appendix = true;
1546 for (int i = 0; i < 10; ++i) {
1547 par->setCounter(i, 0);
1550 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1551 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1554 for (int i = 0; i < 10; ++i) {
1555 par->setCounter(i, 0);
1557 par->appendix = par->start_of_appendix;
1562 // if this is an open marginnote and this is the first
1563 // entry in the marginnote and the enclosing
1564 // environment is an enum/item then correct for the
1565 // LaTeX behaviour (ARRae)
1566 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1567 && par->footnotekind == LyXParagraph::MARGIN
1569 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1570 && (par->PreviousBeforeFootnote()
1571 && textclasslist.Style(buffer->params.textclass,
1572 par->PreviousBeforeFootnote()->GetLayout()
1573 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1574 // Any itemize or enumerate environment in a marginnote
1575 // that is embedded in an itemize or enumerate
1576 // paragraph is seen by LaTeX as being at a deeper
1577 // level within that enclosing itemization/enumeration
1578 // even if there is a "standard" layout at the start of
1584 /* Maybe we have to increment the enumeration depth.
1585 * BUT, enumeration in a footnote is considered in isolation from its
1586 * surrounding paragraph so don't increment if this is the
1587 * first line of the footnote
1588 * AND, bibliographies can't have their depth changed ie. they
1589 * are always of depth 0
1592 && par->Previous()->GetDepth() < par->GetDepth()
1593 && textclasslist.Style(buffer->params.textclass,
1594 par->Previous()->GetLayout()
1595 ).labeltype == LABEL_COUNTER_ENUMI
1596 && par->enumdepth < 3
1597 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1598 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1599 && par->footnotekind == LyXParagraph::FOOTNOTE)
1600 && layout.labeltype != LABEL_BIBLIO) {
1604 /* Maybe we have to decrement the enumeration depth, see note above */
1606 && par->Previous()->GetDepth() > par->GetDepth()
1607 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1608 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1609 && par->footnotekind == LyXParagraph::FOOTNOTE)
1610 && layout.labeltype != LABEL_BIBLIO) {
1611 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1612 par->setCounter(6 + par->enumdepth,
1613 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1614 /* reset the counters.
1615 * A depth change is like a breaking layout
1617 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1618 par->setCounter(i, 0);
1621 if (!par->labelstring.empty()) {
1622 par->labelstring.erase();
1625 if (layout.margintype == MARGIN_MANUAL) {
1626 if (par->labelwidthstring.empty()) {
1627 par->SetLabelWidthString(layout.labelstring());
1630 par->SetLabelWidthString(string());
1633 /* is it a layout that has an automatic label ? */
1634 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1636 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1637 if (i >= 0 && i<= buffer->params.secnumdepth) {
1638 par->incCounter(i); // increment the counter
1640 // Is there a label? Useful for Chapter layout
1641 if (!par->appendix){
1642 if (!layout.labelstring().empty())
1643 par->labelstring = layout.labelstring();
1645 par->labelstring.erase();
1647 if (!layout.labelstring_appendix().empty())
1648 par->labelstring = layout.labelstring_appendix();
1650 par->labelstring.erase();
1654 std::ostringstream s;
1658 if (!par->appendix) {
1659 switch (2 * LABEL_FIRST_COUNTER -
1660 textclass.maxcounter() + i) {
1661 case LABEL_COUNTER_CHAPTER:
1662 s << par->getCounter(i);
1664 case LABEL_COUNTER_SECTION:
1665 s << par->getCounter(i - 1) << '.'
1666 << par->getCounter(i);
1668 case LABEL_COUNTER_SUBSECTION:
1669 s << par->getCounter(i - 2) << '.'
1670 << par->getCounter(i - 1) << '.'
1671 << par->getCounter(i);
1673 case LABEL_COUNTER_SUBSUBSECTION:
1674 s << par->getCounter(i - 3) << '.'
1675 << par->getCounter(i - 2) << '.'
1676 << par->getCounter(i - 1) << '.'
1677 << par->getCounter(i);
1680 case LABEL_COUNTER_PARAGRAPH:
1681 s << par->getCounter(i - 4) << '.'
1682 << par->getCounter(i - 3) << '.'
1683 << par->getCounter(i - 2) << '.'
1684 << par->getCounter(i - 1) << '.'
1685 << par->getCounter(i);
1687 case LABEL_COUNTER_SUBPARAGRAPH:
1688 s << par->getCounter(i - 5) << '.'
1689 << par->getCounter(i - 4) << '.'
1690 << par->getCounter(i - 3) << '.'
1691 << par->getCounter(i - 2) << '.'
1692 << par->getCounter(i - 1) << '.'
1693 << par->getCounter(i);
1697 s << par->getCounter(i) << '.';
1700 } else { // appendix
1701 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1702 case LABEL_COUNTER_CHAPTER:
1703 if (par->isRightToLeftPar())
1704 s << hebrewCounter(par->getCounter(i));
1706 s << alphaCounter(par->getCounter(i));
1708 case LABEL_COUNTER_SECTION:
1709 if (par->isRightToLeftPar())
1710 s << hebrewCounter(par->getCounter(i - 1));
1712 s << alphaCounter(par->getCounter(i - 1));
1715 << par->getCounter(i);
1718 case LABEL_COUNTER_SUBSECTION:
1719 if (par->isRightToLeftPar())
1720 s << hebrewCounter(par->getCounter(i - 2));
1722 s << alphaCounter(par->getCounter(i - 2));
1725 << par->getCounter(i-1) << '.'
1726 << par->getCounter(i);
1729 case LABEL_COUNTER_SUBSUBSECTION:
1730 if (par->isRightToLeftPar())
1731 s << hebrewCounter(par->getCounter(i-3));
1733 s << alphaCounter(par->getCounter(i-3));
1736 << par->getCounter(i-2) << '.'
1737 << par->getCounter(i-1) << '.'
1738 << par->getCounter(i);
1741 case LABEL_COUNTER_PARAGRAPH:
1742 if (par->isRightToLeftPar())
1743 s << hebrewCounter(par->getCounter(i-4));
1745 s << alphaCounter(par->getCounter(i-4));
1748 << par->getCounter(i-3) << '.'
1749 << par->getCounter(i-2) << '.'
1750 << par->getCounter(i-1) << '.'
1751 << par->getCounter(i);
1754 case LABEL_COUNTER_SUBPARAGRAPH:
1755 if (par->isRightToLeftPar())
1756 s << hebrewCounter(par->getCounter(i-5));
1758 s << alphaCounter(par->getCounter(i-5));
1761 << par->getCounter(i-4) << '.'
1762 << par->getCounter(i-3) << '.'
1763 << par->getCounter(i-2) << '.'
1764 << par->getCounter(i-1) << '.'
1765 << par->getCounter(i);
1769 // Can this ever be reached? And in the
1770 // case it is, how can this be correct?
1772 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1778 par->labelstring += s.str().c_str();
1779 // We really want to remove the c_str as soon as
1783 char * tmps = s.str();
1784 par->labelstring += tmps;
1788 for (i++; i < 10; ++i) {
1789 // reset the following counters
1790 par->setCounter(i, 0);
1792 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1793 for (i++; i < 10; ++i) {
1794 // reset the following counters
1795 par->setCounter(i, 0);
1797 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1798 par->incCounter(i + par->enumdepth);
1799 int number = par->getCounter(i + par->enumdepth);
1802 std::ostringstream s;
1806 switch (par->enumdepth) {
1808 if (par->isRightToLeftPar())
1810 << hebrewCounter(number)
1814 << loweralphaCounter(number)
1818 if (par->isRightToLeftPar())
1819 s << '.' << romanCounter(number);
1821 s << romanCounter(number) << '.';
1824 if (par->isRightToLeftPar())
1826 << alphaCounter(number);
1828 s << alphaCounter(number)
1832 if (par->isRightToLeftPar())
1839 par->labelstring = s.str().c_str();
1840 // we really want to get rid of that c_str()
1843 char * tmps = s.str();
1844 par->labelstring = tmps;
1848 for (i += par->enumdepth + 1; i < 10; ++i)
1849 par->setCounter(i, 0); /* reset the following counters */
1852 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1853 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1855 int number = par->getCounter(i);
1857 par->bibkey = new InsetBibKey();
1858 par->bibkey->setCounter(number);
1859 par->labelstring = layout.labelstring();
1861 // In biblio should't be following counters but...
1863 string s = layout.labelstring();
1865 // the caption hack:
1867 if (layout.labeltype == LABEL_SENSITIVE) {
1868 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1869 && (par->footnotekind == LyXParagraph::FIG
1870 || par->footnotekind == LyXParagraph::WIDE_FIG))
1871 s = (par->getParLanguage()->lang == "hebrew")
1872 ? ":øåéà " : "Figure:";
1873 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1874 && (par->footnotekind == LyXParagraph::TAB
1875 || par->footnotekind == LyXParagraph::WIDE_TAB))
1876 s = (par->getParLanguage()->lang == "hebrew")
1877 ? ":äìáè" : "Table:";
1878 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1879 && par->footnotekind == LyXParagraph::ALGORITHM)
1880 s = (par->getParLanguage()->lang == "hebrew")
1881 ? ":Ãúéøåâìà " : "Algorithm:";
1883 /* par->SetLayout(0);
1884 s = layout->labelstring; */
1885 s = (par->getParLanguage()->lang == "hebrew")
1886 ? " :úåòîùî øñç" : "Senseless: ";
1889 par->labelstring = s;
1891 /* reset the enumeration counter. They are always resetted
1892 * when there is any other layout between */
1893 for (int i = 6 + par->enumdepth; i < 10; ++i)
1894 par->setCounter(i, 0);
1899 /* Updates all counters BEHIND the row. Changed paragraphs
1900 * with a dynamic left margin will be rebroken. */
1901 void LyXText::UpdateCounters(Row * row) const
1910 && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1911 par = row->par->LastPhysicalPar()->Next();
1913 par = row->par->next;
1918 while (row->par != par)
1923 /* now check for the headline layouts. remember that they
1924 * have a dynamic left margin */
1926 && ( textclasslist.Style(buffer->params.textclass,
1927 par->layout).margintype == MARGIN_DYNAMIC
1928 || textclasslist.Style(buffer->params.textclass,
1929 par->layout).labeltype == LABEL_SENSITIVE)
1932 /* Rebreak the paragraph */
1933 RemoveParagraph(row);
1934 AppendParagraph(row);
1936 /* think about the damned open footnotes! */
1937 while (par->Next() &&
1938 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1939 || par->Next()->IsDummy())){
1941 if (par->IsDummy()) {
1942 while (row->par != par)
1944 RemoveParagraph(row);
1945 AppendParagraph(row);
1950 par = par->LastPhysicalPar()->Next();
1956 /* insets an inset. */
1957 void LyXText::InsertInset(Inset *inset)
1959 if (!cursor.par->InsertInsetAllowed(inset))
1961 SetUndo(Undo::INSERT,
1962 cursor.par->ParFromPos(cursor.pos)->previous,
1963 cursor.par->ParFromPos(cursor.pos)->next);
1964 cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1965 cursor.par->InsertInset(cursor.pos, inset);
1966 InsertChar(LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
1967 * The character will not be inserted a
1972 #ifdef USE_OLD_CUT_AND_PASTE
1973 // this is for the simple cut and paste mechanism
1974 static LyXParagraph * simple_cut_buffer = 0;
1975 static char simple_cut_buffer_textclass = 0;
1977 void DeleteSimpleCutBuffer()
1979 if (!simple_cut_buffer)
1981 LyXParagraph * tmppar;
1983 while (simple_cut_buffer) {
1984 tmppar = simple_cut_buffer;
1985 simple_cut_buffer = simple_cut_buffer->next;
1988 simple_cut_buffer = 0;
1992 void LyXText::copyEnvironmentType()
1994 copylayouttype = cursor.par->GetLayout();
1998 void LyXText::pasteEnvironmentType()
2000 SetLayout(copylayouttype);
2003 #ifdef USE_OLD_CUT_AND_PASTE
2004 void LyXText::CutSelection(bool doclear)
2006 // This doesn't make sense, if there is no selection
2010 // OK, we have a selection. This is always between sel_start_cursor
2011 // and sel_end cursor
2012 LyXParagraph * tmppar;
2014 // Check whether there are half footnotes in the selection
2015 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2016 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2017 tmppar = sel_start_cursor.par;
2018 while (tmppar != sel_end_cursor.par){
2019 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
2020 WriteAlert(_("Impossible operation"),
2021 _("Don't know what to do with half floats."),
2025 tmppar = tmppar->Next();
2029 /* table stuff -- begin */
2030 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
2031 if ( sel_start_cursor.par != sel_end_cursor.par) {
2032 WriteAlert(_("Impossible operation"),
2033 _("Don't know what to do with half tables."),
2037 sel_start_cursor.par->table->Reinit();
2039 /* table stuff -- end */
2041 // make sure that the depth behind the selection are restored, too
2042 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
2043 LyXParagraph * undoendpar = endpar;
2045 if (endpar && endpar->GetDepth()) {
2046 while (endpar && endpar->GetDepth()) {
2047 endpar = endpar->LastPhysicalPar()->Next();
2048 undoendpar = endpar;
2050 } else if (endpar) {
2051 endpar = endpar->Next(); // because of parindents etc.
2054 SetUndo(Undo::DELETE,
2056 .par->ParFromPos(sel_start_cursor.pos)->previous,
2059 // clear the simple_cut_buffer
2060 DeleteSimpleCutBuffer();
2062 // set the textclass
2063 simple_cut_buffer_textclass = buffer->params.textclass;
2065 #ifdef WITH_WARNINGS
2066 #warning Asger: Make cut more intelligent here.
2069 White paper for "intelligent" cutting:
2071 Example: "This is our text."
2072 Using " our " as selection, cutting will give "This istext.".
2073 Using "our" as selection, cutting will give "This is text.".
2074 Using " our" as selection, cutting will give "This is text.".
2075 Using "our " as selection, cutting will give "This is text.".
2077 All those four selections will (however) paste identically:
2078 Pasting with the cursor right after the "is" will give the
2079 original text with all four selections.
2081 The rationale is to be intelligent such that words are copied,
2082 cut and pasted in a functional manner.
2084 This is not implemented yet. (Asger)
2086 The changes below sees to do a lot of what you want. However
2087 I have not verified that all cases work as they should:
2089 - cut in multiple row
2091 - cut across footnotes and paragraph
2092 My simplistic tests show that the idea are basically sound but
2093 there are some items to fix up...we only need to find them
2096 As do redo Asger's example above (with | beeing the cursor in the
2097 result after cutting.):
2099 Example: "This is our text."
2100 Using " our " as selection, cutting will give "This is|text.".
2101 Using "our" as selection, cutting will give "This is | text.".
2102 Using " our" as selection, cutting will give "This is| text.".
2103 Using "our " as selection, cutting will give "This is |text.".
2108 // there are two cases: cut only within one paragraph or
2109 // more than one paragraph
2111 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2112 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2113 // only within one paragraph
2114 simple_cut_buffer = new LyXParagraph;
2115 LyXParagraph::size_type i =
2116 sel_start_cursor.pos;
2117 for (; i < sel_end_cursor.pos; ++i) {
2118 /* table stuff -- begin */
2119 if (sel_start_cursor.par->table
2120 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)) {
2121 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2122 sel_start_cursor.pos++;
2124 /* table stuff -- end */
2125 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2126 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2128 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
2130 endpar = sel_end_cursor.par->Next();
2132 // cut more than one paragraph
2135 ->BreakParagraphConservative(sel_end_cursor.pos);
2136 sel_end_cursor.par = sel_end_cursor.par->Next();
2137 sel_end_cursor.pos = 0;
2139 cursor = sel_end_cursor;
2141 sel_start_cursor.par
2142 ->BreakParagraphConservative(sel_start_cursor.pos);
2143 // store the endparagraph for redoing later
2144 endpar = sel_end_cursor.par->Next(); /* needed because
2149 // store the selection
2150 simple_cut_buffer = sel_start_cursor.par
2151 ->ParFromPos(sel_start_cursor.pos)->next;
2152 simple_cut_buffer->previous = 0;
2153 sel_end_cursor.par->previous->next = 0;
2155 // cut the selection
2156 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
2157 = sel_end_cursor.par;
2159 sel_end_cursor.par->previous
2160 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2162 // care about footnotes
2163 if (simple_cut_buffer->footnoteflag) {
2164 LyXParagraph * tmppar = simple_cut_buffer;
2166 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2167 tmppar = tmppar->next;
2171 // the cut selection should begin with standard layout
2172 simple_cut_buffer->Clear();
2174 // paste the paragraphs again, if possible
2176 sel_start_cursor.par->Next()->ClearParagraph();
2177 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
2179 !sel_start_cursor.par->Next()->Last())
2180 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
2183 // sometimes necessary
2185 sel_start_cursor.par->ClearParagraph();
2187 RedoParagraphs(sel_start_cursor, endpar);
2190 cursor = sel_start_cursor;
2191 SetCursor(cursor.par, cursor.pos);
2192 sel_cursor = cursor;
2193 UpdateCounters(cursor.row);
2196 #else ///////////////////////////////////////////////////////////////////
2198 void LyXText::CutSelection(bool doclear)
2200 // This doesn't make sense, if there is no selection
2204 // OK, we have a selection. This is always between sel_start_cursor
2205 // and sel_end cursor
2206 LyXParagraph * tmppar;
2208 // Check whether there are half footnotes in the selection
2209 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2210 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2211 tmppar = sel_start_cursor.par;
2212 while (tmppar != sel_end_cursor.par){
2213 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
2214 WriteAlert(_("Impossible operation"),
2215 _("Don't know what to do with half floats."),
2219 tmppar = tmppar->Next();
2223 /* table stuff -- begin */
2224 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
2225 if ( sel_start_cursor.par != sel_end_cursor.par) {
2226 WriteAlert(_("Impossible operation"),
2227 _("Don't know what to do with half tables."),
2231 sel_start_cursor.par->table->Reinit();
2233 /* table stuff -- end */
2235 // make sure that the depth behind the selection are restored, too
2236 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
2237 LyXParagraph * undoendpar = endpar;
2239 if (endpar && endpar->GetDepth()) {
2240 while (endpar && endpar->GetDepth()) {
2241 endpar = endpar->LastPhysicalPar()->Next();
2242 undoendpar = endpar;
2244 } else if (endpar) {
2245 endpar = endpar->Next(); // because of parindents etc.
2248 SetUndo(Undo::DELETE, sel_start_cursor
2249 .par->ParFromPos(sel_start_cursor.pos)->previous, undoendpar);
2253 // there are two cases: cut only within one paragraph or
2254 // more than one paragraph
2255 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2256 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2257 // only within one paragraph
2258 endpar = sel_start_cursor.par;
2259 cap.cutSelection(sel_start_cursor.par, &endpar,
2260 sel_start_cursor.pos, sel_end_cursor.pos,
2261 buffer->params.textclass, doclear);
2263 endpar = sel_end_cursor.par;
2265 cap.cutSelection(sel_start_cursor.par, &endpar,
2266 sel_start_cursor.pos, sel_end_cursor.pos,
2267 buffer->params.textclass, doclear);
2268 cursor.par = sel_end_cursor.par = endpar;
2269 cursor.pos = sel_end_cursor.pos;
2271 endpar = endpar->Next();
2273 // sometimes necessary
2275 sel_start_cursor.par->ClearParagraph();
2277 RedoParagraphs(sel_start_cursor, endpar);
2280 cursor = sel_start_cursor;
2281 SetCursor(cursor.par, cursor.pos);
2282 sel_cursor = cursor;
2283 UpdateCounters(cursor.row);
2287 #ifdef USE_OLD_CUT_AND_PASTE
2288 void LyXText::CopySelection()
2290 // this doesnt make sense, if there is no selection
2294 // ok we have a selection. This is always between sel_start_cursor
2295 // and sel_end cursor
2296 LyXParagraph * tmppar;
2298 /* check wether there are half footnotes in the selection */
2299 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2300 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2301 tmppar = sel_start_cursor.par;
2302 while (tmppar != sel_end_cursor.par) {
2303 if (tmppar->footnoteflag !=
2304 sel_end_cursor.par->footnoteflag) {
2305 WriteAlert(_("Impossible operation"),
2306 _("Don't know what to do"
2307 " with half floats."),
2311 tmppar = tmppar->Next();
2315 /* table stuff -- begin */
2316 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2317 if ( sel_start_cursor.par != sel_end_cursor.par){
2318 WriteAlert(_("Impossible operation"),
2319 _("Don't know what to do with half tables."),
2324 /* table stuff -- end */
2326 // delete the simple_cut_buffer
2327 DeleteSimpleCutBuffer();
2329 // set the textclass
2330 simple_cut_buffer_textclass = buffer->params.textclass;
2332 // copy behind a space if there is one
2333 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2334 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2335 && (sel_start_cursor.par != sel_end_cursor.par
2336 || sel_start_cursor.pos < sel_end_cursor.pos))
2337 sel_start_cursor.pos++;
2339 // there are two cases: copy only within one paragraph
2340 // or more than one paragraph
2341 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2342 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2343 // only within one paragraph
2344 simple_cut_buffer = new LyXParagraph;
2345 LyXParagraph::size_type i = 0;
2346 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2347 sel_start_cursor.par->CopyIntoMinibuffer(i);
2348 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2351 // copy more than one paragraph
2352 // clone the paragraphs within the selection
2354 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2355 simple_cut_buffer = tmppar->Clone();
2356 LyXParagraph *tmppar2 = simple_cut_buffer;
2358 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2360 tmppar = tmppar->next;
2361 tmppar2->next = tmppar->Clone();
2362 tmppar2->next->previous = tmppar2;
2363 tmppar2 = tmppar2->next;
2367 // care about footnotes
2368 if (simple_cut_buffer->footnoteflag) {
2369 tmppar = simple_cut_buffer;
2371 tmppar->footnoteflag =
2372 LyXParagraph::NO_FOOTNOTE;
2373 tmppar = tmppar->next;
2377 // the simple_cut_buffer paragraph is too big
2378 LyXParagraph::size_type tmpi2 =
2379 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2380 for (; tmpi2; --tmpi2)
2381 simple_cut_buffer->Erase(0);
2383 // now tmppar 2 is too big, delete all after sel_end_cursor.pos
2385 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2386 while (tmppar2->size() > tmpi2) {
2387 tmppar2->Erase(tmppar2->size() - 1);
2392 #else //////////////////////////////////////////////////////////////////////
2394 void LyXText::CopySelection()
2396 // this doesnt make sense, if there is no selection
2400 // ok we have a selection. This is always between sel_start_cursor
2401 // and sel_end cursor
2402 LyXParagraph * tmppar;
2404 /* check wether there are half footnotes in the selection */
2405 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2406 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2407 tmppar = sel_start_cursor.par;
2408 while (tmppar != sel_end_cursor.par) {
2409 if (tmppar->footnoteflag !=
2410 sel_end_cursor.par->footnoteflag) {
2411 WriteAlert(_("Impossible operation"),
2412 _("Don't know what to do"
2413 " with half floats."),
2417 tmppar = tmppar->Next();
2421 /* table stuff -- begin */
2422 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2423 if ( sel_start_cursor.par != sel_end_cursor.par){
2424 WriteAlert(_("Impossible operation"),
2425 _("Don't know what to do with half tables."),
2430 /* table stuff -- end */
2432 // copy behind a space if there is one
2433 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2434 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2435 && (sel_start_cursor.par != sel_end_cursor.par
2436 || sel_start_cursor.pos < sel_end_cursor.pos))
2437 sel_start_cursor.pos++;
2441 cap.copySelection(sel_start_cursor.par, sel_end_cursor.par,
2442 sel_start_cursor.pos, sel_end_cursor.pos,
2443 buffer->params.textclass);
2447 #ifdef USE_OLD_CUT_AND_PASTE
2448 void LyXText::PasteSelection()
2450 // this does not make sense, if there is nothing to paste
2451 if (!simple_cut_buffer)
2454 LyXParagraph * tmppar;
2455 LyXParagraph * endpar;
2457 LyXCursor tmpcursor;
2459 // be carefull with footnotes in footnotes
2460 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2462 // check whether the cut_buffer includes a footnote
2463 tmppar = simple_cut_buffer;
2465 && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2466 tmppar = tmppar->next;
2469 WriteAlert(_("Impossible operation"),
2470 _("Can't paste float into float!"),
2476 /* table stuff -- begin */
2477 if (cursor.par->table) {
2478 if (simple_cut_buffer->next) {
2479 WriteAlert(_("Impossible operation"),
2480 _("Table cell cannot include more than one paragraph!"),
2485 /* table stuff -- end */
2487 SetUndo(Undo::INSERT,
2488 cursor.par->ParFromPos(cursor.pos)->previous,
2489 cursor.par->ParFromPos(cursor.pos)->next);
2493 // There are two cases: cutbuffer only one paragraph or many
2494 if (!simple_cut_buffer->next) {
2495 // only within a paragraph
2497 tmppar = simple_cut_buffer->Clone();
2498 /* table stuff -- begin */
2499 bool table_too_small = false;
2500 if (tmpcursor.par->table) {
2501 while (simple_cut_buffer->size()
2502 && !table_too_small) {
2503 if (simple_cut_buffer->IsNewline(0)){
2504 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2506 simple_cut_buffer->Erase(0);
2507 if (tmpcursor.pos < tmpcursor.par->Last())
2510 table_too_small = true;
2512 // This is an attempt to fix the
2513 // "never insert a space at the
2514 // beginning of a paragraph" problem.
2515 if (tmpcursor.pos == 0
2516 && simple_cut_buffer->IsLineSeparator(0)) {
2517 simple_cut_buffer->Erase(0);
2519 simple_cut_buffer->CutIntoMinibuffer(0);
2520 simple_cut_buffer->Erase(0);
2521 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2527 /* table stuff -- end */
2528 // Some provisions should be done here for checking
2529 // if we are inserting at the beginning of a
2530 // paragraph. If there are a space at the beginning
2531 // of the text to insert and we are inserting at
2532 // the beginning of the paragraph the space should
2534 while (simple_cut_buffer->size()) {
2535 // This is an attempt to fix the
2536 // "never insert a space at the
2537 // beginning of a paragraph" problem.
2538 if (tmpcursor.pos == 0
2539 && simple_cut_buffer->IsLineSeparator(0)) {
2540 simple_cut_buffer->Erase(0);
2542 simple_cut_buffer->CutIntoMinibuffer(0);
2543 simple_cut_buffer->Erase(0);
2544 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2549 delete simple_cut_buffer;
2550 simple_cut_buffer = tmppar;
2551 endpar = tmpcursor.par->Next();
2556 // make a copy of the simple cut_buffer
2557 tmppar = simple_cut_buffer;
2558 LyXParagraph * simple_cut_clone = tmppar->Clone();
2559 LyXParagraph * tmppar2 = simple_cut_clone;
2560 if (cursor.par->footnoteflag){
2561 tmppar->footnoteflag = cursor.par->footnoteflag;
2562 tmppar->footnotekind = cursor.par->footnotekind;
2564 while (tmppar->next) {
2565 tmppar = tmppar->next;
2566 tmppar2->next = tmppar->Clone();
2567 tmppar2->next->previous = tmppar2;
2568 tmppar2 = tmppar2->next;
2569 if (cursor.par->footnoteflag){
2570 tmppar->footnoteflag = cursor.par->footnoteflag;
2571 tmppar->footnotekind = cursor.par->footnotekind;
2575 // make sure there is no class difference
2576 cap.SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2577 buffer->params.textclass,
2580 // make the simple_cut_buffer exactly the same layout than
2581 // the cursor paragraph
2582 simple_cut_buffer->MakeSameLayout(cursor.par);
2584 // find the end of the buffer
2585 LyXParagraph * lastbuffer = simple_cut_buffer;
2586 while (lastbuffer->Next())
2587 lastbuffer = lastbuffer->Next();
2589 bool paste_the_end = false;
2591 // open the paragraph for inserting the simple_cut_buffer
2593 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2594 cursor.par->BreakParagraphConservative(cursor.pos);
2595 paste_the_end = true;
2598 // set the end for redoing later
2599 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2602 lastbuffer->ParFromPos(lastbuffer->Last())->next =
2603 cursor.par->ParFromPos(cursor.pos)->next;
2604 cursor.par->ParFromPos(cursor.pos)->next->previous =
2605 lastbuffer->ParFromPos(lastbuffer->Last());
2607 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2608 simple_cut_buffer->previous =
2609 cursor.par->ParFromPos(cursor.pos);
2611 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2612 lastbuffer = cursor.par;
2614 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2616 // store the new cursor position
2617 tmpcursor.par = lastbuffer;
2618 tmpcursor.pos = lastbuffer->Last();
2620 // maybe some pasting
2621 if (lastbuffer->Next() && paste_the_end) {
2622 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2623 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2625 } else if (!lastbuffer->Next()->Last()) {
2626 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2627 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2629 } else if (!lastbuffer->Last()) {
2630 lastbuffer->MakeSameLayout(lastbuffer->next);
2631 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2634 lastbuffer->Next()->ClearParagraph();
2637 // restore the simple cut buffer
2638 simple_cut_buffer = simple_cut_clone;
2641 RedoParagraphs(cursor, endpar);
2643 SetCursor(cursor.par, cursor.pos);
2646 sel_cursor = cursor;
2647 SetCursor(tmpcursor.par, tmpcursor.pos);
2649 UpdateCounters(cursor.row);
2652 #else ////////////////////////////////////////////////////////////////////
2654 void LyXText::PasteSelection()
2658 // this does not make sense, if there is nothing to paste
2659 if (!cap.checkPastePossible(cursor.par, cursor.pos))
2662 SetUndo(Undo::INSERT,
2663 cursor.par->ParFromPos(cursor.pos)->previous,
2664 cursor.par->ParFromPos(cursor.pos)->next);
2666 LyXParagraph *endpar;
2667 LyXParagraph *actpar = cursor.par;
2668 int endpos = cursor.pos;
2670 cap.pasteSelection(&actpar, &endpar, endpos, buffer->params.textclass);
2672 RedoParagraphs(cursor, endpar);
2674 SetCursor(cursor.par, cursor.pos);
2677 sel_cursor = cursor;
2678 SetCursor(actpar, endpos);
2680 UpdateCounters(cursor.row);
2684 // returns a pointer to the very first LyXParagraph
2685 LyXParagraph * LyXText::FirstParagraph() const
2687 return buffer->paragraph;
2691 // returns true if the specified string is at the specified position
2692 bool LyXText::IsStringInText(LyXParagraph * par,
2693 LyXParagraph::size_type pos,
2694 char const * str) const
2698 while (pos + i < par->Last() && str[i] &&
2699 str[i] == par->GetChar(pos + i)) {
2709 // sets the selection over the number of characters of string, no check!!
2710 void LyXText::SetSelectionOverString(char const * string)
2712 sel_cursor = cursor;
2713 for (int i = 0; string[i]; ++i)
2719 // simple replacing. The font of the first selected character is used
2720 void LyXText::ReplaceSelectionWithString(char const * str)
2725 if (!selection) { // create a dummy selection
2726 sel_end_cursor = cursor;
2727 sel_start_cursor = cursor;
2730 // Get font setting before we cut
2731 LyXParagraph::size_type pos = sel_end_cursor.pos;
2732 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2734 // Insert the new string
2735 for (int i = 0; str[i]; ++i) {
2736 sel_end_cursor.par->InsertChar(pos, str[i]);
2737 sel_end_cursor.par->SetFont(pos, font);
2741 // Cut the selection
2748 // if the string can be found: return true and set the cursor to
2750 bool LyXText::SearchForward(char const * str) const
2752 LyXParagraph * par = cursor.par;
2753 LyXParagraph::size_type pos = cursor.pos;
2754 while (par && !IsStringInText(par, pos, str)) {
2755 if (pos < par->Last() - 1)
2763 SetCursor(par, pos);
2771 bool LyXText::SearchBackward(char const * string) const
2773 LyXParagraph * par = cursor.par;
2774 int pos = cursor.pos;
2780 // We skip empty paragraphs (Asger)
2782 par = par->Previous();
2784 pos = par->Last() - 1;
2785 } while (par && pos < 0);
2787 } while (par && !IsStringInText(par, pos, string));
2790 SetCursor(par, pos);
2797 // needed to insert the selection
2798 void LyXText::InsertStringA(string const & str)
2800 LyXParagraph * par = cursor.par;
2801 LyXParagraph::size_type pos = cursor.pos;
2802 LyXParagraph::size_type a = 0;
2804 LyXParagraph * endpar = cursor.par->Next();
2809 textclasslist.Style(buffer->params.textclass,
2810 cursor.par->GetLayout()).isEnvironment();
2811 // only to be sure, should not be neccessary
2814 // insert the string, don't insert doublespace
2815 string::size_type i = 0;
2816 while (i < str.length()) {
2817 if (str[i] != '\n') {
2819 && i + 1 < str.length() && str[i + 1] != ' '
2820 && pos && par->GetChar(pos - 1)!= ' ') {
2821 par->InsertChar(pos,' ');
2822 par->SetFont(pos, current_font);
2824 } else if (par->table) {
2825 if (str[i] == '\t') {
2826 while((pos < par->size()) &&
2827 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2829 if (pos < par->size())
2831 else // no more fields to fill skip the rest
2833 } else if ((str[i] != 13) &&
2834 ((str[i] & 127) >= ' ')) {
2835 par->InsertChar(pos, str[i]);
2836 par->SetFont(pos, current_font);
2839 } else if (str[i] == ' ') {
2840 InsetSpecialChar * new_inset =
2841 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2842 if (par->InsertInsetAllowed(new_inset)) {
2843 par->InsertChar(pos, LyXParagraph::META_INSET);
2844 par->SetFont(pos, current_font);
2845 par->InsertInset(pos, new_inset);
2850 } else if (str[i] == '\t') {
2851 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2852 InsetSpecialChar * new_inset =
2853 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2854 if (par->InsertInsetAllowed(new_inset)) {
2855 par->InsertChar(pos, LyXParagraph::META_INSET);
2856 par->SetFont(pos, current_font);
2857 par->InsertInset(pos, new_inset);
2863 } else if (str[i] != 13 &&
2864 // Ignore unprintables
2865 (str[i] & 127) >= ' ') {
2866 par->InsertChar(pos, str[i]);
2867 par->SetFont(pos, current_font);
2872 if (i + 1 >= str.length()) {
2876 while((pos < par->size()) &&
2877 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2880 cell = NumberOfCell(par, pos);
2881 while((pos < par->size()) &&
2882 !(par->table->IsFirstCell(cell))) {
2884 while((pos < par->size()) &&
2885 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2888 cell = NumberOfCell(par, pos);
2890 if (pos >= par->size())
2891 // no more fields to fill skip the rest
2894 if (!par->size()) { // par is empty
2895 InsetSpecialChar * new_inset =
2896 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2897 if (par->InsertInsetAllowed(new_inset)) {
2898 par->InsertChar(pos, LyXParagraph::META_INSET);
2899 par->SetFont(pos, current_font);
2900 par->InsertInset(pos, new_inset);
2906 par->BreakParagraph(pos, flag);
2914 RedoParagraphs(cursor, endpar);
2915 SetCursor(cursor.par, cursor.pos);
2916 sel_cursor = cursor;
2917 SetCursor(par, pos);
2922 /* turns double-CR to single CR, others where converted into one blank and 13s
2923 * that are ignored .Double spaces are also converted into one. Spaces at
2924 * the beginning of a paragraph are forbidden. tabs are converted into one
2925 * space. then InsertStringA is called */
2926 void LyXText::InsertStringB(string const & s)
2929 LyXParagraph * par = cursor.par;
2930 string::size_type i = 1;
2931 while (i < str.length()) {
2932 if (str[i] == '\t' && !par->table)
2934 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2936 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2937 if (str[i + 1] != '\n') {
2938 if (str[i - 1] != ' ')
2943 while (i + 1 < str.length()
2944 && (str[i + 1] == ' '
2945 || str[i + 1] == '\t'
2946 || str[i + 1] == '\n'
2947 || str[i + 1] == 13)) {
2958 bool LyXText::GotoNextError() const
2960 LyXCursor res = cursor;
2962 if (res.pos < res.par->Last() - 1) {
2966 res.par = res.par->Next();
2971 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2972 && res.par->GetInset(res.pos)->AutoDelete()));
2975 SetCursor(res.par, res.pos);
2982 bool LyXText::GotoNextNote() const
2984 LyXCursor res = cursor;
2986 if (res.pos < res.par->Last() - 1) {
2989 res.par = res.par->Next();
2994 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2995 && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
2998 SetCursor(res.par, res.pos);
3005 void LyXText::CheckParagraph(LyXParagraph * par,
3006 LyXParagraph::size_type pos)
3008 LyXCursor tmpcursor;
3011 /* table stuff -- begin*/
3014 CheckParagraphInTable(par, pos);
3017 /* table stuff -- end*/
3020 LyXParagraph::size_type z;
3021 Row * row = GetRow(par, pos, y);
3023 // is there a break one row above
3024 if (row->previous && row->previous->par == row->par) {
3025 z = NextBreakPoint(row->previous, paperwidth);
3026 if ( z >= row->pos) {
3027 // set the dimensions of the row above
3028 y -= row->previous->height;
3030 refresh_row = row->previous;
3031 status = LyXText::NEED_MORE_REFRESH;
3033 BreakAgain(row->previous);
3035 // set the cursor again. Otherwise
3036 // dangling pointers are possible
3037 SetCursor(cursor.par, cursor.pos);
3038 sel_cursor = cursor;
3043 int tmpheight = row->height;
3044 LyXParagraph::size_type tmplast = RowLast(row);
3049 if (row->height == tmpheight && RowLast(row) == tmplast)
3050 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3052 status = LyXText::NEED_MORE_REFRESH;
3054 // check the special right address boxes
3055 if (textclasslist.Style(buffer->params.textclass,
3056 par->GetLayout()).margintype
3057 == MARGIN_RIGHT_ADDRESS_BOX) {
3058 tmpcursor.par = par;
3059 tmpcursor.row = row;
3062 tmpcursor.x_fix = 0;
3063 tmpcursor.pos = pos;
3064 RedoDrawingOfParagraph(tmpcursor);
3069 // set the cursor again. Otherwise dangling pointers are possible
3070 // also set the selection
3074 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
3075 sel_cursor = cursor;
3076 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
3077 sel_start_cursor = cursor;
3078 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
3079 sel_end_cursor = cursor;
3080 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
3081 last_sel_cursor = cursor;
3084 SetCursorIntern(cursor.par, cursor.pos);
3088 // returns 0 if inset wasn't found
3089 int LyXText::UpdateInset(Inset * inset)
3091 // first check the current paragraph
3092 int pos = cursor.par->GetPositionOfInset(inset);
3094 CheckParagraph(cursor.par, pos);
3098 // check every paragraph
3100 LyXParagraph * par = FirstParagraph();
3102 // make sure the paragraph is open
3103 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
3104 pos = par->GetPositionOfInset(inset);
3106 CheckParagraph(par, pos);
3117 void LyXText::SetCursor(LyXParagraph * par,
3118 LyXParagraph::size_type pos, bool setfont) const
3120 LyXCursor old_cursor = cursor;
3121 SetCursorIntern(par, pos, setfont);
3122 DeleteEmptyParagraphMechanism(old_cursor);
3126 void LyXText::SetCursor(LyXCursor & cur, LyXParagraph * par,
3127 LyXParagraph::size_type pos) const
3129 // correct the cursor position if impossible
3130 if (pos > par->Last()){
3131 LyXParagraph * tmppar = par->ParFromPos(pos);
3132 pos = par->PositionInParFromPos(pos);
3135 if (par->IsDummy() && par->previous &&
3136 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3137 while (par->previous &&
3138 ((par->previous->IsDummy() &&
3139 (par->previous->previous->footnoteflag ==
3140 LyXParagraph::CLOSED_FOOTNOTE)) ||
3141 (par->previous->footnoteflag ==
3142 LyXParagraph::CLOSED_FOOTNOTE))) {
3143 par = par->previous ;
3144 if (par->IsDummy() &&
3145 (par->previous->footnoteflag ==
3146 LyXParagraph::CLOSED_FOOTNOTE))
3147 pos += par->size() + 1;
3149 if (par->previous) {
3150 par = par->previous;
3152 pos += par->size() + 1;
3158 /* get the cursor y position in text */
3160 Row * row = GetRow(par, pos, y);
3161 /* y is now the beginning of the cursor row */
3163 /* y is now the cursor baseline */
3166 /* now get the cursors x position */
3168 float fill_separator, fill_hfill, fill_label_hfill;
3169 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3170 LyXParagraph::size_type cursor_vpos;
3171 LyXParagraph::size_type last = RowLastPrintable(row);
3173 if (pos > last + 1) // This shouldn't happen.
3176 if (last < row->pos)
3178 else if ((pos > last) ||
3179 ((pos - 1 >= row->pos) &&
3180 (row->par->IsSeparator(pos) ||
3181 (row->par->table && row->par->IsNewline(pos)))))
3182 /// Place cursor after char at (logical) position pos-1
3183 cursor_vpos = !(bidi_level(pos-1) % 2)
3184 ? log2vis(pos-1) + 1 : log2vis(pos-1);
3186 /// Place cursor before char at (logical) position pos
3187 cursor_vpos = !(bidi_level(pos) % 2)
3188 ? log2vis(pos) : log2vis(pos) + 1;
3190 /* table stuff -- begin*/
3191 if (row->par->table) {
3192 int cell = NumberOfCell(row->par, row->pos);
3194 x += row->par->table->GetBeginningOfTextInCell(cell);
3195 for (LyXParagraph::size_type vpos = row->pos;
3196 vpos < cursor_vpos; ++vpos) {
3197 pos = vis2log(vpos);
3198 if (row->par->IsNewline(pos)) {
3199 x = x_old + row->par->table->WidthOfColumn(cell);
3202 x += row->par->table->GetBeginningOfTextInCell(cell);
3204 x += SingleWidth(row->par, pos);
3208 /* table stuff -- end*/
3209 LyXParagraph::size_type main_body =
3210 BeginningOfMainBody(row->par);
3211 if ((main_body > 0) &&
3212 ((main_body-1 > last) ||
3213 !row->par->IsLineSeparator(main_body-1)))
3216 for (LyXParagraph::size_type vpos = row->pos;
3217 vpos < cursor_vpos; ++vpos) {
3218 pos = vis2log(vpos);
3219 if (main_body > 0 && pos == main_body-1) {
3220 x += fill_label_hfill +
3221 lyxfont::width(textclasslist.Style(
3222 buffer->params.textclass,
3223 row->par->GetLayout())
3225 GetFont(row->par, -2));
3226 if (row->par->IsLineSeparator(main_body-1))
3227 x -= SingleWidth(row->par,main_body-1);
3229 if (HfillExpansion(row, pos)) {
3230 x += SingleWidth(row->par, pos);
3231 if (pos >= main_body)
3234 x += fill_label_hfill;
3235 } else if (row->par->IsSeparator(pos)) {
3236 x += SingleWidth(row->par, pos);
3237 if (pos >= main_body)
3238 x += fill_separator;
3240 x += SingleWidth(row->par, pos);
3250 void LyXText::SetCursorIntern(LyXParagraph * par,
3251 LyXParagraph::size_type pos, bool setfont) const
3253 SetCursor(cursor, par, pos);
3254 // #warning Remove this when verified working (Jug 20000413)
3256 // correct the cursor position if impossible
3257 if (pos > par->Last()){
3258 LyXParagraph * tmppar = par->ParFromPos(pos);
3259 pos = par->PositionInParFromPos(pos);
3262 if (par->IsDummy() && par->previous &&
3263 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3264 while (par->previous &&
3265 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
3266 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
3267 par = par->previous ;
3268 if (par->IsDummy() &&
3269 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3270 pos += par->size() + 1;
3272 if (par->previous) {
3273 par = par->previous;
3275 pos += par->size() + 1;
3281 /* get the cursor y position in text */
3283 Row * row = GetRow(par, pos, y);
3284 /* y is now the beginning of the cursor row */
3286 /* y is now the cursor baseline */
3289 /* now get the cursors x position */
3291 float fill_separator, fill_hfill, fill_label_hfill;
3292 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3293 LyXParagraph::size_type cursor_vpos;
3294 LyXParagraph::size_type last = RowLastPrintable(row);
3296 if (pos > last + 1) // This shouldn't happen.
3299 if (last < row->pos)
3301 else if (pos > last ||
3302 (pos - 1 >= row->pos &&
3303 (row->par->IsSeparator(pos) ||
3304 (row->par->table && row->par->IsNewline(pos))
3306 /// Place cursor after char at (logical) position pos-1
3307 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
3308 ? log2vis(pos-1) + 1 : log2vis(pos-1);
3310 /// Place cursor before char at (logical) position pos
3311 cursor_vpos = (bidi_level(pos) % 2 == 0)
3312 ? log2vis(pos) : log2vis(pos) + 1;
3314 /* table stuff -- begin*/
3315 if (row->par->table) {
3316 int cell = NumberOfCell(row->par, row->pos);
3318 x += row->par->table->GetBeginningOfTextInCell(cell);
3319 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3320 pos = vis2log(vpos);
3321 if (row->par->IsNewline(pos)) {
3322 x = x_old + row->par->table->WidthOfColumn(cell);
3325 x += row->par->table->GetBeginningOfTextInCell(cell);
3327 x += SingleWidth(row->par, pos);
3331 /* table stuff -- end*/
3332 LyXParagraph::size_type main_body =
3333 BeginningOfMainBody(row->par);
3334 if (main_body > 0 &&
3335 (main_body-1 > last ||
3336 !row->par->IsLineSeparator(main_body-1)))
3339 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3340 pos = vis2log(vpos);
3341 if (main_body > 0 && pos == main_body-1) {
3342 x += fill_label_hfill +
3343 lyxfont::width(textclasslist
3344 .Style(buffer->params.textclass,
3345 row->par->GetLayout())
3347 GetFont(row->par, -2));
3348 if (row->par->IsLineSeparator(main_body-1))
3349 x -= SingleWidth(row->par, main_body-1);
3351 if (HfillExpansion(row, pos)) {
3352 x += SingleWidth(row->par, pos);
3353 if (pos >= main_body)
3356 x += fill_label_hfill;
3358 else if (row->par->IsSeparator(pos)) {
3359 x += SingleWidth(row->par, pos);
3360 if (pos >= main_body)
3361 x += fill_separator;
3363 x += SingleWidth(row->par, pos);
3369 cursor.x_fix = cursor.x;
3374 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
3375 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3377 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3378 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3380 current_font = cursor.par->GetFontSettings(cursor.pos);
3381 real_current_font = GetFont(cursor.par, cursor.pos);
3387 void LyXText::SetCursorFromCoordinates(int x, long y) const
3389 LyXCursor old_cursor = cursor;
3391 /* get the row first */
3393 Row * row = GetRowNearY(y);
3395 cursor.par = row->par;
3397 int column = GetColumnNearX(row, x);
3398 cursor.pos = row->pos + column;
3400 cursor.y = y + row->baseline;
3405 (cursor.pos == cursor.par->Last()
3406 || cursor.par->IsSeparator(cursor.pos)
3407 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3408 && !cursor.par->IsSeparator(cursor.pos))
3409 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3411 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3412 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3414 current_font = cursor.par->GetFontSettings(cursor.pos);
3415 real_current_font = GetFont(cursor.par, cursor.pos);
3417 DeleteEmptyParagraphMechanism(old_cursor);
3420 void LyXText::SetCursorFromCoordinates(LyXCursor & cur, int x, long y) const
3422 /* get the row first */
3424 Row * row = GetRowNearY(y);
3425 int column = GetColumnNearX(row, x);
3428 cur.pos = row->pos + column;
3430 cur.y = y + row->baseline;
3435 void LyXText::CursorLeft() const
3438 if (cursor.par->table) {
3439 int cell = NumberOfCell(cursor.par, cursor.pos);
3440 if (cursor.par->table->IsContRow(cell) &&
3441 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell)) < 0) {
3448 void LyXText::CursorLeftIntern() const
3450 if (cursor.pos > 0) {
3451 SetCursor(cursor.par, cursor.pos - 1);
3453 else if (cursor.par->Previous()) { // steps into the above paragraph.
3454 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3459 void LyXText::CursorRight() const
3461 CursorRightIntern();
3462 if (cursor.par->table) {
3463 int cell = NumberOfCell(cursor.par, cursor.pos);
3464 if (cursor.par->table->IsContRow(cell) &&
3465 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3472 void LyXText::CursorRightIntern() const
3474 if (cursor.pos < cursor.par->Last()) {
3475 SetCursor(cursor.par, cursor.pos + 1);
3477 else if (cursor.par->Next()) {
3478 SetCursor(cursor.par->Next(), 0);
3483 void LyXText::CursorUp() const
3485 SetCursorFromCoordinates(cursor.x_fix,
3486 cursor.y - cursor.row->baseline - 1);
3487 if (cursor.par->table) {
3488 int cell = NumberOfCell(cursor.par, cursor.pos);
3489 if (cursor.par->table->IsContRow(cell) &&
3490 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3497 void LyXText::CursorDown() const
3499 if (cursor.par->table &&
3500 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3503 SetCursorFromCoordinates(cursor.x_fix,
3504 cursor.y - cursor.row->baseline
3505 + cursor.row->height + 1);
3506 if (cursor.par->table) {
3507 int cell = NumberOfCell(cursor.par, cursor.pos);
3508 int cell_above = cursor.par->table->GetCellAbove(cell);
3509 while(cursor.par->table &&
3510 cursor.par->table->IsContRow(cell) &&
3511 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3512 SetCursorFromCoordinates(cursor.x_fix,
3513 cursor.y - cursor.row->baseline
3514 + cursor.row->height + 1);
3515 if (cursor.par->table) {
3516 cell = NumberOfCell(cursor.par, cursor.pos);
3517 cell_above = cursor.par->table->GetCellAbove(cell);
3524 void LyXText::CursorUpParagraph() const
3526 if (cursor.pos > 0) {
3527 SetCursor(cursor.par, 0);
3529 else if (cursor.par->Previous()) {
3530 SetCursor(cursor.par->Previous(), 0);
3535 void LyXText::CursorDownParagraph() const
3537 if (cursor.par->Next()) {
3538 SetCursor(cursor.par->Next(), 0);
3540 SetCursor(cursor.par, cursor.par->Last());
3546 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3548 // Would be wrong to delete anything if we have a selection.
3549 if (selection) return;
3551 // We allow all kinds of "mumbo-jumbo" when freespacing.
3552 if (textclasslist.Style(buffer->params.textclass,
3553 old_cursor.par->GetLayout()).free_spacing)
3556 bool deleted = false;
3558 /* Ok I'll put some comments here about what is missing.
3559 I have fixed BackSpace (and thus Delete) to not delete
3560 double-spaces automagically. I have also changed Cut,
3561 Copy and Paste to hopefully do some sensible things.
3562 There are still some small problems that can lead to
3563 double spaces stored in the document file or space at
3564 the beginning of paragraphs. This happens if you have
3565 the cursor betwenn to spaces and then save. Or if you
3566 cut and paste and the selection have a space at the
3567 beginning and then save right after the paste. I am
3568 sure none of these are very hard to fix, but I will
3569 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3570 that I can get some feedback. (Lgb)
3573 // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3574 // delete the LineSeparator.
3577 // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3578 // delete the LineSeparator.
3581 // If the pos around the old_cursor were spaces, delete one of them.
3582 if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) { // Only if the cursor has really moved
3584 if (old_cursor.pos > 0
3585 && old_cursor.pos < old_cursor.par->Last()
3586 && old_cursor.par->IsLineSeparator(old_cursor.pos)
3587 && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3588 old_cursor.par->Erase(old_cursor.pos - 1);
3589 RedoParagraphs(old_cursor, old_cursor.par->Next());
3591 if (old_cursor.par == cursor.par &&
3592 cursor.pos > old_cursor.pos) {
3593 SetCursorIntern(cursor.par, cursor.pos - 1);
3595 SetCursorIntern(cursor.par, cursor.pos);
3600 // Do not delete empty paragraphs with keepempty set.
3601 if ((textclasslist.Style(buffer->params.textclass,
3602 old_cursor.par->GetLayout())).keepempty)
3605 LyXCursor tmpcursor;
3607 if (old_cursor.par != cursor.par) {
3608 if ( (old_cursor.par->Last() == 0
3609 || (old_cursor.par->Last() == 1
3610 && old_cursor.par->IsLineSeparator(0)))
3611 && old_cursor.par->FirstPhysicalPar()
3612 == old_cursor.par->LastPhysicalPar()) {
3613 // ok, we will delete anything
3615 // make sure that you do not delete any environments
3616 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3617 !(old_cursor.row->previous
3618 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3619 && !(old_cursor.row->next
3620 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3621 || (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3622 && ((old_cursor.row->previous
3623 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3624 || (old_cursor.row->next
3625 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3627 status = LyXText::NEED_MORE_REFRESH;
3630 if (old_cursor.row->previous) {
3631 refresh_row = old_cursor.row->previous;
3632 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3634 cursor = old_cursor; // that undo can restore the right cursor position
3635 LyXParagraph * endpar = old_cursor.par->next;
3636 if (endpar && endpar->GetDepth()) {
3637 while (endpar && endpar->GetDepth()) {
3638 endpar = endpar->LastPhysicalPar()->Next();
3641 SetUndo(Undo::DELETE,
3642 old_cursor.par->previous,
3647 RemoveRow(old_cursor.row);
3648 if (buffer->paragraph == old_cursor.par) {
3649 buffer->paragraph = buffer->paragraph->next;
3652 delete old_cursor.par;
3654 /* Breakagain the next par. Needed
3655 * because of the parindent that
3656 * can occur or dissappear. The
3657 * next row can change its height,
3658 * if there is another layout before */
3659 if (refresh_row->next) {
3660 BreakAgain(refresh_row->next);
3661 UpdateCounters(refresh_row);
3663 SetHeightOfRow(refresh_row);
3665 refresh_row = old_cursor.row->next;
3666 refresh_y = old_cursor.y - old_cursor.row->baseline;
3669 cursor = old_cursor; // that undo can restore the right cursor position
3670 LyXParagraph *endpar = old_cursor.par->next;
3671 if (endpar && endpar->GetDepth()) {
3672 while (endpar && endpar->GetDepth()) {
3673 endpar = endpar->LastPhysicalPar()->Next();
3676 SetUndo(Undo::DELETE,
3677 old_cursor.par->previous,
3682 RemoveRow(old_cursor.row);
3684 if (buffer->paragraph == old_cursor.par) {
3685 buffer->paragraph = buffer->paragraph->next;
3687 delete old_cursor.par;
3689 /* Breakagain the next par. Needed
3690 because of the parindent that can
3691 occur or dissappear.
3692 The next row can change its height,
3693 if there is another layout before
3696 BreakAgain(refresh_row);
3697 UpdateCounters(refresh_row->previous);
3703 SetCursorIntern(cursor.par, cursor.pos);
3705 if (sel_cursor.par == old_cursor.par
3706 && sel_cursor.pos == sel_cursor.pos) {
3707 // correct selection
3708 sel_cursor = cursor;
3713 if (old_cursor.par->ClearParagraph()) {
3714 RedoParagraphs(old_cursor, old_cursor.par->Next());
3716 SetCursorIntern(cursor.par, cursor.pos);
3717 sel_cursor = cursor;
3724 LyXParagraph * LyXText::GetParFromID(int id)
3726 LyXParagraph * result = FirstParagraph();
3727 while (result && result->id() != id)
3728 result = result->next;
3734 bool LyXText::TextUndo()
3736 // returns false if no undo possible
3737 Undo * undo = buffer->undostack.pop();
3742 .push(CreateUndo(undo->kind,
3743 GetParFromID(undo->number_of_before_par),
3744 GetParFromID(undo->number_of_behind_par)));
3746 return TextHandleUndo(undo);
3750 bool LyXText::TextRedo()
3752 // returns false if no redo possible
3753 Undo * undo = buffer->redostack.pop();
3758 .push(CreateUndo(undo->kind,
3759 GetParFromID(undo->number_of_before_par),
3760 GetParFromID(undo->number_of_behind_par)));
3762 return TextHandleUndo(undo);
3766 bool LyXText::TextHandleUndo(Undo * undo)
3768 // returns false if no undo possible
3769 bool result = false;
3771 LyXParagraph * before =
3772 GetParFromID(undo->number_of_before_par);
3773 LyXParagraph * behind =
3774 GetParFromID(undo->number_of_behind_par);
3775 LyXParagraph * tmppar;
3776 LyXParagraph * tmppar2;
3777 LyXParagraph * endpar;
3778 LyXParagraph * tmppar5;
3780 // if there's no before take the beginning
3781 // of the document for redoing
3783 SetCursorIntern(FirstParagraph(), 0);
3785 // replace the paragraphs with the undo informations
3787 LyXParagraph * tmppar3 = undo->par;
3788 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3789 LyXParagraph * tmppar4 = tmppar3;
3791 while (tmppar4->next)
3792 tmppar4 = tmppar4->next;
3793 } // get last undo par
3795 // now remove the old text if there is any
3796 if (before != behind || (!behind && !before)){
3798 tmppar5 = before->next;
3800 tmppar5 = buffer->paragraph;
3802 while (tmppar5 && tmppar5 != behind){
3804 tmppar5 = tmppar5->next;
3805 // a memory optimization for edit: Only layout information
3806 // is stored in the undo. So restore the text informations.
3807 if (undo->kind == Undo::EDIT) {
3808 tmppar2->setContentsFromPar(tmppar);
3809 tmppar->clearContents();
3810 tmppar2 = tmppar2->next;
3815 // put the new stuff in the list if there is one
3818 before->next = tmppar3;
3820 buffer->paragraph = tmppar3;
3821 tmppar3->previous = before;
3825 buffer->paragraph = behind;
3828 tmppar4->next = behind;
3830 behind->previous = tmppar4;
3834 // Set the cursor for redoing
3836 SetCursorIntern(before->FirstSelfrowPar(), 0);
3837 // check wether before points to a closed float and open it if necessary
3838 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3839 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3841 while (tmppar4->previous &&
3842 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3843 tmppar4 = tmppar4->previous;
3844 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3845 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3846 tmppar4 = tmppar4->next;
3851 // open a cosed footnote at the end if necessary
3852 if (behind && behind->previous &&
3853 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3854 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3855 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3856 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3857 behind = behind->next;
3861 // calculate the endpar for redoing the paragraphs.
3863 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3864 endpar = behind->LastPhysicalPar()->Next();
3866 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3871 tmppar = GetParFromID(undo->number_of_cursor_par);
3872 RedoParagraphs(cursor, endpar);
3874 SetCursorIntern(tmppar, undo->cursor_pos);
3875 UpdateCounters(cursor.row);
3885 void LyXText::FinishUndo()
3887 // makes sure the next operation will be stored
3888 undo_finished = True;
3892 void LyXText::FreezeUndo()
3894 // this is dangerous and for internal use only
3899 void LyXText::UnFreezeUndo()
3901 // this is dangerous and for internal use only
3902 undo_frozen = false;
3906 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3907 LyXParagraph const * behind) const
3910 buffer->undostack.push(CreateUndo(kind, before, behind));
3911 buffer->redostack.clear();
3915 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3916 LyXParagraph const * behind)
3918 buffer->redostack.push(CreateUndo(kind, before, behind));
3922 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3923 LyXParagraph const * behind) const
3925 int before_number = -1;
3926 int behind_number = -1;
3928 before_number = before->id();
3930 behind_number = behind->id();
3931 // Undo::EDIT and Undo::FINISH are
3932 // always finished. (no overlapping there)
3933 // overlapping only with insert and delete inside one paragraph:
3934 // Nobody wants all removed character
3935 // appear one by one when undoing.
3936 // EDIT is special since only layout information, not the
3937 // contents of a paragaph are stored.
3938 if (!undo_finished && kind != Undo::EDIT &&
3939 kind != Undo::FINISH){
3940 // check wether storing is needed
3941 if (!buffer->undostack.empty() &&
3942 buffer->undostack.top()->kind == kind &&
3943 buffer->undostack.top()->number_of_before_par == before_number &&
3944 buffer->undostack.top()->number_of_behind_par == behind_number ){
3949 // create a new Undo
3950 LyXParagraph * undopar;
3951 LyXParagraph * tmppar;
3952 LyXParagraph * tmppar2;
3954 LyXParagraph * start = 0;
3955 LyXParagraph * end = 0;
3958 start = before->next;
3960 start = FirstParagraph();
3962 end = behind->previous;
3964 end = FirstParagraph();
3970 && start != end->next
3971 && (before != behind || (!before && !behind))) {
3973 tmppar2 = tmppar->Clone();
3974 tmppar2->id(tmppar->id());
3976 // a memory optimization: Just store the layout information
3978 if (kind == Undo::EDIT){
3979 //tmppar2->text.clear();
3980 tmppar2->clearContents();
3985 while (tmppar != end && tmppar->next) {
3986 tmppar = tmppar->next;
3987 tmppar2->next = tmppar->Clone();
3988 tmppar2->next->id(tmppar->id());
3989 // a memory optimization: Just store the layout
3990 // information when only edit
3991 if (kind == Undo::EDIT){
3992 //tmppar2->next->text.clear();
3993 tmppar2->clearContents();
3995 tmppar2->next->previous = tmppar2;
3996 tmppar2 = tmppar2->next;
4000 undopar = 0; // nothing to replace (undo of delete maybe)
4002 int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
4003 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
4005 Undo * undo = new Undo(kind,
4006 before_number, behind_number,
4007 cursor_par, cursor_pos,
4010 undo_finished = false;
4015 void LyXText::SetCursorParUndo()
4017 SetUndo(Undo::FINISH,
4018 cursor.par->ParFromPos(cursor.pos)->previous,
4019 cursor.par->ParFromPos(cursor.pos)->next);
4023 void LyXText::RemoveTableRow(LyXCursor * cur) const
4029 // move to the previous row
4030 int cell_act = NumberOfCell(cur->par, cur->pos);
4033 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
4036 !cur->par->table->IsFirstCell(cell_act)) {
4038 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
4043 // now we have to pay attention if the actual table is the
4044 // main row of TableContRows and if yes to delete all of them
4049 // delete up to the next row
4050 while (cur->pos < cur->par->Last() &&
4052 || !cur->par->table->IsFirstCell(cell_act))) {
4053 while (cur->pos < cur->par->Last() &&
4054 !cur->par->IsNewline(cur->pos))
4055 cur->par->Erase(cur->pos);
4058 if (cur->pos < cur->par->Last())
4059 cur->par->Erase(cur->pos);
4061 if (cur->pos && cur->pos == cur->par->Last()) {
4063 cur->par->Erase(cur->pos); // no newline at very end!
4065 } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
4066 !cur->par->table->IsContRow(cell_org) &&
4067 cur->par->table->IsContRow(cell));
4068 cur->par->table->DeleteRow(cell_org);
4073 bool LyXText::IsEmptyTableCell() const
4075 LyXParagraph::size_type pos = cursor.pos - 1;
4076 while (pos >= 0 && pos < cursor.par->Last()
4077 && !cursor.par->IsNewline(pos))
4079 return cursor.par->IsNewline(pos + 1);
4083 void LyXText::toggleAppendix(){
4084 LyXParagraph * par = cursor.par->FirstPhysicalPar();
4085 bool start = !par->start_of_appendix;
4087 // ensure that we have only one start_of_appendix in this document
4088 LyXParagraph * tmp = FirstParagraph();
4089 for (; tmp; tmp = tmp->next)
4090 tmp->start_of_appendix = 0;
4091 par->start_of_appendix = start;
4093 // we can set the refreshing parameters now
4094 status = LyXText::NEED_MORE_REFRESH;
4096 refresh_row = 0; // not needed for full update
4098 SetCursor(cursor.par, cursor.pos);