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(buffer()->params,
148 realize(layout.reslabelfont);
150 return par->GetFontSettings(buffer()->params,
152 realize(layout.resfont);
155 // process layoutfont for pos == -1 and labelfont for pos < -1
157 return layout.resfont;
159 return layout.reslabelfont;
163 // The uncommon case need not be optimized as much
165 LyXFont layoutfont, tmpfont;
169 if (pos < BeginningOfMainBody(par)) {
171 layoutfont = layout.labelfont;
174 layoutfont = layout.font;
176 tmpfont = par->GetFontSettings(buffer()->params, pos);
177 tmpfont.realize(layoutfont);
180 // process layoutfont for pos == -1 and labelfont for pos < -1
182 tmpfont = layout.font;
184 tmpfont = layout.labelfont;
187 // Resolve against environment font information
188 while (par && par_depth && !tmpfont.resolved()) {
189 par = par->DepthHook(par_depth - 1);
191 tmpfont.realize(textclasslist.
192 Style(buffer()->params.textclass,
193 par->GetLayout()).font);
194 par_depth = par->GetDepth();
198 tmpfont.realize(textclasslist.TextClass(buffer()->params.textclass).defaultfont());
200 // Cosmetic improvement: If this is an open footnote, make the font
202 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
203 && par->footnotekind == LyXParagraph::FOOTNOTE) {
211 void LyXText::SetCharFont(LyXParagraph * par,
212 LyXParagraph::size_type pos,
216 // Let the insets convert their font
217 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
218 if (par->GetInset(pos))
219 font = par->GetInset(pos)->ConvertFont(font);
222 LyXLayout const & layout =
223 textclasslist.Style(buffer()->params.textclass,
226 // Get concrete layout font to reduce against
229 if (pos < BeginningOfMainBody(par))
230 layoutfont = layout.labelfont;
232 layoutfont = layout.font;
234 // Realize against environment font information
235 if (par->GetDepth()){
236 LyXParagraph * tp = par;
237 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
238 tp = tp->DepthHook(tp->GetDepth()-1);
240 layoutfont.realize(textclasslist.
241 Style(buffer()->params.textclass,
242 tp->GetLayout()).font);
246 layoutfont.realize(textclasslist.TextClass(buffer()->params.textclass).defaultfont());
248 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
249 && par->footnotekind == LyXParagraph::FOOTNOTE) {
250 layoutfont.decSize();
253 // Now, reduce font against full layout font
254 font.reduce(layoutfont);
256 par->SetFont(pos, font);
260 /* inserts a new row behind the specified row, increments
261 * the touched counters */
262 void LyXText::InsertRow(Row * row, LyXParagraph * par,
263 LyXParagraph::size_type pos) const
265 Row * tmprow = new Row;
268 tmprow->next(firstrow);
271 tmprow->previous(row);
272 tmprow->next(row->next());
277 tmprow->next()->previous(tmprow);
279 if (tmprow->previous())
280 tmprow->previous()->next(tmprow);
288 ++number_of_rows; // one more row
292 // removes the row and reset the touched counters
293 void LyXText::RemoveRow(Row * row) const
295 /* this must not happen before the currentrow for clear reasons.
296 so the trick is just to set the current row onto the previous
299 GetRow(row->par(), row->pos(), unused_y);
302 row->next()->previous(row->previous());
303 if (!row->previous()) {
304 firstrow = row->next();
306 row->previous()->next(row->next());
309 lastrow = row->previous();
311 height -= row->height(); // the text becomes smaller
314 --number_of_rows; // one row less
318 // remove all following rows of the paragraph of the specified row.
319 void LyXText::RemoveParagraph(Row * row) const
321 LyXParagraph * tmppar = row->par();
325 while (row && row->par() == tmppar) {
326 tmprow = row->next();
333 // insert the specified paragraph behind the specified row
334 void LyXText::InsertParagraph(LyXParagraph * par, Row * row) const
336 InsertRow(row, par, 0); /* insert a new row, starting
339 SetCounter(par); // set the counters
341 // and now append the whole paragraph behind the new row
344 AppendParagraph(firstrow);
346 row->next()->height(0);
347 AppendParagraph(row->next());
352 void LyXText::ToggleFootnote()
354 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
356 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
358 owner_->owner()->getMiniBuffer()->Set(_("Opened float"));
360 owner_->owner()->getMiniBuffer()->Set(_("Closed float"));
366 void LyXText::OpenStuff()
368 if (cursor.pos() == 0 && cursor.par()->bibkey){
369 cursor.par()->bibkey->Edit(owner_, 0, 0, 0);
371 else if (cursor.pos() < cursor.par()->Last()
372 && cursor.par()->GetChar(cursor.pos()) == LyXParagraph::META_INSET
373 && cursor.par()->GetInset(cursor.pos())->Editable()) {
374 owner_->owner()->getMiniBuffer()
375 ->Set(cursor.par()->GetInset(cursor.pos())->EditMessage());
376 if (cursor.par()->GetInset(cursor.pos())->Editable() != Inset::HIGHLY_EDITABLE)
378 cursor.par()->GetInset(cursor.pos())->Edit(owner_, 0, 0, 0);
385 void LyXText::CloseFootnote()
387 LyXParagraph * tmppar;
388 LyXParagraph * par = cursor.par()->ParFromPos(cursor.pos());
390 // if the cursor is not in an open footnote, or
391 // there is no open footnote in this paragraph, just return.
392 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
395 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
396 owner_->owner()->getMiniBuffer()
397 ->Set(_("Nothing to do"));
401 // ok, move the cursor right before the footnote
402 // just a little faster than using CursorRight()
404 cursor.par()->ParFromPos(cursor.pos()) != par;) {
405 cursor.pos(cursor.pos() + 1);
408 // now the cursor is at the beginning of the physical par
409 SetCursor(cursor.par(),
411 cursor.par()->ParFromPos(cursor.pos())->size());
413 /* we are in a footnote, so let us move at the beginning */
414 /* this is just faster than using just CursorLeft() */
416 tmppar = cursor.par();
417 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
418 // just a little bit faster than movin the cursor
419 tmppar = tmppar->Previous();
421 SetCursor(tmppar, tmppar->Last());
424 // the cursor must be exactly before the footnote
425 par = cursor.par()->ParFromPos(cursor.pos());
427 status = LyXText::NEED_MORE_REFRESH;
428 refresh_row = cursor.row();
429 refresh_y = cursor.y() - cursor.row()->baseline();
431 tmppar = cursor.par();
432 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
433 Row * row = cursor.row();
435 tmppar->CloseFootnote(cursor.pos());
437 while (tmppar != endpar) {
438 RemoveRow(row->next());
440 tmppar = row->next()->par();
445 AppendParagraph(cursor.row());
447 SetCursor(cursor.par(), cursor.pos());
451 if (cursor.row()->next())
452 SetHeightOfRow(cursor.row()->next());
456 /* used in setlayout */
457 // Asger is not sure we want to do this...
458 void LyXText::MakeFontEntriesLayoutSpecific(LyXParagraph * par)
461 LyXLayout const & layout =
462 textclasslist.Style(buffer()->params.textclass,
465 LyXFont layoutfont, tmpfont;
466 for (LyXParagraph::size_type pos = 0;
467 pos < par->Last(); ++pos) {
468 if (pos < BeginningOfMainBody(par))
469 layoutfont = layout.labelfont;
471 layoutfont = layout.font;
473 tmpfont = par->GetFontSettings(buffer()->params, pos);
474 tmpfont.reduce(layoutfont);
475 par->SetFont(pos, tmpfont);
479 LyXParagraph * LyXText::SetLayout(LyXCursor & cur, LyXCursor & sstart_cur,
480 LyXCursor & send_cur,
481 LyXTextClass::size_type layout)
483 LyXParagraph * endpar = send_cur.par()->LastPhysicalPar()->Next();
484 LyXParagraph * undoendpar = endpar;
486 if (endpar && endpar->GetDepth()) {
487 while (endpar && endpar->GetDepth()) {
488 endpar = endpar->LastPhysicalPar()->Next();
492 endpar = endpar->Next(); // because of parindents etc.
496 sstart_cur.par()->ParFromPos(sstart_cur.pos())->previous,
499 /* ok we have a selection. This is always between sstart_cur
500 * and sel_end cursor */
503 LyXLayout const & lyxlayout =
504 textclasslist.Style(buffer()->params.textclass, layout);
506 while (cur.par() != send_cur.par()) {
507 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
508 cur.par()->SetLayout(buffer()->params, layout);
509 MakeFontEntriesLayoutSpecific(cur.par());
510 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
511 fppar->added_space_top = lyxlayout.fill_top ?
512 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
513 fppar->added_space_bottom = lyxlayout.fill_bottom ?
514 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
515 if (lyxlayout.margintype == MARGIN_MANUAL)
516 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
517 if (lyxlayout.labeltype != LABEL_BIBLIO
519 delete fppar->bibkey;
523 cur.par(cur.par()->Next());
525 if (cur.par()->footnoteflag == sstart_cur.par()->footnoteflag) {
526 cur.par()->SetLayout(buffer()->params, layout);
527 MakeFontEntriesLayoutSpecific(cur.par());
528 LyXParagraph * fppar = cur.par()->FirstPhysicalPar();
529 fppar->added_space_top = lyxlayout.fill_top ?
530 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
531 fppar->added_space_bottom = lyxlayout.fill_bottom ?
532 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
533 if (lyxlayout.margintype == MARGIN_MANUAL)
534 cur.par()->SetLabelWidthString(lyxlayout.labelstring());
535 if (lyxlayout.labeltype != LABEL_BIBLIO
537 delete fppar->bibkey;
544 // set layout over selection and make a total rebreak of those paragraphs
545 void LyXText::SetLayout(LyXTextClass::size_type layout)
548 tmpcursor = cursor; /* store the current cursor */
550 #ifdef USE_OLD_SET_LAYOUT
551 // if there is no selection just set the layout
552 // of the current paragraph */
554 sel_start_cursor = cursor; // dummy selection
555 sel_end_cursor = cursor;
558 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
559 LyXParagraph * undoendpar = endpar;
561 if (endpar && endpar->GetDepth()) {
562 while (endpar && endpar->GetDepth()) {
563 endpar = endpar->LastPhysicalPar()->Next();
568 endpar = endpar->Next(); // because of parindents etc.
572 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
575 /* ok we have a selection. This is always between sel_start_cursor
576 * and sel_end cursor */
577 cursor = sel_start_cursor;
579 LyXLayout const & lyxlayout =
580 textclasslist.Style(buffer()->params.textclass, layout);
582 while (cursor.par() != sel_end_cursor.par()) {
583 if (cursor.par()->footnoteflag ==
584 sel_start_cursor.par()->footnoteflag) {
585 cursor.par()->SetLayout(layout);
586 MakeFontEntriesLayoutSpecific(cursor.par());
587 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
588 fppar->added_space_top = lyxlayout.fill_top ?
589 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
590 fppar->added_space_bottom = lyxlayout.fill_bottom ?
591 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
592 if (lyxlayout.margintype == MARGIN_MANUAL)
593 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
594 if (lyxlayout.labeltype != LABEL_BIBLIO
596 delete fppar->bibkey;
600 cursor.par() = cursor.par()->Next();
602 if (cursor.par()->footnoteflag ==
603 sel_start_cursor.par()->footnoteflag) {
604 cursor.par()->SetLayout(layout);
605 MakeFontEntriesLayoutSpecific(cursor.par());
606 LyXParagraph* fppar = cursor.par()->FirstPhysicalPar();
607 fppar->added_space_top = lyxlayout.fill_top ?
608 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
609 fppar->added_space_bottom = lyxlayout.fill_bottom ?
610 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
611 if (lyxlayout.margintype == MARGIN_MANUAL)
612 cursor.par()->SetLabelWidthString(lyxlayout.labelstring());
613 if (lyxlayout.labeltype != LABEL_BIBLIO
615 delete fppar->bibkey;
620 // if there is no selection just set the layout
621 // of the current paragraph */
623 sel_start_cursor = cursor; // dummy selection
624 sel_end_cursor = cursor;
627 endpar = SetLayout(cursor, sel_start_cursor, sel_end_cursor, layout);
629 RedoParagraphs(sel_start_cursor, endpar);
631 // we have to reset the selection, because the
632 // geometry could have changed */
633 SetCursor(sel_start_cursor.par(), sel_start_cursor.pos(), false);
635 SetCursor(sel_end_cursor.par(), sel_end_cursor.pos(), false);
636 UpdateCounters(cursor.row());
639 SetCursor(tmpcursor.par(), tmpcursor.pos(), true);
643 // increment depth over selection and
644 // make a total rebreak of those paragraphs
645 void LyXText::IncDepth()
647 // If there is no selection, just use the current paragraph
649 sel_start_cursor = cursor; // dummy selection
650 sel_end_cursor = cursor;
653 // We end at the next paragraph with depth 0
654 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
655 LyXParagraph * undoendpar = endpar;
657 if (endpar && endpar->GetDepth()) {
658 while (endpar && endpar->GetDepth()) {
659 endpar = endpar->LastPhysicalPar()->Next();
664 endpar = endpar->Next(); // because of parindents etc.
669 .par()->ParFromPos(sel_start_cursor.pos())->previous,
672 LyXCursor tmpcursor = cursor; // store the current cursor
674 // ok we have a selection. This is always between sel_start_cursor
675 // and sel_end cursor
676 cursor = sel_start_cursor;
678 bool anything_changed = false;
681 // NOTE: you can't change the depth of a bibliography entry
682 if (cursor.par()->footnoteflag ==
683 sel_start_cursor.par()->footnoteflag
684 && textclasslist.Style(buffer()->params.textclass,
685 cursor.par()->GetLayout()
686 ).labeltype != LABEL_BIBLIO) {
687 LyXParagraph * prev =
688 cursor.par()->FirstPhysicalPar()->Previous();
690 && (prev->GetDepth() - cursor.par()->GetDepth() > 0
691 || (prev->GetDepth() == cursor.par()->GetDepth()
692 && textclasslist.Style(buffer()->params.textclass,
693 prev->GetLayout()).isEnvironment()))) {
694 cursor.par()->FirstPhysicalPar()->depth++;
695 anything_changed = true;
698 if (cursor.par() == sel_end_cursor.par())
700 cursor.par(cursor.par()->Next());
703 // if nothing changed set all depth to 0
704 if (!anything_changed) {
705 cursor = sel_start_cursor;
706 while (cursor.par() != sel_end_cursor.par()) {
707 cursor.par()->FirstPhysicalPar()->depth = 0;
708 cursor.par(cursor.par()->Next());
710 if (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag)
711 cursor.par()->FirstPhysicalPar()->depth = 0;
714 RedoParagraphs(sel_start_cursor, endpar);
716 // we have to reset the selection, because the
717 // geometry could have changed
718 SetCursor(sel_start_cursor.par(), sel_start_cursor.pos());
720 SetCursor(sel_end_cursor.par(), sel_end_cursor.pos());
721 UpdateCounters(cursor.row());
724 SetCursor(tmpcursor.par(), tmpcursor.pos());
728 // decrement depth over selection and
729 // make a total rebreak of those paragraphs
730 void LyXText::DecDepth()
732 // if there is no selection just set the layout
733 // of the current paragraph
735 sel_start_cursor = cursor; // dummy selection
736 sel_end_cursor = cursor;
739 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
740 LyXParagraph * undoendpar = endpar;
742 if (endpar && endpar->GetDepth()) {
743 while (endpar && endpar->GetDepth()) {
744 endpar = endpar->LastPhysicalPar()->Next();
749 endpar = endpar->Next(); // because of parindents etc.
754 .par()->ParFromPos(sel_start_cursor.pos())->previous,
757 LyXCursor tmpcursor = cursor; // store the current cursor
759 // ok we have a selection. This is always between sel_start_cursor
760 // and sel_end cursor
761 cursor = sel_start_cursor;
764 if (cursor.par()->footnoteflag ==
765 sel_start_cursor.par()->footnoteflag) {
766 if (cursor.par()->FirstPhysicalPar()->depth)
767 cursor.par()->FirstPhysicalPar()->depth--;
769 if (cursor.par() == sel_end_cursor.par())
771 cursor.par(cursor.par()->Next());
774 RedoParagraphs(sel_start_cursor, endpar);
776 // we have to reset the selection, because the
777 // geometry could have changed
778 SetCursor(sel_start_cursor.par(), sel_start_cursor.pos());
780 SetCursor(sel_end_cursor.par(), sel_end_cursor.pos());
781 UpdateCounters(cursor.row());
784 SetCursor(tmpcursor.par(), tmpcursor.pos());
788 // set font over selection and make a total rebreak of those paragraphs
789 void LyXText::SetFont(LyXFont const & font, bool toggleall)
791 // if there is no selection just set the current_font
793 // Determine basis font
795 if (cursor.pos() < BeginningOfMainBody(cursor.par()))
796 layoutfont = GetFont(cursor.par(), -2);
798 layoutfont = GetFont(cursor.par(), -1);
799 // Update current font
800 real_current_font.update(font,
801 buffer()->params.language_info,
804 // Reduce to implicit settings
805 current_font = real_current_font;
806 current_font.reduce(layoutfont);
807 // And resolve it completely
808 real_current_font.realize(layoutfont);
812 LyXCursor tmpcursor = cursor; // store the current cursor
814 // ok we have a selection. This is always between sel_start_cursor
815 // and sel_end cursor
818 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->previous,
819 sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())->next);
820 cursor = sel_start_cursor;
821 while (cursor.par() != sel_end_cursor.par() ||
822 (cursor.par()->footnoteflag == sel_start_cursor.par()->footnoteflag
823 && cursor.pos() < sel_end_cursor.pos()))
825 if (cursor.pos() < cursor.par()->Last()
826 && cursor.par()->footnoteflag
827 == sel_start_cursor.par()->footnoteflag) {
828 // an open footnote should behave
830 LyXFont newfont = GetFont(cursor.par(), cursor.pos());
832 buffer()->params.language_info,
834 SetCharFont(cursor.par(), cursor.pos(), newfont);
835 cursor.pos(cursor.pos() + 1);
838 cursor.par(cursor.par()->Next());
842 RedoParagraphs(sel_start_cursor, sel_end_cursor.par()->Next());
844 // we have to reset the selection, because the
845 // geometry could have changed
846 SetCursor(sel_start_cursor.par(), sel_start_cursor.pos());
848 SetCursor(sel_end_cursor.par(), sel_end_cursor.pos());
851 SetCursor(tmpcursor.par(), tmpcursor.pos(), true, tmpcursor.boundary());
855 void LyXText::RedoHeightOfParagraph(LyXCursor const & cur)
857 Row * tmprow = cur.row();
858 long y = cur.y() - tmprow->baseline();
860 SetHeightOfRow(tmprow);
861 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
862 // find the first row of the paragraph
863 if (first_phys_par != tmprow->par())
864 while (tmprow->previous()
865 && tmprow->previous()->par() != first_phys_par) {
866 tmprow = tmprow->previous();
867 y -= tmprow->height();
868 SetHeightOfRow(tmprow);
870 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
871 tmprow = tmprow->previous();
872 y -= tmprow->height();
873 SetHeightOfRow(tmprow);
876 // we can set the refreshing parameters now
877 status = LyXText::NEED_MORE_REFRESH;
879 refresh_row = tmprow;
880 SetCursor(cur.par(), cur.pos(), false, cursor.boundary());
884 void LyXText::RedoDrawingOfParagraph(LyXCursor const & cur)
886 Row * tmprow = cur.row();
888 long y = cur.y() - tmprow->baseline();
889 SetHeightOfRow(tmprow);
890 LyXParagraph * first_phys_par = tmprow->par()->FirstPhysicalPar();
891 // find the first row of the paragraph
892 if (first_phys_par != tmprow->par())
893 while (tmprow->previous() && tmprow->previous()->par() != first_phys_par) {
894 tmprow = tmprow->previous();
895 y -= tmprow->height();
897 while (tmprow->previous() && tmprow->previous()->par() == first_phys_par) {
898 tmprow = tmprow->previous();
899 y -= tmprow->height();
902 // we can set the refreshing parameters now
903 if (status == LyXText::UNCHANGED || y < refresh_y) {
905 refresh_row = tmprow;
907 status = LyXText::NEED_MORE_REFRESH;
908 SetCursor(cur.par(), cur.pos());
912 /* deletes and inserts again all paragaphs between the cursor
913 * and the specified par
914 * This function is needed after SetLayout and SetFont etc. */
915 void LyXText::RedoParagraphs(LyXCursor const & cur,
916 LyXParagraph const * endpar) const
919 LyXParagraph * tmppar = 0, * first_phys_par = 0;
921 Row * tmprow = cur.row();
923 long y = cur.y() - tmprow->baseline();
925 if (!tmprow->previous()){
926 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
928 first_phys_par = tmprow->par()->FirstPhysicalPar();
929 // find the first row of the paragraph
930 if (first_phys_par != tmprow->par())
931 while (tmprow->previous() &&
932 (tmprow->previous()->par() != first_phys_par)) {
933 tmprow = tmprow->previous();
934 y -= tmprow->height();
936 while (tmprow->previous()
937 && tmprow->previous()->par() == first_phys_par) {
938 tmprow = tmprow->previous();
939 y -= tmprow->height();
943 // we can set the refreshing parameters now
944 status = LyXText::NEED_MORE_REFRESH;
946 refresh_row = tmprow->previous(); /* the real refresh row will
947 be deleted, so I store
951 tmppar = tmprow->next()->par();
954 while (tmppar != endpar) {
955 RemoveRow(tmprow->next());
957 tmppar = tmprow->next()->par();
962 // remove the first one
963 tmprow2 = tmprow; /* this is because tmprow->previous()
965 tmprow = tmprow->previous();
968 tmppar = first_phys_par;
972 InsertParagraph(tmppar, tmprow);
975 while (tmprow->next() && tmprow->next()->par() == tmppar)
976 tmprow = tmprow->next();
977 tmppar = tmppar->Next();
979 } while (tmppar != endpar);
981 // this is because of layout changes
983 refresh_y -= refresh_row->height();
984 SetHeightOfRow(refresh_row);
986 refresh_row = firstrow;
988 SetHeightOfRow(refresh_row);
991 if (tmprow && tmprow->next())
992 SetHeightOfRow(tmprow->next());
996 bool LyXText::FullRebreak()
998 if (need_break_row) {
999 BreakAgain(need_break_row);
1007 /* important for the screen */
1010 /* the cursor set functions have a special mechanism. When they
1011 * realize, that you left an empty paragraph, they will delete it.
1012 * They also delete the corresponding row */
1014 // need the selection cursor:
1015 void LyXText::SetSelection()
1018 last_sel_cursor = sel_cursor;
1019 sel_start_cursor = sel_cursor;
1020 sel_end_cursor = sel_cursor;
1025 // first the toggling area
1026 if (cursor.y() < last_sel_cursor.y()
1027 || (cursor.y() == last_sel_cursor.y()
1028 && cursor.x() < last_sel_cursor.x())) {
1029 toggle_end_cursor = last_sel_cursor;
1030 toggle_cursor = cursor;
1032 toggle_end_cursor = cursor;
1033 toggle_cursor = last_sel_cursor;
1036 last_sel_cursor = cursor;
1038 // and now the whole selection
1040 if (sel_cursor.par() == cursor.par())
1041 if (sel_cursor.pos() < cursor.pos()) {
1042 sel_end_cursor = cursor;
1043 sel_start_cursor = sel_cursor;
1045 sel_end_cursor = sel_cursor;
1046 sel_start_cursor = cursor;
1048 else if (sel_cursor.y() < cursor.y() ||
1049 (sel_cursor.y() == cursor.y() && sel_cursor.x() < cursor.x())) {
1050 sel_end_cursor = cursor;
1051 sel_start_cursor = sel_cursor;
1054 sel_end_cursor = sel_cursor;
1055 sel_start_cursor = cursor;
1058 // a selection with no contents is not a selection
1059 if (sel_start_cursor.par() == sel_end_cursor.par() &&
1060 sel_start_cursor.pos() == sel_end_cursor.pos())
1063 // Stuff what we got on the clipboard. Even if there is no selection.
1065 // There is a problem with having the stuffing here in that the
1066 // larger the selection the slower LyX will get. This can be
1067 // solved by running the line below only when the selection has
1068 // finished. The solution used currently just works, to make it
1069 // faster we need to be more clever and probably also have more
1070 // calls to stuffClipboard. (Lgb)
1071 owner_->stuffClipboard(selectionAsString());
1075 string LyXText::selectionAsString() const
1077 if (!selection) return string();
1080 // Special handling if the whole selection is within one paragraph
1081 if (sel_start_cursor.par() == sel_end_cursor.par()) {
1082 result += sel_start_cursor.par()->String(sel_start_cursor.pos(),
1083 sel_end_cursor.pos());
1087 // The selection spans more than one paragraph
1089 // First paragraph in selection
1090 result += sel_start_cursor.par()->String(sel_start_cursor.pos(),
1091 sel_start_cursor.par()->Last())
1094 // The paragraphs in between (if any)
1095 LyXCursor tmpcur(sel_start_cursor);
1096 tmpcur.par(tmpcur.par()->Next());
1097 while (tmpcur.par() != sel_end_cursor.par()) {
1098 result += tmpcur.par()->String(0, tmpcur.par()->Last()) + "\n\n";
1099 tmpcur.par(tmpcur.par()->Next()); // Or NextAfterFootnote??
1102 // Last paragraph in selection
1103 result += sel_end_cursor.par()->String(0, sel_end_cursor.pos());
1109 void LyXText::ClearSelection() const
1116 void LyXText::CursorHome() const
1118 SetCursor(cursor.par(), cursor.row()->pos());
1122 void LyXText::CursorEnd() const
1124 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1125 SetCursor(cursor.par(), RowLast(cursor.row()) + 1);
1127 if (cursor.par()->Last() &&
1128 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1129 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1130 SetCursor(cursor.par(), RowLast(cursor.row()));
1132 SetCursor(cursor.par(), RowLast(cursor.row()) + 1);
1135 if (cursor.par()->table) {
1136 int cell = NumberOfCell(cursor.par(), cursor.pos());
1137 if (cursor.par()->table->RowHasContRow(cell) &&
1138 cursor.par()->table->CellHasContRow(cell)<0) {
1139 if (!cursor.row()->next() || cursor.row()->next()->par() != cursor.row()->par())
1140 SetCursor(cursor.par(), RowLast(cursor.row()) + 1);
1142 if (cursor.par()->Last() &&
1143 (cursor.par()->GetChar(RowLast(cursor.row())) == ' '
1144 || cursor.par()->IsNewline(RowLast(cursor.row()))))
1145 SetCursor(cursor.par(), RowLast(cursor.row()));
1147 SetCursor(cursor.par(), RowLast(cursor.row()) + 1);
1155 void LyXText::CursorTop() const
1157 while (cursor.par()->Previous())
1158 cursor.par(cursor.par()->Previous());
1159 SetCursor(cursor.par(), 0);
1163 void LyXText::CursorBottom() const
1165 while (cursor.par()->Next())
1166 cursor.par(cursor.par()->Next());
1167 SetCursor(cursor.par(), cursor.par()->Last());
1171 /* returns a pointer to the row near the specified y-coordinate
1172 * (relative to the whole text). y is set to the real beginning
1174 Row * LyXText::GetRowNearY(long & y) const
1176 Row * tmprow = firstrow;
1179 while (tmprow->next() && tmpy + tmprow->height() <= y) {
1180 tmpy += tmprow->height();
1181 tmprow = tmprow->next();
1184 y = tmpy; // return the real y
1189 void LyXText::ToggleFree(LyXFont const & font, bool toggleall)
1191 // If the mask is completely neutral, tell user
1192 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1193 // Could only happen with user style
1194 owner_->owner()->getMiniBuffer()
1195 ->Set(_("No font change defined. Use Character under"
1196 " the Layout menu to define font change."));
1200 // Try implicit word selection
1201 // If there is a change in the language the implicit word selection
1203 LyXCursor resetCursor = cursor;
1204 bool implicitSelection = (font.language() == ignore_language)
1205 ? SelectWordWhenUnderCursor() : false;
1208 SetFont(font, toggleall);
1210 /* Implicit selections are cleared afterwards and cursor is set to the
1211 original position. */
1212 if (implicitSelection) {
1214 cursor = resetCursor;
1215 SetCursor( cursor.par(), cursor.pos() );
1216 sel_cursor = cursor;
1221 LyXParagraph::size_type
1222 LyXText::BeginningOfMainBody(LyXParagraph const * par) const
1224 if (textclasslist.Style(buffer()->params.textclass,
1225 par->GetLayout()).labeltype != LABEL_MANUAL)
1228 return par->BeginningOfMainBody();
1232 /* if there is a selection, reset every environment you can find
1233 * in the selection, otherwise just the environment you are in */
1234 void LyXText::MeltFootnoteEnvironment()
1236 LyXParagraph * tmppar, * firsttmppar;
1240 /* is is only allowed, if the cursor is IN an open footnote.
1241 * Otherwise it is too dangerous */
1242 if (cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1245 SetUndo(Undo::FINISH,
1246 cursor.par()->PreviousBeforeFootnote()->previous,
1247 cursor.par()->NextAfterFootnote()->next);
1249 /* ok, move to the beginning of the footnote. */
1250 while (cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1251 cursor.par(cursor.par()->Previous());
1253 SetCursor(cursor.par(), cursor.par()->Last());
1254 /* this is just faster than using CursorLeft(); */
1256 firsttmppar = cursor.par()->ParFromPos(cursor.pos());
1257 tmppar = firsttmppar;
1258 /* tmppar is now the paragraph right before the footnote */
1260 bool first_footnote_par_is_not_empty = tmppar->next->size();
1263 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1264 tmppar = tmppar->next; /* I use next instead of Next(),
1265 * because there cannot be any
1266 * footnotes in a footnote
1268 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1270 /* remember the captions and empty paragraphs */
1271 if ((textclasslist.Style(buffer()->params.textclass,
1272 tmppar->GetLayout())
1273 .labeltype == LABEL_SENSITIVE)
1275 tmppar->SetLayout(buffer()->params, 0);
1278 // now we will paste the ex-footnote, if the layouts allow it
1279 // first restore the layout of the paragraph right behind
1282 tmppar->next->MakeSameLayout(cursor.par());
1285 if ((!tmppar->GetLayout() && !tmppar->table)
1287 && (!tmppar->Next()->Last()
1288 || tmppar->Next()->HasSameLayout(tmppar)))) {
1289 if (tmppar->Next()->Last()
1290 && tmppar->Next()->IsLineSeparator(0))
1291 tmppar->Next()->Erase(0);
1292 tmppar->PasteParagraph(buffer()->params);
1295 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1296 * by the pasting of the beginning */
1298 /* then the beginning */
1299 /* if there is no space between the text and the footnote, so we insert
1301 * (only if the previous par and the footnotepar are not empty!) */
1302 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1303 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1304 if (firsttmppar->size()
1305 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1306 && first_footnote_par_is_not_empty) {
1307 firsttmppar->next->InsertChar(0, ' ');
1309 firsttmppar->PasteParagraph(buffer()->params);
1312 /* now redo the paragaphs */
1313 RedoParagraphs(cursor, tmppar);
1315 SetCursor(cursor.par(), cursor.pos());
1317 /* sometimes it can happen, that there is a counter change */
1318 Row * row = cursor.row();
1319 while (row->next() && row->par() != tmppar && row->next()->par() != tmppar)
1321 UpdateCounters(row);
1328 /* the DTP switches for paragraphs. LyX will store them in the
1329 * first physicla paragraph. When a paragraph is broken, the top settings
1330 * rest, the bottom settings are given to the new one. So I can make shure,
1331 * they do not duplicate themself and you cannnot make dirty things with
1334 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1335 bool pagebreak_top, bool pagebreak_bottom,
1336 VSpace const & space_top,
1337 VSpace const & space_bottom,
1339 string labelwidthstring,
1342 LyXCursor tmpcursor = cursor;
1344 sel_start_cursor = cursor;
1345 sel_end_cursor = cursor;
1348 // make sure that the depth behind the selection are restored, too
1349 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1350 LyXParagraph * undoendpar = endpar;
1352 if (endpar && endpar->GetDepth()) {
1353 while (endpar && endpar->GetDepth()) {
1354 endpar = endpar->LastPhysicalPar()->Next();
1355 undoendpar = endpar;
1359 endpar = endpar->Next(); // because of parindents etc.
1364 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1368 LyXParagraph * tmppar = sel_end_cursor.par();
1369 while (tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1370 SetCursor(tmppar->FirstPhysicalPar(), 0);
1371 status = LyXText::NEED_MORE_REFRESH;
1372 refresh_row = cursor.row();
1373 refresh_y = cursor.y() - cursor.row()->baseline();
1374 if (cursor.par()->footnoteflag ==
1375 sel_start_cursor.par()->footnoteflag) {
1376 cursor.par()->line_top = line_top;
1377 cursor.par()->line_bottom = line_bottom;
1378 cursor.par()->pagebreak_top = pagebreak_top;
1379 cursor.par()->pagebreak_bottom = pagebreak_bottom;
1380 cursor.par()->added_space_top = space_top;
1381 cursor.par()->added_space_bottom = space_bottom;
1382 // does the layout allow the new alignment?
1383 if (align == LYX_ALIGN_LAYOUT)
1384 align = textclasslist
1385 .Style(buffer()->params.textclass,
1386 cursor.par()->GetLayout()).align;
1387 if (align & textclasslist
1388 .Style(buffer()->params.textclass,
1389 cursor.par()->GetLayout()).alignpossible) {
1390 if (align == textclasslist
1391 .Style(buffer()->params.textclass,
1392 cursor.par()->GetLayout()).align)
1393 cursor.par()->align = LYX_ALIGN_LAYOUT;
1395 cursor.par()->align = align;
1397 cursor.par()->SetLabelWidthString(labelwidthstring);
1398 cursor.par()->noindent = noindent;
1401 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1404 RedoParagraphs(sel_start_cursor, endpar);
1407 SetCursor(sel_start_cursor.par(), sel_start_cursor.pos());
1408 sel_cursor = cursor;
1409 SetCursor(sel_end_cursor.par(), sel_end_cursor.pos());
1411 SetCursor(tmpcursor.par(), tmpcursor.pos());
1415 void LyXText::SetParagraphExtraOpt(int type,
1417 char const * widthp,
1418 int alignment, bool hfill,
1419 bool start_minipage)
1421 LyXCursor tmpcursor = cursor;
1422 LyXParagraph * tmppar;
1424 sel_start_cursor = cursor;
1425 sel_end_cursor = cursor;
1428 // make sure that the depth behind the selection are restored, too
1429 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
1430 LyXParagraph * undoendpar = endpar;
1432 if (endpar && endpar->GetDepth()) {
1433 while (endpar && endpar->GetDepth()) {
1434 endpar = endpar->LastPhysicalPar()->Next();
1435 undoendpar = endpar;
1439 endpar = endpar->Next(); // because of parindents etc.
1444 .par()->ParFromPos(sel_start_cursor.pos())->previous,
1447 tmppar = sel_end_cursor.par();
1448 while(tmppar != sel_start_cursor.par()->FirstPhysicalPar()->Previous()) {
1449 SetCursor(tmppar->FirstPhysicalPar(), 0);
1450 status = LyXText::NEED_MORE_REFRESH;
1451 refresh_row = cursor.row();
1452 refresh_y = cursor.y() - cursor.row()->baseline();
1453 if (cursor.par()->footnoteflag ==
1454 sel_start_cursor.par()->footnoteflag) {
1455 if (type == LyXParagraph::PEXTRA_NONE) {
1456 if (cursor.par()->pextra_type != LyXParagraph::PEXTRA_NONE) {
1457 cursor.par()->UnsetPExtraType(buffer()->params);
1458 cursor.par()->pextra_type = LyXParagraph::PEXTRA_NONE;
1461 cursor.par()->SetPExtraType(buffer()->params,
1462 type, width, widthp);
1463 cursor.par()->pextra_hfill = hfill;
1464 cursor.par()->pextra_start_minipage = start_minipage;
1465 cursor.par()->pextra_alignment = alignment;
1468 tmppar = cursor.par()->FirstPhysicalPar()->Previous();
1470 RedoParagraphs(sel_start_cursor, endpar);
1472 SetCursor(sel_start_cursor.par(), sel_start_cursor.pos());
1473 sel_cursor = cursor;
1474 SetCursor(sel_end_cursor.par(), sel_end_cursor.pos());
1476 SetCursor(tmpcursor.par(), tmpcursor.pos());
1480 char loweralphaCounter(int n)
1482 if (n < 1 || n > 26)
1488 char alphaCounter(int n)
1490 if (n < 1 || n > 26)
1496 char hebrewCounter(int n)
1498 static const char hebrew[22] = {
1499 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1500 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1501 '÷', 'ø', 'ù', 'ú'
1503 if (n < 1 || n > 22)
1509 static char const * romanCounter(int n)
1511 static char const * roman[20] = {
1512 "i", "ii", "iii", "iv", "v",
1513 "vi", "vii", "viii", "ix", "x",
1514 "xi", "xii", "xiii", "xiv", "xv",
1515 "xvi", "xvii", "xviii", "xix", "xx"
1517 if (n < 1 || n > 20)
1523 // set the counter of a paragraph. This includes the labels
1524 void LyXText::SetCounter(LyXParagraph * par) const
1526 // this is only relevant for the beginning of paragraph
1527 par = par->FirstPhysicalPar();
1529 LyXLayout const & layout =
1530 textclasslist.Style(buffer()->params.textclass,
1533 LyXTextClass const & textclass =
1534 textclasslist.TextClass(buffer()->params.textclass);
1536 /* copy the prev-counters to this one, unless this is the start of a
1537 footnote or of a bibliography or the very first paragraph */
1539 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1540 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1541 && par->footnotekind == LyXParagraph::FOOTNOTE)
1542 && !(textclasslist.Style(buffer()->params.textclass,
1543 par->Previous()->GetLayout()
1544 ).labeltype != LABEL_BIBLIO
1545 && layout.labeltype == LABEL_BIBLIO)) {
1546 for (int i = 0; i < 10; ++i) {
1547 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1549 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1550 if (!par->appendix && par->start_of_appendix){
1551 par->appendix = true;
1552 for (int i = 0; i < 10; ++i) {
1553 par->setCounter(i, 0);
1556 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1557 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1560 for (int i = 0; i < 10; ++i) {
1561 par->setCounter(i, 0);
1563 par->appendix = par->start_of_appendix;
1568 // if this is an open marginnote and this is the first
1569 // entry in the marginnote and the enclosing
1570 // environment is an enum/item then correct for the
1571 // LaTeX behaviour (ARRae)
1572 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1573 && par->footnotekind == LyXParagraph::MARGIN
1575 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1576 && (par->PreviousBeforeFootnote()
1577 && textclasslist.Style(buffer()->params.textclass,
1578 par->PreviousBeforeFootnote()->GetLayout()
1579 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1580 // Any itemize or enumerate environment in a marginnote
1581 // that is embedded in an itemize or enumerate
1582 // paragraph is seen by LaTeX as being at a deeper
1583 // level within that enclosing itemization/enumeration
1584 // even if there is a "standard" layout at the start of
1590 /* Maybe we have to increment the enumeration depth.
1591 * BUT, enumeration in a footnote is considered in isolation from its
1592 * surrounding paragraph so don't increment if this is the
1593 * first line of the footnote
1594 * AND, bibliographies can't have their depth changed ie. they
1595 * are always of depth 0
1598 && par->Previous()->GetDepth() < par->GetDepth()
1599 && textclasslist.Style(buffer()->params.textclass,
1600 par->Previous()->GetLayout()
1601 ).labeltype == LABEL_COUNTER_ENUMI
1602 && par->enumdepth < 3
1603 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1604 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1605 && par->footnotekind == LyXParagraph::FOOTNOTE)
1606 && layout.labeltype != LABEL_BIBLIO) {
1610 /* Maybe we have to decrement the enumeration depth, see note above */
1612 && par->Previous()->GetDepth() > par->GetDepth()
1613 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1614 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1615 && par->footnotekind == LyXParagraph::FOOTNOTE)
1616 && layout.labeltype != LABEL_BIBLIO) {
1617 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1618 par->setCounter(6 + par->enumdepth,
1619 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1620 /* reset the counters.
1621 * A depth change is like a breaking layout
1623 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1624 par->setCounter(i, 0);
1627 if (!par->labelstring.empty()) {
1628 par->labelstring.erase();
1631 if (layout.margintype == MARGIN_MANUAL) {
1632 if (par->labelwidthstring.empty()) {
1633 par->SetLabelWidthString(layout.labelstring());
1636 par->SetLabelWidthString(string());
1639 /* is it a layout that has an automatic label ? */
1640 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1642 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1643 if (i >= 0 && i<= buffer()->params.secnumdepth) {
1644 par->incCounter(i); // increment the counter
1646 // Is there a label? Useful for Chapter layout
1647 if (!par->appendix){
1648 if (!layout.labelstring().empty())
1649 par->labelstring = layout.labelstring();
1651 par->labelstring.erase();
1653 if (!layout.labelstring_appendix().empty())
1654 par->labelstring = layout.labelstring_appendix();
1656 par->labelstring.erase();
1660 std::ostringstream s;
1664 if (!par->appendix) {
1665 switch (2 * LABEL_FIRST_COUNTER -
1666 textclass.maxcounter() + i) {
1667 case LABEL_COUNTER_CHAPTER:
1668 s << par->getCounter(i);
1670 case LABEL_COUNTER_SECTION:
1671 s << par->getCounter(i - 1) << '.'
1672 << par->getCounter(i);
1674 case LABEL_COUNTER_SUBSECTION:
1675 s << par->getCounter(i - 2) << '.'
1676 << par->getCounter(i - 1) << '.'
1677 << par->getCounter(i);
1679 case LABEL_COUNTER_SUBSUBSECTION:
1680 s << par->getCounter(i - 3) << '.'
1681 << par->getCounter(i - 2) << '.'
1682 << par->getCounter(i - 1) << '.'
1683 << par->getCounter(i);
1686 case LABEL_COUNTER_PARAGRAPH:
1687 s << par->getCounter(i - 4) << '.'
1688 << par->getCounter(i - 3) << '.'
1689 << par->getCounter(i - 2) << '.'
1690 << par->getCounter(i - 1) << '.'
1691 << par->getCounter(i);
1693 case LABEL_COUNTER_SUBPARAGRAPH:
1694 s << par->getCounter(i - 5) << '.'
1695 << par->getCounter(i - 4) << '.'
1696 << par->getCounter(i - 3) << '.'
1697 << par->getCounter(i - 2) << '.'
1698 << par->getCounter(i - 1) << '.'
1699 << par->getCounter(i);
1703 s << par->getCounter(i) << '.';
1706 } else { // appendix
1707 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1708 case LABEL_COUNTER_CHAPTER:
1709 if (par->isRightToLeftPar(buffer()->params))
1710 s << hebrewCounter(par->getCounter(i));
1712 s << alphaCounter(par->getCounter(i));
1714 case LABEL_COUNTER_SECTION:
1715 if (par->isRightToLeftPar(buffer()->params))
1716 s << hebrewCounter(par->getCounter(i - 1));
1718 s << alphaCounter(par->getCounter(i - 1));
1721 << par->getCounter(i);
1724 case LABEL_COUNTER_SUBSECTION:
1725 if (par->isRightToLeftPar(buffer()->params))
1726 s << hebrewCounter(par->getCounter(i - 2));
1728 s << alphaCounter(par->getCounter(i - 2));
1731 << par->getCounter(i-1) << '.'
1732 << par->getCounter(i);
1735 case LABEL_COUNTER_SUBSUBSECTION:
1736 if (par->isRightToLeftPar(buffer()->params))
1737 s << hebrewCounter(par->getCounter(i-3));
1739 s << alphaCounter(par->getCounter(i-3));
1742 << par->getCounter(i-2) << '.'
1743 << par->getCounter(i-1) << '.'
1744 << par->getCounter(i);
1747 case LABEL_COUNTER_PARAGRAPH:
1748 if (par->isRightToLeftPar(buffer()->params))
1749 s << hebrewCounter(par->getCounter(i-4));
1751 s << alphaCounter(par->getCounter(i-4));
1754 << par->getCounter(i-3) << '.'
1755 << par->getCounter(i-2) << '.'
1756 << par->getCounter(i-1) << '.'
1757 << par->getCounter(i);
1760 case LABEL_COUNTER_SUBPARAGRAPH:
1761 if (par->isRightToLeftPar(buffer()->params))
1762 s << hebrewCounter(par->getCounter(i-5));
1764 s << alphaCounter(par->getCounter(i-5));
1767 << par->getCounter(i-4) << '.'
1768 << par->getCounter(i-3) << '.'
1769 << par->getCounter(i-2) << '.'
1770 << par->getCounter(i-1) << '.'
1771 << par->getCounter(i);
1775 // Can this ever be reached? And in the
1776 // case it is, how can this be correct?
1778 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1784 par->labelstring += s.str().c_str();
1785 // We really want to remove the c_str as soon as
1789 char * tmps = s.str();
1790 par->labelstring += tmps;
1794 for (i++; i < 10; ++i) {
1795 // reset the following counters
1796 par->setCounter(i, 0);
1798 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1799 for (i++; i < 10; ++i) {
1800 // reset the following counters
1801 par->setCounter(i, 0);
1803 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1804 par->incCounter(i + par->enumdepth);
1805 int number = par->getCounter(i + par->enumdepth);
1808 std::ostringstream s;
1812 switch (par->enumdepth) {
1814 if (par->isRightToLeftPar(buffer()->params))
1816 << hebrewCounter(number)
1820 << loweralphaCounter(number)
1824 if (par->isRightToLeftPar(buffer()->params))
1825 s << '.' << romanCounter(number);
1827 s << romanCounter(number) << '.';
1830 if (par->isRightToLeftPar(buffer()->params))
1832 << alphaCounter(number);
1834 s << alphaCounter(number)
1838 if (par->isRightToLeftPar(buffer()->params))
1845 par->labelstring = s.str().c_str();
1846 // we really want to get rid of that c_str()
1849 char * tmps = s.str();
1850 par->labelstring = tmps;
1854 for (i += par->enumdepth + 1; i < 10; ++i)
1855 par->setCounter(i, 0); /* reset the following counters */
1858 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1859 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1861 int number = par->getCounter(i);
1863 par->bibkey = new InsetBibKey();
1864 par->bibkey->setCounter(number);
1865 par->labelstring = layout.labelstring();
1867 // In biblio should't be following counters but...
1869 string s = layout.labelstring();
1871 // the caption hack:
1873 if (layout.labeltype == LABEL_SENSITIVE) {
1874 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1875 && (par->footnotekind == LyXParagraph::FIG
1876 || par->footnotekind == LyXParagraph::WIDE_FIG))
1877 s = (par->getParLanguage(buffer()->params)->lang() == "hebrew")
1878 ? ":øåéà " : "Figure:";
1879 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1880 && (par->footnotekind == LyXParagraph::TAB
1881 || par->footnotekind == LyXParagraph::WIDE_TAB))
1882 s = (par->getParLanguage(buffer()->params)->lang() == "hebrew")
1883 ? ":äìáè" : "Table:";
1884 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1885 && par->footnotekind == LyXParagraph::ALGORITHM)
1886 s = (par->getParLanguage(buffer()->params)->lang() == "hebrew")
1887 ? ":Ãúéøåâìà " : "Algorithm:";
1889 /* par->SetLayout(0);
1890 s = layout->labelstring; */
1891 s = (par->getParLanguage(buffer()->params)->lang() == "hebrew")
1892 ? " :úåòîùî øñç" : "Senseless: ";
1895 par->labelstring = s;
1897 /* reset the enumeration counter. They are always resetted
1898 * when there is any other layout between */
1899 for (int i = 6 + par->enumdepth; i < 10; ++i)
1900 par->setCounter(i, 0);
1905 /* Updates all counters BEHIND the row. Changed paragraphs
1906 * with a dynamic left margin will be rebroken. */
1907 void LyXText::UpdateCounters(Row * row) const
1915 if (row->par()->next
1916 && row->par()->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1917 par = row->par()->LastPhysicalPar()->Next();
1919 par = row->par()->next;
1924 while (row->par() != par)
1929 /* now check for the headline layouts. remember that they
1930 * have a dynamic left margin */
1932 && ( textclasslist.Style(buffer()->params.textclass,
1933 par->layout).margintype == MARGIN_DYNAMIC
1934 || textclasslist.Style(buffer()->params.textclass,
1935 par->layout).labeltype == LABEL_SENSITIVE)
1938 /* Rebreak the paragraph */
1939 RemoveParagraph(row);
1940 AppendParagraph(row);
1942 /* think about the damned open footnotes! */
1943 while (par->Next() &&
1944 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1945 || par->Next()->IsDummy())){
1947 if (par->IsDummy()) {
1948 while (row->par() != par)
1950 RemoveParagraph(row);
1951 AppendParagraph(row);
1956 par = par->LastPhysicalPar()->Next();
1962 /* insets an inset. */
1963 void LyXText::InsertInset(Inset *inset)
1965 if (!cursor.par()->InsertInsetAllowed(inset))
1967 SetUndo(Undo::INSERT,
1968 cursor.par()->ParFromPos(cursor.pos())->previous,
1969 cursor.par()->ParFromPos(cursor.pos())->next);
1970 cursor.par()->InsertChar(cursor.pos(), LyXParagraph::META_INSET);
1971 cursor.par()->InsertInset(cursor.pos(), inset);
1972 InsertChar(LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
1973 * The character will not be inserted a
1978 #ifdef USE_OLD_CUT_AND_PASTE
1979 // this is for the simple cut and paste mechanism
1980 static LyXParagraph * simple_cut_buffer = 0;
1981 static char simple_cut_buffer_textclass = 0;
1983 void DeleteSimpleCutBuffer()
1985 if (!simple_cut_buffer)
1987 LyXParagraph * tmppar;
1989 while (simple_cut_buffer) {
1990 tmppar = simple_cut_buffer;
1991 simple_cut_buffer = simple_cut_buffer()->next;
1994 simple_cut_buffer = 0;
1998 void LyXText::copyEnvironmentType()
2000 copylayouttype = cursor.par()->GetLayout();
2004 void LyXText::pasteEnvironmentType()
2006 SetLayout(copylayouttype);
2009 #ifdef USE_OLD_CUT_AND_PASTE
2010 void LyXText::CutSelection(bool doclear)
2012 // This doesn't make sense, if there is no selection
2016 // OK, we have a selection. This is always between sel_start_cursor
2017 // and sel_end cursor
2018 LyXParagraph * tmppar;
2020 // Check whether there are half footnotes in the selection
2021 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2022 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2023 tmppar = sel_start_cursor.par();
2024 while (tmppar != sel_end_cursor.par()){
2025 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2026 WriteAlert(_("Impossible operation"),
2027 _("Don't know what to do with half floats."),
2031 tmppar = tmppar->Next();
2036 /* table stuff -- begin */
2037 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2038 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2039 WriteAlert(_("Impossible operation"),
2040 _("Don't know what to do with half tables."),
2044 sel_start_cursor.par()->table->Reinit();
2046 /* table stuff -- end */
2049 // make sure that the depth behind the selection are restored, too
2050 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2051 LyXParagraph * undoendpar = endpar;
2053 if (endpar && endpar->GetDepth()) {
2054 while (endpar && endpar->GetDepth()) {
2055 endpar = endpar->LastPhysicalPar()->Next();
2056 undoendpar = endpar;
2058 } else if (endpar) {
2059 endpar = endpar->Next(); // because of parindents etc.
2062 SetUndo(Undo::DELETE,
2064 .par->ParFromPos(sel_start_cursor.pos())->previous,
2067 // clear the simple_cut_buffer
2068 DeleteSimpleCutBuffer();
2070 // set the textclass
2071 simple_cut_buffer_textclass = buffer()->params.textclass;
2073 #ifdef WITH_WARNINGS
2074 #warning Asger: Make cut more intelligent here.
2077 White paper for "intelligent" cutting:
2079 Example: "This is our text."
2080 Using " our " as selection, cutting will give "This istext.".
2081 Using "our" as selection, cutting will give "This is text.".
2082 Using " our" as selection, cutting will give "This is text.".
2083 Using "our " as selection, cutting will give "This is text.".
2085 All those four selections will (however) paste identically:
2086 Pasting with the cursor right after the "is" will give the
2087 original text with all four selections.
2089 The rationale is to be intelligent such that words are copied,
2090 cut and pasted in a functional manner.
2092 This is not implemented yet. (Asger)
2094 The changes below sees to do a lot of what you want. However
2095 I have not verified that all cases work as they should:
2097 - cut in multiple row
2099 - cut across footnotes and paragraph
2100 My simplistic tests show that the idea are basically sound but
2101 there are some items to fix up...we only need to find them
2104 As do redo Asger's example above (with | beeing the cursor in the
2105 result after cutting.):
2107 Example: "This is our text."
2108 Using " our " as selection, cutting will give "This is|text.".
2109 Using "our" as selection, cutting will give "This is | text.".
2110 Using " our" as selection, cutting will give "This is| text.".
2111 Using "our " as selection, cutting will give "This is |text.".
2116 // there are two cases: cut only within one paragraph or
2117 // more than one paragraph
2119 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2120 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2121 // only within one paragraph
2122 simple_cut_buffer = new LyXParagraph;
2123 LyXParagraph::size_type i =
2124 sel_start_cursor.pos();
2125 for (; i < sel_end_cursor.pos(); ++i) {
2127 /* table stuff -- begin */
2128 if (sel_start_cursor.par()->table
2129 && sel_start_cursor.par()->IsNewline(sel_start_cursor.pos())) {
2130 sel_start_cursor.par()->CopyIntoMinibuffer(sel_start_cursor.pos());
2131 sel_start_cursor.pos()++;
2133 /* table stuff -- end */
2135 sel_start_cursor.par()->CopyIntoMinibuffer(sel_start_cursor.pos());
2136 sel_start_cursor.par()->Erase(sel_start_cursor.pos());
2140 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
2142 endpar = sel_end_cursor.par()->Next();
2144 // cut more than one paragraph
2146 sel_end_cursor.par()
2147 ->BreakParagraphConservative(sel_end_cursor.pos());
2148 sel_end_cursor.par() = sel_end_cursor.par()->Next();
2149 sel_end_cursor.pos() = 0;
2151 cursor = sel_end_cursor;
2153 sel_start_cursor.par()
2154 ->BreakParagraphConservative(sel_start_cursor.pos());
2155 // store the endparagraph for redoing later
2156 endpar = sel_end_cursor.par()->Next(); /* needed because
2161 // store the selection
2162 simple_cut_buffer = sel_start_cursor.par()
2163 ->ParFromPos(sel_start_cursor.pos())->next;
2164 simple_cut_buffer->previous = 0;
2165 sel_end_cursor.par()->previous->next = 0;
2167 // cut the selection
2168 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->next
2169 = sel_end_cursor.par();
2171 sel_end_cursor.par()->previous
2172 = sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos());
2174 // care about footnotes
2175 if (simple_cut_buffer->footnoteflag) {
2176 LyXParagraph * tmppar = simple_cut_buffer;
2178 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2179 tmppar = tmppar->next;
2183 // the cut selection should begin with standard layout
2184 simple_cut_buffer->Clear();
2186 // paste the paragraphs again, if possible
2188 sel_start_cursor.par()->Next()->StripLeadingSpaces(simple_cut_buffer_textclass);
2189 if (sel_start_cursor.par()->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par()->Next())
2191 !sel_start_cursor.par()->Next()->Last())
2192 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())->PasteParagraph();
2195 // sometimes necessary
2197 sel_start_cursor.par()->StripLeadingSpaces(simple_cut_buffer_textclass);
2199 RedoParagraphs(sel_start_cursor, endpar);
2202 cursor = sel_start_cursor;
2203 SetCursor(cursor.par(), cursor.pos());
2204 sel_cursor = cursor;
2205 UpdateCounters(cursor.row());
2208 #else ///////////////////////////////////////////////////////////////////
2210 void LyXText::CutSelection(bool doclear)
2212 // This doesn't make sense, if there is no selection
2216 // OK, we have a selection. This is always between sel_start_cursor
2217 // and sel_end cursor
2218 LyXParagraph * tmppar;
2220 // Check whether there are half footnotes in the selection
2221 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2222 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2223 tmppar = sel_start_cursor.par();
2224 while (tmppar != sel_end_cursor.par()){
2225 if (tmppar->footnoteflag != sel_end_cursor.par()->footnoteflag) {
2226 WriteAlert(_("Impossible operation"),
2227 _("Don't know what to do with half floats."),
2231 tmppar = tmppar->Next();
2236 /* table stuff -- begin */
2237 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table) {
2238 if ( sel_start_cursor.par() != sel_end_cursor.par()) {
2239 WriteAlert(_("Impossible operation"),
2240 _("Don't know what to do with half tables."),
2244 sel_start_cursor.par()->table->Reinit();
2246 /* table stuff -- end */
2249 // make sure that the depth behind the selection are restored, too
2250 LyXParagraph * endpar = sel_end_cursor.par()->LastPhysicalPar()->Next();
2251 LyXParagraph * undoendpar = endpar;
2253 if (endpar && endpar->GetDepth()) {
2254 while (endpar && endpar->GetDepth()) {
2255 endpar = endpar->LastPhysicalPar()->Next();
2256 undoendpar = endpar;
2258 } else if (endpar) {
2259 endpar = endpar->Next(); // because of parindents etc.
2262 SetUndo(Undo::DELETE, sel_start_cursor
2263 .par()->ParFromPos(sel_start_cursor.pos())->previous, undoendpar);
2267 // there are two cases: cut only within one paragraph or
2268 // more than one paragraph
2269 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2270 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2271 // only within one paragraph
2272 endpar = sel_start_cursor.par();
2273 int pos = sel_end_cursor.pos();
2274 cap.cutSelection(sel_start_cursor.par(), &endpar,
2275 sel_start_cursor.pos(), pos,
2276 buffer()->params.textclass, doclear);
2277 sel_end_cursor.pos(pos);
2279 endpar = sel_end_cursor.par();
2281 int pos = sel_end_cursor.pos();
2282 cap.cutSelection(sel_start_cursor.par(), &endpar,
2283 sel_start_cursor.pos(), pos,
2284 buffer()->params.textclass, doclear);
2286 sel_end_cursor.par(endpar);
2287 sel_end_cursor.pos(pos);
2288 cursor.pos(sel_end_cursor.pos());
2290 endpar = endpar->Next();
2292 // sometimes necessary
2294 sel_start_cursor.par()->StripLeadingSpaces(buffer()->params.textclass);
2296 RedoParagraphs(sel_start_cursor, endpar);
2299 cursor = sel_start_cursor;
2300 SetCursor(cursor.par(), cursor.pos());
2301 sel_cursor = cursor;
2302 UpdateCounters(cursor.row());
2306 #ifdef USE_OLD_CUT_AND_PASTE
2307 void LyXText::CopySelection()
2309 // this doesnt make sense, if there is no selection
2313 // ok we have a selection. This is always between sel_start_cursor
2314 // and sel_end cursor
2315 LyXParagraph * tmppar;
2317 /* check wether there are half footnotes in the selection */
2318 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2319 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2320 tmppar = sel_start_cursor.par();
2321 while (tmppar != sel_end_cursor.par()) {
2322 if (tmppar->footnoteflag !=
2323 sel_end_cursor.par()->footnoteflag) {
2324 WriteAlert(_("Impossible operation"),
2325 _("Don't know what to do"
2326 " with half floats."),
2330 tmppar = tmppar->Next();
2335 /* table stuff -- begin */
2336 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2337 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2338 WriteAlert(_("Impossible operation"),
2339 _("Don't know what to do with half tables."),
2344 /* table stuff -- end */
2347 // delete the simple_cut_buffer
2348 DeleteSimpleCutBuffer();
2350 // set the textclass
2351 simple_cut_buffer_textclass = buffer()->params.textclass;
2353 // copy behind a space if there is one
2354 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2355 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2356 && (sel_start_cursor.par() != sel_end_cursor.par()
2357 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2358 sel_start_cursor.pos()++;
2360 // there are two cases: copy only within one paragraph
2361 // or more than one paragraph
2362 if (sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos())
2363 == sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())) {
2364 // only within one paragraph
2365 simple_cut_buffer = new LyXParagraph;
2366 LyXParagraph::size_type i = 0;
2367 for (i = sel_start_cursor.pos(); i < sel_end_cursor.pos(); ++i){
2368 sel_start_cursor.par()->CopyIntoMinibuffer(i);
2369 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos());
2372 // copy more than one paragraph
2373 // clone the paragraphs within the selection
2375 sel_start_cursor.par()->ParFromPos(sel_start_cursor.pos());
2376 simple_cut_buffer = tmppar->Clone();
2377 LyXParagraph *tmppar2 = simple_cut_buffer;
2379 while (tmppar != sel_end_cursor.par()->ParFromPos(sel_end_cursor.pos())
2381 tmppar = tmppar->next;
2382 tmppar2->next = tmppar->Clone();
2383 tmppar2->next->previous = tmppar2;
2384 tmppar2 = tmppar2->next;
2388 // care about footnotes
2389 if (simple_cut_buffer->footnoteflag) {
2390 tmppar = simple_cut_buffer;
2392 tmppar->footnoteflag =
2393 LyXParagraph::NO_FOOTNOTE;
2394 tmppar = tmppar->next;
2398 // the simple_cut_buffer paragraph is too big
2399 LyXParagraph::size_type tmpi2 =
2400 sel_start_cursor.par()->PositionInParFromPos(sel_start_cursor.pos());
2401 for (; tmpi2; --tmpi2)
2402 simple_cut_buffer->Erase(0);
2404 // now tmppar 2 is too big, delete all after sel_end_cursor.pos()
2406 tmpi2 = sel_end_cursor.par()->PositionInParFromPos(sel_end_cursor.pos());
2407 while (tmppar2->size() > tmpi2) {
2408 tmppar2->Erase(tmppar2->size() - 1);
2413 #else //////////////////////////////////////////////////////////////////////
2415 void LyXText::CopySelection()
2417 // this doesnt make sense, if there is no selection
2421 // ok we have a selection. This is always between sel_start_cursor
2422 // and sel_end cursor
2423 LyXParagraph * tmppar;
2425 /* check wether there are half footnotes in the selection */
2426 if (sel_start_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE
2427 || sel_end_cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2428 tmppar = sel_start_cursor.par();
2429 while (tmppar != sel_end_cursor.par()) {
2430 if (tmppar->footnoteflag !=
2431 sel_end_cursor.par()->footnoteflag) {
2432 WriteAlert(_("Impossible operation"),
2433 _("Don't know what to do"
2434 " with half floats."),
2438 tmppar = tmppar->Next();
2443 /* table stuff -- begin */
2444 if (sel_start_cursor.par()->table || sel_end_cursor.par()->table){
2445 if ( sel_start_cursor.par() != sel_end_cursor.par()){
2446 WriteAlert(_("Impossible operation"),
2447 _("Don't know what to do with half tables."),
2452 /* table stuff -- end */
2455 // copy behind a space if there is one
2456 while (sel_start_cursor.par()->Last() > sel_start_cursor.pos()
2457 && sel_start_cursor.par()->IsLineSeparator(sel_start_cursor.pos())
2458 && (sel_start_cursor.par() != sel_end_cursor.par()
2459 || sel_start_cursor.pos() < sel_end_cursor.pos()))
2460 sel_start_cursor.pos(sel_start_cursor.pos() + 1);
2464 cap.copySelection(sel_start_cursor.par(), sel_end_cursor.par(),
2465 sel_start_cursor.pos(), sel_end_cursor.pos(),
2466 buffer()->params.textclass);
2470 #ifdef USE_OLD_CUT_AND_PASTE
2471 void LyXText::PasteSelection()
2473 // this does not make sense, if there is nothing to paste
2474 if (!simple_cut_buffer)
2477 LyXParagraph * tmppar;
2478 LyXParagraph * endpar;
2480 LyXCursor tmpcursor;
2482 // be carefull with footnotes in footnotes
2483 if (cursor.par()->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2485 // check whether the cut_buffer includes a footnote
2486 tmppar = simple_cut_buffer;
2488 && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2489 tmppar = tmppar->next;
2492 WriteAlert(_("Impossible operation"),
2493 _("Can't paste float into float!"),
2500 /* table stuff -- begin */
2501 if (cursor.par()->table) {
2502 if (simple_cut_buffer->next) {
2503 WriteAlert(_("Impossible operation"),
2504 _("Table cell cannot include more than one paragraph!"),
2509 /* table stuff -- end */
2512 SetUndo(Undo::INSERT,
2513 cursor.par()->ParFromPos(cursor.pos())->previous,
2514 cursor.par()->ParFromPos(cursor.pos())->next);
2518 // There are two cases: cutbuffer only one paragraph or many
2519 if (!simple_cut_buffer->next) {
2520 // only within a paragraph
2522 tmppar = simple_cut_buffer->Clone();
2524 /* table stuff -- begin */
2525 bool table_too_small = false;
2526 if (tmpcursor.par()->table) {
2527 while (simple_cut_buffer->size()
2528 && !table_too_small) {
2529 if (simple_cut_buffer->IsNewline(0)){
2530 while(tmpcursor.pos() < tmpcursor.par()->Last() && !tmpcursor.par()->IsNewline(tmpcursor.pos()))
2532 simple_cut_buffer->Erase(0);
2533 if (tmpcursor.pos() < tmpcursor.par()->Last())
2536 table_too_small = true;
2538 // This is an attempt to fix the
2539 // "never insert a space at the
2540 // beginning of a paragraph" problem.
2541 if (tmpcursor.pos() == 0
2542 && simple_cut_buffer->IsLineSeparator(0)) {
2543 simple_cut_buffer->Erase(0);
2545 simple_cut_buffer->CutIntoMinibuffer(0);
2546 simple_cut_buffer->Erase(0);
2547 tmpcursor.par()->InsertFromMinibuffer(tmpcursor.pos());
2554 /* table stuff -- end */
2555 // Some provisions should be done here for checking
2556 // if we are inserting at the beginning of a
2557 // paragraph. If there are a space at the beginning
2558 // of the text to insert and we are inserting at
2559 // the beginning of the paragraph the space should
2561 while (simple_cut_buffer->size()) {
2562 // This is an attempt to fix the
2563 // "never insert a space at the
2564 // beginning of a paragraph" problem.
2565 if (tmpcursor.pos() == 0
2566 && simple_cut_buffer->IsLineSeparator(0)) {
2567 simple_cut_buffer->Erase(0);
2569 simple_cut_buffer->CutIntoMinibuffer(0);
2570 simple_cut_buffer->Erase(0);
2571 tmpcursor.par()->InsertFromMinibuffer(tmpcursor.pos());
2578 delete simple_cut_buffer;
2579 simple_cut_buffer = tmppar;
2580 endpar = tmpcursor.par()->Next();
2585 // make a copy of the simple cut_buffer
2586 tmppar = simple_cut_buffer;
2587 LyXParagraph * simple_cut_clone = tmppar->Clone();
2588 LyXParagraph * tmppar2 = simple_cut_clone;
2589 if (cursor.par()->footnoteflag){
2590 tmppar->footnoteflag = cursor.par()->footnoteflag;
2591 tmppar->footnotekind = cursor.par()->footnotekind;
2593 while (tmppar->next) {
2594 tmppar = tmppar->next;
2595 tmppar2->next = tmppar->Clone();
2596 tmppar2->next->previous = tmppar2;
2597 tmppar2 = tmppar2->next;
2598 if (cursor.par()->footnoteflag){
2599 tmppar->footnoteflag = cursor.par()->footnoteflag;
2600 tmppar->footnotekind = cursor.par()->footnotekind;
2604 // make sure there is no class difference
2605 cap.SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2606 buffer()->params.textclass,
2609 // make the simple_cut_buffer exactly the same layout than
2610 // the cursor paragraph
2611 simple_cut_buffer->MakeSameLayout(cursor.par());
2613 // find the end of the buffer
2614 LyXParagraph * lastbuffer = simple_cut_buffer;
2615 while (lastbuffer->Next())
2616 lastbuffer = lastbuffer->Next();
2618 bool paste_the_end = false;
2620 // open the paragraph for inserting the simple_cut_buffer
2622 if (cursor.par()->Last() > cursor.pos() || !cursor.par()->Next()){
2623 cursor.par()->BreakParagraphConservative(cursor.pos());
2624 paste_the_end = true;
2627 // set the end for redoing later
2628 endpar = cursor.par()->ParFromPos(cursor.pos())->next->Next();
2631 lastbuffer->ParFromPos(lastbuffer->Last())->next =
2632 cursor.par()->ParFromPos(cursor.pos())->next;
2633 cursor.par()->ParFromPos(cursor.pos())->next->previous =
2634 lastbuffer->ParFromPos(lastbuffer->Last());
2636 cursor.par()->ParFromPos(cursor.pos())->next = simple_cut_buffer;
2637 simple_cut_buffer->previous =
2638 cursor.par()->ParFromPos(cursor.pos());
2640 if (cursor.par()->ParFromPos(cursor.pos())->Next() == lastbuffer)
2641 lastbuffer = cursor.par();
2643 cursor.par()->ParFromPos(cursor.pos())->PasteParagraph();
2645 // store the new cursor position
2646 tmpcursor.par() = lastbuffer;
2647 tmpcursor.pos() = lastbuffer->Last();
2649 // maybe some pasting
2650 if (lastbuffer->Next() && paste_the_end) {
2651 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2652 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2654 } else if (!lastbuffer->Next()->Last()) {
2655 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2656 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2658 } else if (!lastbuffer->Last()) {
2659 lastbuffer->MakeSameLayout(lastbuffer->next);
2660 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2663 lastbuffer->Next()->StripLeadingSpaces(buffer->params.textclass);
2666 // restore the simple cut buffer
2667 simple_cut_buffer = simple_cut_clone;
2670 RedoParagraphs(cursor, endpar);
2672 SetCursor(cursor.par(), cursor.pos());
2675 sel_cursor = cursor;
2676 SetCursor(tmpcursor.par(), tmpcursor.pos());
2678 UpdateCounters(cursor.row());
2681 #else ////////////////////////////////////////////////////////////////////
2683 void LyXText::PasteSelection()
2687 // this does not make sense, if there is nothing to paste
2688 if (!cap.checkPastePossible(cursor.par(), cursor.pos()))
2691 SetUndo(Undo::INSERT,
2692 cursor.par()->ParFromPos(cursor.pos())->previous,
2693 cursor.par()->ParFromPos(cursor.pos())->next);
2695 LyXParagraph * endpar;
2696 LyXParagraph * actpar = cursor.par();
2697 int endpos = cursor.pos();
2699 int pos = cursor.pos();
2700 cap.pasteSelection(&actpar, &endpar, pos, buffer()->params.textclass);
2703 RedoParagraphs(cursor, endpar);
2705 SetCursor(cursor.par(), cursor.pos());
2708 sel_cursor = cursor;
2709 SetCursor(actpar, endpos);
2711 UpdateCounters(cursor.row());
2715 // returns a pointer to the very first LyXParagraph
2716 LyXParagraph * LyXText::FirstParagraph() const
2718 return buffer()->paragraph;
2722 // returns true if the specified string is at the specified position
2723 bool LyXText::IsStringInText(LyXParagraph * par,
2724 LyXParagraph::size_type pos,
2725 char const * str) const
2729 while (pos + i < par->Last() && str[i] &&
2730 str[i] == par->GetChar(pos + i)) {
2740 // sets the selection over the number of characters of string, no check!!
2741 void LyXText::SetSelectionOverString(char const * string)
2743 sel_cursor = cursor;
2744 for (int i = 0; string[i]; ++i)
2750 // simple replacing. The font of the first selected character is used
2751 void LyXText::ReplaceSelectionWithString(char const * str)
2756 if (!selection) { // create a dummy selection
2757 sel_end_cursor = cursor;
2758 sel_start_cursor = cursor;
2761 // Get font setting before we cut
2762 LyXParagraph::size_type pos = sel_end_cursor.pos();
2763 LyXFont font = sel_start_cursor.par()->GetFontSettings(buffer()->params,
2764 sel_start_cursor.pos());
2766 // Insert the new string
2767 for (int i = 0; str[i]; ++i) {
2768 sel_end_cursor.par()->InsertChar(pos, str[i]);
2769 sel_end_cursor.par()->SetFont(pos, font);
2773 // Cut the selection
2780 // if the string can be found: return true and set the cursor to
2782 bool LyXText::SearchForward(char const * str) const
2784 LyXParagraph * par = cursor.par();
2785 LyXParagraph::size_type pos = cursor.pos();
2786 while (par && !IsStringInText(par, pos, str)) {
2787 if (pos < par->Last() - 1)
2795 SetCursor(par, pos);
2803 bool LyXText::SearchBackward(char const * string) const
2805 LyXParagraph * par = cursor.par();
2806 int pos = cursor.pos();
2812 // We skip empty paragraphs (Asger)
2814 par = par->Previous();
2816 pos = par->Last() - 1;
2817 } while (par && pos < 0);
2819 } while (par && !IsStringInText(par, pos, string));
2822 SetCursor(par, pos);
2829 // needed to insert the selection
2830 void LyXText::InsertStringA(string const & str)
2832 LyXParagraph * par = cursor.par();
2833 LyXParagraph::size_type pos = cursor.pos();
2834 LyXParagraph::size_type a = 0;
2836 LyXParagraph * endpar = cursor.par()->Next();
2841 textclasslist.Style(buffer()->params.textclass,
2842 cursor.par()->GetLayout()).isEnvironment();
2843 // only to be sure, should not be neccessary
2846 // insert the string, don't insert doublespace
2847 string::size_type i = 0;
2848 while (i < str.length()) {
2849 if (str[i] != '\n') {
2851 && i + 1 < str.length() && str[i + 1] != ' '
2852 && pos && par->GetChar(pos - 1)!= ' ') {
2853 par->InsertChar(pos,' ');
2854 par->SetFont(pos, current_font);
2857 } else if (par->table) {
2858 if (str[i] == '\t') {
2859 while((pos < par->size()) &&
2860 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2862 if (pos < par->size())
2864 else // no more fields to fill skip the rest
2866 } else if ((str[i] != 13) &&
2867 ((str[i] & 127) >= ' ')) {
2868 par->InsertChar(pos, str[i]);
2869 par->SetFont(pos, current_font);
2873 } else if (str[i] == ' ') {
2874 InsetSpecialChar * new_inset =
2875 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2876 if (par->InsertInsetAllowed(new_inset)) {
2877 par->InsertChar(pos, LyXParagraph::META_INSET);
2878 par->SetFont(pos, current_font);
2879 par->InsertInset(pos, new_inset);
2884 } else if (str[i] == '\t') {
2885 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2886 InsetSpecialChar * new_inset =
2887 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2888 if (par->InsertInsetAllowed(new_inset)) {
2889 par->InsertChar(pos, LyXParagraph::META_INSET);
2890 par->SetFont(pos, current_font);
2891 par->InsertInset(pos, new_inset);
2897 } else if (str[i] != 13 &&
2898 // Ignore unprintables
2899 (str[i] & 127) >= ' ') {
2900 par->InsertChar(pos, str[i]);
2901 par->SetFont(pos, current_font);
2907 if ((i + 1) >= str.length()) {
2908 if (pos < par->size())
2912 while((pos < par->size()) &&
2913 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2916 cell = NumberOfCell(par, pos);
2917 while((pos < par->size()) &&
2918 !(par->table->IsFirstCell(cell))) {
2920 while((pos < par->size()) &&
2921 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2924 cell = NumberOfCell(par, pos);
2926 if (pos >= par->size())
2927 // no more fields to fill skip the rest
2931 if (!par->size()) { // par is empty
2932 InsetSpecialChar * new_inset =
2933 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2934 if (par->InsertInsetAllowed(new_inset)) {
2935 par->InsertChar(pos, LyXParagraph::META_INSET);
2936 par->SetFont(pos, current_font);
2937 par->InsertInset(pos, new_inset);
2943 par->BreakParagraph(buffer()->params, pos, flag);
2953 RedoParagraphs(cursor, endpar);
2954 SetCursor(cursor.par(), cursor.pos());
2955 sel_cursor = cursor;
2956 SetCursor(par, pos);
2961 /* turns double-CR to single CR, others where converted into one blank and 13s
2962 * that are ignored .Double spaces are also converted into one. Spaces at
2963 * the beginning of a paragraph are forbidden. tabs are converted into one
2964 * space. then InsertStringA is called */
2965 void LyXText::InsertStringB(string const & s)
2968 LyXParagraph * par = cursor.par();
2969 string::size_type i = 1;
2970 while (i < str.length()) {
2971 if (str[i] == '\t' && !par->table)
2973 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2975 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2976 if (str[i + 1] != '\n') {
2977 if (str[i - 1] != ' ')
2982 while (i + 1 < str.length()
2983 && (str[i + 1] == ' '
2984 || str[i + 1] == '\t'
2985 || str[i + 1] == '\n'
2986 || str[i + 1] == 13)) {
2997 bool LyXText::GotoNextError() const
2999 LyXCursor res = cursor;
3001 if (res.pos() < res.par()->Last() - 1) {
3002 res.pos(res.pos() + 1);
3004 res.par(res.par()->Next());
3008 } while (res.par() &&
3009 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
3010 && res.par()->GetInset(res.pos())->AutoDelete()));
3013 SetCursor(res.par(), res.pos());
3020 bool LyXText::GotoNextNote() const
3022 LyXCursor res = cursor;
3024 if (res.pos() < res.par()->Last() - 1) {
3025 res.pos(res.pos() + 1);
3027 res.par(res.par()->Next());
3031 } while (res.par() &&
3032 !(res.par()->GetChar(res.pos()) == LyXParagraph::META_INSET
3033 && res.par()->GetInset(res.pos())->LyxCode() == Inset::IGNORE_CODE));
3036 SetCursor(res.par(), res.pos());
3043 void LyXText::CheckParagraph(LyXParagraph * par,
3044 LyXParagraph::size_type pos)
3046 LyXCursor tmpcursor;
3049 /* table stuff -- begin*/
3052 CheckParagraphInTable(par, pos);
3056 /* table stuff -- end*/
3059 LyXParagraph::size_type z;
3060 Row * row = GetRow(par, pos, y);
3062 // is there a break one row above
3063 if (row->previous() && row->previous()->par() == row->par()) {
3064 z = NextBreakPoint(row->previous(), paperwidth);
3065 if ( z >= row->pos()) {
3066 // set the dimensions of the row above
3067 y -= row->previous()->height();
3069 refresh_row = row->previous();
3070 status = LyXText::NEED_MORE_REFRESH;
3072 BreakAgain(row->previous());
3074 // set the cursor again. Otherwise
3075 // dangling pointers are possible
3076 SetCursor(cursor.par(), cursor.pos());
3077 sel_cursor = cursor;
3082 int tmpheight = row->height();
3083 LyXParagraph::size_type tmplast = RowLast(row);
3088 if (row->height() == tmpheight && RowLast(row) == tmplast)
3089 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3091 status = LyXText::NEED_MORE_REFRESH;
3093 // check the special right address boxes
3094 if (textclasslist.Style(buffer()->params.textclass,
3095 par->GetLayout()).margintype
3096 == MARGIN_RIGHT_ADDRESS_BOX) {
3103 RedoDrawingOfParagraph(tmpcursor);
3109 // set the cursor again. Otherwise dangling pointers are possible
3110 // also set the selection
3114 SetCursorIntern(sel_cursor.par(), sel_cursor.pos());
3115 sel_cursor = cursor;
3116 SetCursorIntern(sel_start_cursor.par(), sel_start_cursor.pos());
3117 sel_start_cursor = cursor;
3118 SetCursorIntern(sel_end_cursor.par(), sel_end_cursor.pos());
3119 sel_end_cursor = cursor;
3120 SetCursorIntern(last_sel_cursor.par(), last_sel_cursor.pos());
3121 last_sel_cursor = cursor;
3124 SetCursorIntern(cursor.par(), cursor.pos());
3128 // returns 0 if inset wasn't found
3129 int LyXText::UpdateInset(Inset * inset)
3131 // first check the current paragraph
3132 int pos = cursor.par()->GetPositionOfInset(inset);
3134 CheckParagraph(cursor.par(), pos);
3138 // check every paragraph
3140 LyXParagraph * par = FirstParagraph();
3142 // make sure the paragraph is open
3143 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
3144 pos = par->GetPositionOfInset(inset);
3146 CheckParagraph(par, pos);
3157 void LyXText::SetCursor(LyXParagraph * par,
3158 LyXParagraph::size_type pos,
3159 bool setfont, bool boundary) const
3161 LyXCursor old_cursor = cursor;
3162 SetCursorIntern(par, pos, setfont, boundary);
3163 DeleteEmptyParagraphMechanism(old_cursor);
3167 void LyXText::SetCursor(LyXCursor & cur, LyXParagraph * par,
3168 LyXParagraph::size_type pos, bool boundary) const
3170 // correct the cursor position if impossible
3171 if (pos > par->Last()){
3172 LyXParagraph * tmppar = par->ParFromPos(pos);
3173 pos = par->PositionInParFromPos(pos);
3176 if (par->IsDummy() && par->previous &&
3177 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3178 while (par->previous &&
3179 ((par->previous->IsDummy() &&
3180 (par->previous->previous->footnoteflag ==
3181 LyXParagraph::CLOSED_FOOTNOTE)) ||
3182 (par->previous->footnoteflag ==
3183 LyXParagraph::CLOSED_FOOTNOTE))) {
3184 par = par->previous ;
3185 if (par->IsDummy() &&
3186 (par->previous->footnoteflag ==
3187 LyXParagraph::CLOSED_FOOTNOTE))
3188 pos += par->size() + 1;
3190 if (par->previous) {
3191 par = par->previous;
3193 pos += par->size() + 1;
3198 cur.boundary(boundary);
3200 /* get the cursor y position in text */
3202 Row * row = GetRow(par, pos, y);
3203 /* y is now the beginning of the cursor row */
3204 y += row->baseline();
3205 /* y is now the cursor baseline */
3208 /* now get the cursors x position */
3210 float fill_separator, fill_hfill, fill_label_hfill;
3211 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3212 LyXParagraph::size_type cursor_vpos = 0;
3213 LyXParagraph::size_type last = RowLastPrintable(row);
3215 if (pos > last + 1) // This shouldn't happen.
3217 else if (pos < row->pos())
3220 if (last < row->pos())
3221 cursor_vpos = row->pos();
3222 else if (pos > last && !boundary)
3223 cursor_vpos = (row->par()->isRightToLeftPar(buffer()->params))
3224 ? row->pos() : last + 1;
3225 else if (pos > row->pos() &&
3226 (pos > last || boundary ||
3227 (row->par()->table && row->par()->IsNewline(pos))))
3228 /// Place cursor after char at (logical) position pos - 1
3229 cursor_vpos = (bidi_level(pos - 1) % 2 == 0)
3230 ? log2vis(pos - 1) + 1 : log2vis(pos - 1);
3232 /// Place cursor before char at (logical) position pos
3233 cursor_vpos = (bidi_level(pos) % 2 == 0)
3234 ? log2vis(pos) : log2vis(pos) + 1;
3237 /* table stuff -- begin*/
3238 if (row->par()->table) {
3239 int cell = NumberOfCell(row->par(), row->pos());
3241 x += row->par()->table->GetBeginningOfTextInCell(cell);
3242 for (LyXParagraph::size_type vpos = row->pos();
3243 vpos < cursor_vpos; ++vpos) {
3244 pos = vis2log(vpos);
3245 if (row->par()->IsNewline(pos)) {
3246 x = x_old + row->par()->table->WidthOfColumn(cell);
3249 x += row->par()->table->GetBeginningOfTextInCell(cell);
3251 x += SingleWidth(row->par(), pos);
3255 /* table stuff -- end*/
3257 LyXParagraph::size_type main_body =
3258 BeginningOfMainBody(row->par());
3259 if ((main_body > 0) &&
3260 ((main_body-1 > last) ||
3261 !row->par()->IsLineSeparator(main_body-1)))
3264 for (LyXParagraph::size_type vpos = row->pos();
3265 vpos < cursor_vpos; ++vpos) {
3266 pos = vis2log(vpos);
3267 if (main_body > 0 && pos == main_body-1) {
3268 x += fill_label_hfill +
3269 lyxfont::width(textclasslist.Style(
3270 buffer()->params.textclass,
3271 row->par()->GetLayout())
3273 GetFont(row->par(), -2));
3274 if (row->par()->IsLineSeparator(main_body-1))
3275 x -= SingleWidth(row->par(),main_body-1);
3277 if (HfillExpansion(row, pos)) {
3278 x += SingleWidth(row->par(), pos);
3279 if (pos >= main_body)
3282 x += fill_label_hfill;
3283 } else if (row->par()->IsSeparator(pos)) {
3284 x += SingleWidth(row->par(), pos);
3285 if (pos >= main_body)
3286 x += fill_separator;
3288 x += SingleWidth(row->par(), pos);
3300 void LyXText::SetCursorIntern(LyXParagraph * par,
3301 LyXParagraph::size_type pos,
3302 bool setfont, bool boundary) const
3304 SetCursor(cursor, par, pos, boundary);
3305 // #warning Remove this when verified working (Jug 20000413)
3307 // correct the cursor position if impossible
3308 if (pos > par->Last()){
3309 LyXParagraph * tmppar = par->ParFromPos(pos);
3310 pos = par->PositionInParFromPos(pos);
3313 if (par->IsDummy() && par->previous &&
3314 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3315 while (par->previous &&
3316 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
3317 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
3318 par = par->previous ;
3319 if (par->IsDummy() &&
3320 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3321 pos += par->size() + 1;
3323 if (par->previous) {
3324 par = par->previous;
3326 pos += par->size() + 1;
3332 /* get the cursor y position in text */
3334 Row * row = GetRow(par, pos, y);
3335 /* y is now the beginning of the cursor row */
3336 y += row->baseline();
3337 /* y is now the cursor baseline */
3340 /* now get the cursors x position */
3342 float fill_separator, fill_hfill, fill_label_hfill;
3343 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3344 LyXParagraph::size_type cursor_vpos;
3345 LyXParagraph::size_type last = RowLastPrintable(row);
3347 if (pos > last + 1) // This shouldn't happen.
3350 if (last < row->pos())
3352 else if (pos > last ||
3353 (pos - 1 >= row->pos() &&
3354 (row->par()->IsSeparator(pos) ||
3355 (row->par()->table && row->par()->IsNewline(pos))
3357 /// Place cursor after char at (logical) position pos-1
3358 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
3359 ? log2vis(pos-1) + 1 : log2vis(pos-1);
3361 /// Place cursor before char at (logical) position pos
3362 cursor_vpos = (bidi_level(pos) % 2 == 0)
3363 ? log2vis(pos) : log2vis(pos) + 1;
3366 /* table stuff -- begin*/
3367 if (row->par()->table) {
3368 int cell = NumberOfCell(row->par(), row->pos());
3370 x += row->par()->table->GetBeginningOfTextInCell(cell);
3371 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos) {
3372 pos = vis2log(vpos);
3373 if (row->par()->IsNewline(pos)) {
3374 x = x_old + row->par()->table->WidthOfColumn(cell);
3377 x += row->par()->table->GetBeginningOfTextInCell(cell);
3379 x += SingleWidth(row->par(), pos);
3383 /* table stuff -- end*/
3385 LyXParagraph::size_type main_body =
3386 BeginningOfMainBody(row->par());
3387 if (main_body > 0 &&
3388 (main_body-1 > last ||
3389 !row->par()->IsLineSeparator(main_body-1)))
3392 for (LyXParagraph::size_type vpos = row->pos(); vpos < cursor_vpos; ++vpos) {
3393 pos = vis2log(vpos);
3394 if (main_body > 0 && pos == main_body-1) {
3395 x += fill_label_hfill +
3396 lyxfont::width(textclasslist
3397 .Style(buffer()->params.textclass,
3398 row->par()->GetLayout())
3400 GetFont(row->par(), -2));
3401 if (row->par()->IsLineSeparator(main_body-1))
3402 x -= SingleWidth(row->par(), main_body-1);
3404 if (HfillExpansion(row, pos)) {
3405 x += SingleWidth(row->par(), pos);
3406 if (pos >= main_body)
3409 x += fill_label_hfill;
3411 else if (row->par()->IsSeparator(pos)) {
3412 x += SingleWidth(row->par(), pos);
3413 if (pos >= main_body)
3414 x += fill_separator;
3416 x += SingleWidth(row->par(), pos);
3423 cursor.x_fix = cursor.x;
3430 void LyXText::SetCurrentFont() const
3432 LyXParagraph::size_type pos = cursor.pos();
3433 if (cursor.boundary() && pos > 0)
3437 if (pos == cursor.par()->Last() ||
3438 (cursor.par()->table && cursor.par()->IsNewline(pos)))
3440 else if (cursor.par()->IsSeparator(pos)) {
3441 if (pos > cursor.row()->pos() &&
3442 bidi_level(pos) % 2 ==
3443 bidi_level(pos - 1) % 2)
3445 else if (pos + 1 < cursor.par()->Last())
3450 current_font = cursor.par()->GetFontSettings(buffer()->params, pos);
3451 real_current_font = GetFont(cursor.par(), pos);
3455 void LyXText::SetCursorFromCoordinates(int x, long y) const
3457 LyXCursor old_cursor = cursor;
3459 /* get the row first */
3461 Row * row = GetRowNearY(y);
3462 cursor.par(row->par());
3465 int column = GetColumnNearX(row, x, bound);
3466 cursor.pos(row->pos() + column);
3468 cursor.y(y + row->baseline());
3470 cursor.boundary(bound);
3472 DeleteEmptyParagraphMechanism(old_cursor);
3476 void LyXText::SetCursorFromCoordinates(LyXCursor & cur, int x, long y) const
3478 /* get the row first */
3480 Row * row = GetRowNearY(y);
3482 int column = GetColumnNearX(row, x, bound);
3484 cur.par(row->par());
3485 cur.pos(row->pos() + column);
3487 cur.y(y + row->baseline());
3489 cur.boundary(bound);
3493 void LyXText::CursorLeft(bool internal) const
3495 CursorLeftIntern(internal);
3497 if (cursor.par()->table) {
3498 int cell = NumberOfCell(cursor.par(), cursor.pos());
3499 if (cursor.par()->table->IsContRow(cell)
3500 && cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell)) < 0) {
3508 void LyXText::CursorLeftIntern(bool internal) const
3510 if (cursor.pos() > 0) {
3511 bool boundary = cursor.boundary();
3512 SetCursor(cursor.par(), cursor.pos() - 1, true, false);
3513 if (!internal && !boundary &&
3514 IsBoundary(cursor.par(), cursor.pos() + 1))
3515 SetCursor(cursor.par(), cursor.pos() + 1, true, true);
3516 } else if (cursor.par()->Previous()) { // steps into the above paragraph.
3517 LyXParagraph * par = cursor.par()->Previous();
3518 LyXParagraph::size_type pos = par->Last();
3519 SetCursor(par, pos);
3520 if (IsBoundary(par, pos))
3521 SetCursor(par, pos, false, true);
3526 void LyXText::CursorRight(bool internal) const
3528 CursorRightIntern(internal);
3530 if (cursor.par()->table) {
3531 int cell = NumberOfCell(cursor.par(), cursor.pos());
3532 if (cursor.par()->table->IsContRow(cell) &&
3533 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3541 void LyXText::CursorRightIntern(bool internal) const
3543 if (cursor.pos() < cursor.par()->Last()) {
3544 if (!internal && cursor.boundary() &&
3545 (!cursor.par()->table || !cursor.par()->IsNewline(cursor.pos())))
3546 SetCursor(cursor.par(), cursor.pos(), true, false);
3548 SetCursor(cursor.par(), cursor.pos() + 1, true, false);
3549 if (!internal && IsBoundary(cursor.par(), cursor.pos()))
3550 SetCursor(cursor.par(), cursor.pos(), true, true);
3552 } else if (cursor.par()->Next())
3553 SetCursor(cursor.par()->Next(), 0);
3557 void LyXText::CursorUp() const
3559 SetCursorFromCoordinates(cursor.x_fix(),
3560 cursor.y() - cursor.row()->baseline() - 1);
3562 if (cursor.par()->table) {
3563 int cell = NumberOfCell(cursor.par(), cursor.pos());
3564 if (cursor.par()->table->IsContRow(cell) &&
3565 cursor.par()->table->CellHasContRow(cursor.par()->table->GetCellAbove(cell))<0) {
3573 void LyXText::CursorDown() const
3576 if (cursor.par()->table &&
3577 cursor.par()->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par(), cursor.pos())) &&
3578 !cursor.par()->next)
3582 SetCursorFromCoordinates(cursor.x_fix(),
3583 cursor.y() - cursor.row()->baseline()
3584 + cursor.row()->height() + 1);
3586 if (cursor.par()->table) {
3587 int cell = NumberOfCell(cursor.par(), cursor.pos());
3588 int cell_above = cursor.par()->table->GetCellAbove(cell);
3589 while(cursor.par()->table &&
3590 cursor.par()->table->IsContRow(cell) &&
3591 (cursor.par()->table->CellHasContRow(cell_above)<0)) {
3592 SetCursorFromCoordinates(cursor.x_fix(),
3593 cursor.y() - cursor.row()->baseline()
3594 + cursor.row()->height() + 1);
3595 if (cursor.par()->table) {
3596 cell = NumberOfCell(cursor.par(), cursor.pos());
3597 cell_above = cursor.par()->table->GetCellAbove(cell);
3605 void LyXText::CursorUpParagraph() const
3607 if (cursor.pos() > 0) {
3608 SetCursor(cursor.par(), 0);
3610 else if (cursor.par()->Previous()) {
3611 SetCursor(cursor.par()->Previous(), 0);
3616 void LyXText::CursorDownParagraph() const
3618 if (cursor.par()->Next()) {
3619 SetCursor(cursor.par()->Next(), 0);
3621 SetCursor(cursor.par(), cursor.par()->Last());
3626 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3628 // Would be wrong to delete anything if we have a selection.
3629 if (selection) return;
3631 // We allow all kinds of "mumbo-jumbo" when freespacing.
3632 if (textclasslist.Style(buffer()->params.textclass,
3633 old_cursor.par()->GetLayout()).free_spacing)
3636 bool deleted = false;
3638 /* Ok I'll put some comments here about what is missing.
3639 I have fixed BackSpace (and thus Delete) to not delete
3640 double-spaces automagically. I have also changed Cut,
3641 Copy and Paste to hopefully do some sensible things.
3642 There are still some small problems that can lead to
3643 double spaces stored in the document file or space at
3644 the beginning of paragraphs. This happens if you have
3645 the cursor betwenn to spaces and then save. Or if you
3646 cut and paste and the selection have a space at the
3647 beginning and then save right after the paste. I am
3648 sure none of these are very hard to fix, but I will
3649 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3650 that I can get some feedback. (Lgb)
3653 // If old_cursor.pos() == 0 and old_cursor.pos()(1) == LineSeparator
3654 // delete the LineSeparator.
3657 // If old_cursor.pos() == 1 and old_cursor.pos()(0) == LineSeparator
3658 // delete the LineSeparator.
3661 // If the pos around the old_cursor were spaces, delete one of them.
3662 if (old_cursor.par() != cursor.par() || old_cursor.pos() != cursor.pos()) {
3663 // Only if the cursor has really moved
3665 if (old_cursor.pos() > 0
3666 && old_cursor.pos() < old_cursor.par()->Last()
3667 && old_cursor.par()->IsLineSeparator(old_cursor.pos())
3668 && old_cursor.par()->IsLineSeparator(old_cursor.pos() - 1)) {
3669 old_cursor.par()->Erase(old_cursor.pos() - 1);
3670 RedoParagraphs(old_cursor, old_cursor.par()->Next());
3672 if (old_cursor.par() == cursor.par() &&
3673 cursor.pos() > old_cursor.pos()) {
3674 SetCursorIntern(cursor.par(), cursor.pos() - 1);
3676 SetCursorIntern(cursor.par(), cursor.pos());
3681 // Do not delete empty paragraphs with keepempty set.
3682 if ((textclasslist.Style(buffer()->params.textclass,
3683 old_cursor.par()->GetLayout())).keepempty)
3686 LyXCursor tmpcursor;
3688 if (old_cursor.par() != cursor.par()) {
3689 if ( (old_cursor.par()->Last() == 0
3690 || (old_cursor.par()->Last() == 1
3691 && old_cursor.par()->IsLineSeparator(0)))
3692 && old_cursor.par()->FirstPhysicalPar()
3693 == old_cursor.par()->LastPhysicalPar()) {
3694 // ok, we will delete anything
3696 // make sure that you do not delete any environments
3697 if ((old_cursor.par()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3698 !(old_cursor.row()->previous()
3699 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3700 && !(old_cursor.row()->next()
3701 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3702 || (old_cursor.par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3703 && ((old_cursor.row()->previous()
3704 && old_cursor.row()->previous()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3705 || (old_cursor.row()->next()
3706 && old_cursor.row()->next()->par()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3708 status = LyXText::NEED_MORE_REFRESH;
3711 if (old_cursor.row()->previous()) {
3712 refresh_row = old_cursor.row()->previous();
3713 refresh_y = old_cursor.y() - old_cursor.row()->baseline() - refresh_row->height();
3715 cursor = old_cursor; // that undo can restore the right cursor position
3716 LyXParagraph * endpar = old_cursor.par()->next;
3717 if (endpar && endpar->GetDepth()) {
3718 while (endpar && endpar->GetDepth()) {
3719 endpar = endpar->LastPhysicalPar()->Next();
3722 SetUndo(Undo::DELETE,
3723 old_cursor.par()->previous,
3728 RemoveRow(old_cursor.row());
3729 if (buffer()->paragraph == old_cursor.par()) {
3730 buffer_->paragraph = buffer_->paragraph->next;
3733 delete old_cursor.par();
3735 /* Breakagain the next par. Needed
3736 * because of the parindent that
3737 * can occur or dissappear. The
3738 * next row can change its height,
3739 * if there is another layout before */
3740 if (refresh_row->next()) {
3741 BreakAgain(refresh_row->next());
3742 UpdateCounters(refresh_row);
3744 SetHeightOfRow(refresh_row);
3746 refresh_row = old_cursor.row()->next();
3747 refresh_y = old_cursor.y() - old_cursor.row()->baseline();
3750 cursor = old_cursor; // that undo can restore the right cursor position
3751 LyXParagraph * endpar = old_cursor.par()->next;
3752 if (endpar && endpar->GetDepth()) {
3753 while (endpar && endpar->GetDepth()) {
3754 endpar = endpar->LastPhysicalPar()->Next();
3757 SetUndo(Undo::DELETE,
3758 old_cursor.par()->previous,
3763 RemoveRow(old_cursor.row());
3765 if (buffer()->paragraph == old_cursor.par()) {
3766 buffer_->paragraph = buffer_->paragraph->next;
3768 delete old_cursor.par();
3770 /* Breakagain the next par. Needed
3771 because of the parindent that can
3772 occur or dissappear.
3773 The next row can change its height,
3774 if there is another layout before
3777 BreakAgain(refresh_row);
3778 UpdateCounters(refresh_row->previous());
3784 SetCursorIntern(cursor.par(), cursor.pos());
3786 if (sel_cursor.par() == old_cursor.par()
3787 && sel_cursor.pos() == sel_cursor.pos()) {
3788 // correct selection
3789 sel_cursor = cursor;
3794 if (old_cursor.par()->StripLeadingSpaces(buffer()->params.textclass)) {
3795 RedoParagraphs(old_cursor, old_cursor.par()->Next());
3797 SetCursorIntern(cursor.par(), cursor.pos());
3798 sel_cursor = cursor;
3805 LyXParagraph * LyXText::GetParFromID(int id)
3807 LyXParagraph * result = FirstParagraph();
3808 while (result && result->id() != id)
3809 result = result->next;
3815 bool LyXText::TextUndo()
3817 // returns false if no undo possible
3818 Undo * undo = buffer_->undostack.pop();
3823 .push(CreateUndo(undo->kind,
3824 GetParFromID(undo->number_of_before_par),
3825 GetParFromID(undo->number_of_behind_par)));
3827 return TextHandleUndo(undo);
3831 bool LyXText::TextRedo()
3833 // returns false if no redo possible
3834 Undo * undo = buffer_->redostack.pop();
3839 .push(CreateUndo(undo->kind,
3840 GetParFromID(undo->number_of_before_par),
3841 GetParFromID(undo->number_of_behind_par)));
3843 return TextHandleUndo(undo);
3847 bool LyXText::TextHandleUndo(Undo * undo)
3849 // returns false if no undo possible
3850 bool result = false;
3852 LyXParagraph * before =
3853 GetParFromID(undo->number_of_before_par);
3854 LyXParagraph * behind =
3855 GetParFromID(undo->number_of_behind_par);
3856 LyXParagraph * tmppar;
3857 LyXParagraph * tmppar2;
3858 LyXParagraph * endpar;
3859 LyXParagraph * tmppar5;
3861 // if there's no before take the beginning
3862 // of the document for redoing
3864 SetCursorIntern(FirstParagraph(), 0);
3866 // replace the paragraphs with the undo informations
3868 LyXParagraph * tmppar3 = undo->par;
3869 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3870 LyXParagraph * tmppar4 = tmppar3;
3872 while (tmppar4->next)
3873 tmppar4 = tmppar4->next;
3874 } // get last undo par
3876 // now remove the old text if there is any
3877 if (before != behind || (!behind && !before)){
3879 tmppar5 = before->next;
3881 tmppar5 = buffer()->paragraph;
3883 while (tmppar5 && tmppar5 != behind){
3885 tmppar5 = tmppar5->next;
3886 // a memory optimization for edit: Only layout information
3887 // is stored in the undo. So restore the text informations.
3888 if (undo->kind == Undo::EDIT) {
3889 tmppar2->setContentsFromPar(tmppar);
3890 tmppar->clearContents();
3891 tmppar2 = tmppar2->next;
3896 // put the new stuff in the list if there is one
3899 before->next = tmppar3;
3901 buffer_->paragraph = tmppar3;
3902 tmppar3->previous = before;
3906 buffer_->paragraph = behind;
3909 tmppar4->next = behind;
3911 behind->previous = tmppar4;
3915 // Set the cursor for redoing
3917 SetCursorIntern(before->FirstSelfrowPar(), 0);
3918 // check wether before points to a closed float and open it if necessary
3919 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3920 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3922 while (tmppar4->previous &&
3923 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3924 tmppar4 = tmppar4->previous;
3925 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3926 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3927 tmppar4 = tmppar4->next;
3932 // open a cosed footnote at the end if necessary
3933 if (behind && behind->previous &&
3934 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3935 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3936 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3937 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3938 behind = behind->next;
3942 // calculate the endpar for redoing the paragraphs.
3944 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3945 endpar = behind->LastPhysicalPar()->Next();
3947 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3951 tmppar = GetParFromID(undo->number_of_cursor_par);
3952 RedoParagraphs(cursor, endpar);
3954 SetCursorIntern(tmppar, undo->cursor_pos);
3955 UpdateCounters(cursor.row());
3965 void LyXText::FinishUndo()
3967 // makes sure the next operation will be stored
3968 undo_finished = true;
3972 void LyXText::FreezeUndo()
3974 // this is dangerous and for internal use only
3979 void LyXText::UnFreezeUndo()
3981 // this is dangerous and for internal use only
3982 undo_frozen = false;
3986 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3987 LyXParagraph const * behind) const
3990 buffer_->undostack.push(CreateUndo(kind, before, behind));
3991 buffer_->redostack.clear();
3995 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3996 LyXParagraph const * behind)
3998 buffer_->redostack.push(CreateUndo(kind, before, behind));
4002 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
4003 LyXParagraph const * behind) const
4005 int before_number = -1;
4006 int behind_number = -1;
4008 before_number = before->id();
4010 behind_number = behind->id();
4011 // Undo::EDIT and Undo::FINISH are
4012 // always finished. (no overlapping there)
4013 // overlapping only with insert and delete inside one paragraph:
4014 // Nobody wants all removed character
4015 // appear one by one when undoing.
4016 // EDIT is special since only layout information, not the
4017 // contents of a paragaph are stored.
4018 if (!undo_finished && kind != Undo::EDIT &&
4019 kind != Undo::FINISH){
4020 // check wether storing is needed
4021 if (!buffer()->undostack.empty() &&
4022 buffer_->undostack.top()->kind == kind &&
4023 buffer_->undostack.top()->number_of_before_par == before_number &&
4024 buffer_->undostack.top()->number_of_behind_par == behind_number ){
4029 // create a new Undo
4030 LyXParagraph * undopar;
4031 LyXParagraph * tmppar;
4032 LyXParagraph * tmppar2;
4034 LyXParagraph * start = 0;
4035 LyXParagraph * end = 0;
4038 start = before->next;
4040 start = FirstParagraph();
4042 end = behind->previous;
4044 end = FirstParagraph();
4050 && start != end->next
4051 && (before != behind || (!before && !behind))) {
4053 tmppar2 = tmppar->Clone();
4054 tmppar2->id(tmppar->id());
4056 // a memory optimization: Just store the layout information
4058 if (kind == Undo::EDIT){
4059 //tmppar2->text.clear();
4060 tmppar2->clearContents();
4065 while (tmppar != end && tmppar->next) {
4066 tmppar = tmppar->next;
4067 tmppar2->next = tmppar->Clone();
4068 tmppar2->next->id(tmppar->id());
4069 // a memory optimization: Just store the layout
4070 // information when only edit
4071 if (kind == Undo::EDIT){
4072 //tmppar2->next->text.clear();
4073 tmppar2->clearContents();
4075 tmppar2->next->previous = tmppar2;
4076 tmppar2 = tmppar2->next;
4080 undopar = 0; // nothing to replace (undo of delete maybe)
4082 int cursor_par = cursor.par()->ParFromPos(cursor.pos())->id();
4083 int cursor_pos = cursor.par()->PositionInParFromPos(cursor.pos());
4085 Undo * undo = new Undo(kind,
4086 before_number, behind_number,
4087 cursor_par, cursor_pos,
4090 undo_finished = false;
4095 void LyXText::SetCursorParUndo()
4097 SetUndo(Undo::FINISH,
4098 cursor.par()->ParFromPos(cursor.pos())->previous,
4099 cursor.par()->ParFromPos(cursor.pos())->next);
4104 void LyXText::RemoveTableRow(LyXCursor & cur) const
4110 // move to the previous row
4111 int cell_act = NumberOfCell(cur.par(), cur.pos());
4114 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
4115 cur.pos(cur.pos() - 1);
4117 !cur.par()->table->IsFirstCell(cell_act)) {
4118 cur.pos(cur.pos() - 1);
4119 while (cur.pos() && !cur.par()->IsNewline(cur.pos() - 1))
4120 cur.pos(cur.pos() - 1);
4124 // now we have to pay attention if the actual table is the
4125 // main row of TableContRows and if yes to delete all of them
4130 // delete up to the next row
4131 while (cur.pos() < cur.par()->Last() &&
4133 || !cur.par()->table->IsFirstCell(cell_act))) {
4134 while (cur.pos() < cur.par()->Last() &&
4135 !cur.par()->IsNewline(cur.pos()))
4136 cur.par()->Erase(cur.pos());
4139 if (cur.pos() < cur.par()->Last())
4140 cur.par()->Erase(cur.pos());
4142 if (cur.pos() && cur.pos() == cur.par()->Last()) {
4143 cur.pos(cur.pos() - 1);
4144 cur.par()->Erase(cur.pos()); // no newline at very end!
4146 } while (((cell + 1) < cur.par()->table->GetNumberOfCells()) &&
4147 !cur.par()->table->IsContRow(cell_org) &&
4148 cur.par()->table->IsContRow(cell));
4149 cur.par()->table->DeleteRow(cell_org);
4156 bool LyXText::IsEmptyTableCell() const
4158 LyXParagraph::size_type pos = cursor.pos() - 1;
4159 while (pos >= 0 && pos < cursor.par()->Last()
4160 && !cursor.par()->IsNewline(pos))
4162 return cursor.par()->IsNewline(pos + 1);
4167 void LyXText::toggleAppendix(){
4168 LyXParagraph * par = cursor.par()->FirstPhysicalPar();
4169 bool start = !par->start_of_appendix;
4171 // ensure that we have only one start_of_appendix in this document
4172 LyXParagraph * tmp = FirstParagraph();
4173 for (; tmp; tmp = tmp->next)
4174 tmp->start_of_appendix = 0;
4175 par->start_of_appendix = start;
4177 // we can set the refreshing parameters now
4178 status = LyXText::NEED_MORE_REFRESH;
4180 refresh_row = 0; // not needed for full update
4182 SetCursor(cursor.par(), cursor.pos());