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 FIX_DOUBLE_SPACE 1
44 //#define USE_OLD_CUT_AND_PASTE 1
50 LyXText::LyXText(BufferView * bv, int pw, Buffer * p)
62 status = LyXText::UNCHANGED;
63 LyXParagraph * par = p->paragraph;
64 current_font = GetFont(par, 0);
69 InsertParagraph(par, lastrow);
73 // set cursor at the very top position
74 selection = true; /* these setting is necessary
75 because of the delete-empty-
76 paragraph mechanism in
78 SetCursor(firstrow->par, 0);
83 // no rebreak necessary
89 // Default layouttype for copy environment type
96 // Delete all rows, this does not touch the paragraphs!
97 Row * tmprow = firstrow;
99 tmprow = firstrow->next;
106 void LyXText::owner(BufferView * bv)
108 if (owner_ && bv) lyxerr << "LyXText::owner_ already set!" << endl;
112 // Gets the fully instantiated font at a given position in a paragraph
113 // Basically the same routine as LyXParagraph::getFont() in paragraph.C.
114 // The difference is that this one is used for displaying, and thus we
115 // are allowed to make cosmetic improvements. For instance make footnotes
117 // If position is -1, we get the layout font of the paragraph.
118 // If position is -2, we get the font of the manual label of the paragraph.
119 LyXFont LyXText::GetFont(LyXParagraph * par,
120 LyXParagraph::size_type pos) const
122 LyXLayout const & layout =
123 textclasslist.Style(bparams->textclass, par->GetLayout());
125 char par_depth = par->GetDepth();
126 // We specialize the 95% common case:
127 if (par->footnoteflag == LyXParagraph::NO_FOOTNOTE && !par_depth) {
130 if (layout.labeltype == LABEL_MANUAL
131 && pos < BeginningOfMainBody(par)) {
133 return par->GetFontSettings(pos).
134 realize(layout.reslabelfont);
136 return par->GetFontSettings(pos).
137 realize(layout.resfont);
140 // process layoutfont for pos == -1 and labelfont for pos < -1
142 return layout.resfont;
144 return layout.reslabelfont;
148 // The uncommon case need not be optimized as much
150 LyXFont layoutfont, tmpfont;
154 if (pos < BeginningOfMainBody(par)) {
156 layoutfont = layout.labelfont;
159 layoutfont = layout.font;
161 tmpfont = par->GetFontSettings(pos);
162 tmpfont.realize(layoutfont);
165 // process layoutfont for pos == -1 and labelfont for pos < -1
167 tmpfont = layout.font;
169 tmpfont = layout.labelfont;
172 // Resolve against environment font information
173 while (par && par_depth && !tmpfont.resolved()) {
174 par = par->DepthHook(par_depth - 1);
176 tmpfont.realize(textclasslist.
177 Style(bparams->textclass,
178 par->GetLayout()).font);
179 par_depth = par->GetDepth();
183 tmpfont.realize(textclasslist.TextClass(bparams->textclass).defaultfont());
185 // Cosmetic improvement: If this is an open footnote, make the font
187 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
188 && par->footnotekind == LyXParagraph::FOOTNOTE) {
196 void LyXText::SetCharFont(LyXParagraph * par,
197 LyXParagraph::size_type pos,
201 // Let the insets convert their font
202 if (par->GetChar(pos) == LyXParagraph::META_INSET) {
203 if (par->GetInset(pos))
204 font = par->GetInset(pos)->ConvertFont(font);
207 LyXLayout const & layout = textclasslist.Style(bparams->textclass,
210 // Get concrete layout font to reduce against
213 if (pos < BeginningOfMainBody(par))
214 layoutfont = layout.labelfont;
216 layoutfont = layout.font;
218 // Realize against environment font information
219 if (par->GetDepth()){
220 LyXParagraph * tp = par;
221 while (!layoutfont.resolved() && tp && tp->GetDepth()) {
222 tp = tp->DepthHook(tp->GetDepth()-1);
224 layoutfont.realize(textclasslist.
225 Style(bparams->textclass,
226 tp->GetLayout()).font);
230 layoutfont.realize(textclasslist.TextClass(bparams->textclass).defaultfont());
232 if (par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
233 && par->footnotekind == LyXParagraph::FOOTNOTE) {
234 layoutfont.decSize();
237 // Now, reduce font against full layout font
238 font.reduce(layoutfont);
240 par->SetFont(pos, font);
244 /* inserts a new row behind the specified row, increments
245 * the touched counters */
246 void LyXText::InsertRow(Row * row, LyXParagraph * par,
247 LyXParagraph::size_type pos) const
249 Row * tmprow = new Row;
251 tmprow->previous = 0;
252 tmprow->next = firstrow;
255 tmprow->previous = row;
256 tmprow->next = row->next;
261 tmprow->next->previous = tmprow;
263 if (tmprow->previous)
264 tmprow->previous->next = tmprow;
272 ++number_of_rows; // one more row
276 // removes the row and reset the touched counters
277 void LyXText::RemoveRow(Row * row) const
279 /* this must not happen before the currentrow for clear reasons.
280 so the trick is just to set the current row onto the previous
283 GetRow(row->par, row->pos, unused_y);
284 currentrow = currentrow->previous;
286 currentrow_y -= currentrow->height;
291 row->next->previous = row->previous;
292 if (!row->previous) {
293 firstrow = row->next;
295 row->previous->next = row->next;
298 lastrow = row->previous;
300 height -= row->height; // the text becomes smaller
303 --number_of_rows; // one row less
307 // remove all following rows of the paragraph of the specified row.
308 void LyXText::RemoveParagraph(Row * row) const
310 LyXParagraph * tmppar = row->par;
314 while (row && row->par == tmppar) {
322 // insert the specified paragraph behind the specified row
323 void LyXText::InsertParagraph(LyXParagraph * par, Row * row) const
325 InsertRow(row, par, 0); /* insert a new row, starting
328 SetCounter(par); // set the counters
330 // and now append the whole paragraph behind the new row
332 firstrow->height = 0;
333 AppendParagraph(firstrow);
335 row->next->height = 0;
336 AppendParagraph(row->next);
341 void LyXText::ToggleFootnote()
343 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
345 && par->next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
347 owner_->owner()->getMiniBuffer()->Set(_("Opened float"));
349 owner_->owner()->getMiniBuffer()->Set(_("Closed float"));
355 void LyXText::OpenStuff()
357 if (cursor.pos == 0 && cursor.par->bibkey){
358 cursor.par->bibkey->Edit(owner_, 0, 0, 0);
360 else if (cursor.pos < cursor.par->Last()
361 && cursor.par->GetChar(cursor.pos) == LyXParagraph::META_INSET
362 && cursor.par->GetInset(cursor.pos)->Editable()) {
363 owner_->owner()->getMiniBuffer()
364 ->Set(cursor.par->GetInset(cursor.pos)->EditMessage());
365 if (cursor.par->GetInset(cursor.pos)->Editable() != Inset::HIGHLY_EDITABLE)
367 cursor.par->GetInset(cursor.pos)->Edit(owner_, 0, 0, 0);
374 void LyXText::CloseFootnote()
376 LyXParagraph * tmppar;
377 LyXParagraph * par = cursor.par->ParFromPos(cursor.pos);
379 // if the cursor is not in an open footnote, or
380 // there is no open footnote in this paragraph, just return.
381 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
384 par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
385 owner_->owner()->getMiniBuffer()
386 ->Set(_("Nothing to do"));
390 // ok, move the cursor right before the footnote
391 // just a little faster than using CursorRight()
393 cursor.par->ParFromPos(cursor.pos) != par;
397 // now the cursor is at the beginning of the physical par
398 SetCursor(cursor.par,
400 cursor.par->ParFromPos(cursor.pos)->size());
402 /* we are in a footnote, so let us move at the beginning */
403 /* this is just faster than using just CursorLeft() */
406 while (tmppar->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
407 // just a little bit faster than movin the cursor
408 tmppar = tmppar->Previous();
410 SetCursor(tmppar, tmppar->Last());
413 // the cursor must be exactly before the footnote
414 par = cursor.par->ParFromPos(cursor.pos);
416 status = LyXText::NEED_MORE_REFRESH;
417 refresh_row = cursor.row;
418 refresh_y = cursor.y - cursor.row->baseline;
421 LyXParagraph * endpar = par->NextAfterFootnote()->Next();
422 Row * row = cursor.row;
424 tmppar->CloseFootnote(cursor.pos);
426 while (tmppar != endpar) {
427 RemoveRow(row->next);
429 tmppar = row->next->par;
434 AppendParagraph(cursor.row);
436 SetCursor(cursor.par, cursor.pos);
440 if (cursor.row->next)
441 SetHeightOfRow(cursor.row->next);
445 /* used in setlayout */
446 // Asger is not sure we want to do this...
447 void LyXText::MakeFontEntriesLayoutSpecific(LyXParagraph * par)
450 LyXLayout const & layout =
451 textclasslist.Style(bparams->textclass, par->GetLayout());
453 LyXFont layoutfont, tmpfont;
454 for (LyXParagraph::size_type pos = 0;
455 pos < par->Last(); ++pos) {
456 if (pos < BeginningOfMainBody(par))
457 layoutfont = layout.labelfont;
459 layoutfont = layout.font;
461 tmpfont = par->GetFontSettings(pos);
462 tmpfont.reduce(layoutfont);
463 par->SetFont(pos, tmpfont);
468 // set layout over selection and make a total rebreak of those paragraphs
469 void LyXText::SetLayout(LyXTextClass::size_type layout)
473 // if there is no selection just set the layout
474 // of the current paragraph */
476 sel_start_cursor = cursor; // dummy selection
477 sel_end_cursor = cursor;
480 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
481 LyXParagraph * undoendpar = endpar;
483 if (endpar && endpar->GetDepth()) {
484 while (endpar && endpar->GetDepth()) {
485 endpar = endpar->LastPhysicalPar()->Next();
490 endpar = endpar->Next(); // because of parindents etc.
494 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
497 tmpcursor = cursor; /* store the current cursor */
499 /* ok we have a selection. This is always between sel_start_cursor
500 * and sel_end cursor */
501 cursor = sel_start_cursor;
503 LyXLayout const & lyxlayout =
504 textclasslist.Style(bparams->textclass, layout);
506 while (cursor.par != sel_end_cursor.par) {
507 if (cursor.par->footnoteflag ==
508 sel_start_cursor.par->footnoteflag) {
509 cursor.par->SetLayout(layout);
510 MakeFontEntriesLayoutSpecific(cursor.par);
511 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
512 fppar->added_space_top = lyxlayout.fill_top ?
513 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
514 fppar->added_space_bottom = lyxlayout.fill_bottom ?
515 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
516 if (lyxlayout.margintype == MARGIN_MANUAL)
517 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
518 if (lyxlayout.labeltype != LABEL_BIBLIO
520 delete fppar->bibkey;
524 cursor.par = cursor.par->Next();
526 if (cursor.par->footnoteflag ==
527 sel_start_cursor.par->footnoteflag) {
528 cursor.par->SetLayout(layout);
529 MakeFontEntriesLayoutSpecific(cursor.par);
530 LyXParagraph* fppar = cursor.par->FirstPhysicalPar();
531 fppar->added_space_top = lyxlayout.fill_top ?
532 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
533 fppar->added_space_bottom = lyxlayout.fill_bottom ?
534 VSpace(VSpace::VFILL) : VSpace(VSpace::NONE);
535 if (lyxlayout.margintype == MARGIN_MANUAL)
536 cursor.par->SetLabelWidthString(lyxlayout.labelstring());
537 if (lyxlayout.labeltype != LABEL_BIBLIO
539 delete fppar->bibkey;
544 RedoParagraphs(sel_start_cursor, endpar);
546 // we have to reset the selection, because the
547 // geometry could have changed */
548 SetCursor(sel_start_cursor.par, sel_start_cursor.pos, false);
550 SetCursor(sel_end_cursor.par, sel_end_cursor.pos, false);
551 UpdateCounters(cursor.row);
554 SetCursor(tmpcursor.par, tmpcursor.pos, true);
558 // increment depth over selection and
559 // make a total rebreak of those paragraphs
560 void LyXText::IncDepth()
562 // If there is no selection, just use the current paragraph
564 sel_start_cursor = cursor; // dummy selection
565 sel_end_cursor = cursor;
568 // We end at the next paragraph with depth 0
569 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
570 LyXParagraph * undoendpar = endpar;
572 if (endpar && endpar->GetDepth()) {
573 while (endpar && endpar->GetDepth()) {
574 endpar = endpar->LastPhysicalPar()->Next();
579 endpar = endpar->Next(); // because of parindents etc.
584 .par->ParFromPos(sel_start_cursor.pos)->previous,
587 LyXCursor tmpcursor = cursor; // store the current cursor
589 // ok we have a selection. This is always between sel_start_cursor
590 // and sel_end cursor
591 cursor = sel_start_cursor;
593 bool anything_changed = false;
596 // NOTE: you can't change the depth of a bibliography entry
597 if (cursor.par->footnoteflag ==
598 sel_start_cursor.par->footnoteflag
599 && textclasslist.Style(bparams->textclass,
600 cursor.par->GetLayout()
601 ).labeltype != LABEL_BIBLIO) {
602 LyXParagraph * prev =
603 cursor.par->FirstPhysicalPar()->Previous();
605 && (prev->GetDepth() - cursor.par->GetDepth() > 0
606 || (prev->GetDepth() == cursor.par->GetDepth()
607 && textclasslist.Style(bparams->textclass,
608 prev->GetLayout()).isEnvironment()))) {
609 cursor.par->FirstPhysicalPar()->depth++;
610 anything_changed = true;
613 if (cursor.par == sel_end_cursor.par)
615 cursor.par = cursor.par->Next();
618 // if nothing changed set all depth to 0
619 if (!anything_changed) {
620 cursor = sel_start_cursor;
621 while (cursor.par != sel_end_cursor.par) {
622 cursor.par->FirstPhysicalPar()->depth = 0;
623 cursor.par = cursor.par->Next();
625 if (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag)
626 cursor.par->FirstPhysicalPar()->depth = 0;
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);
635 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
636 UpdateCounters(cursor.row);
639 SetCursor(tmpcursor.par, tmpcursor.pos);
643 // decrement depth over selection and
644 // make a total rebreak of those paragraphs
645 void LyXText::DecDepth()
647 // if there is no selection just set the layout
648 // of the current paragraph
650 sel_start_cursor = cursor; // dummy selection
651 sel_end_cursor = cursor;
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;
679 if (cursor.par->footnoteflag ==
680 sel_start_cursor.par->footnoteflag) {
681 if (cursor.par->FirstPhysicalPar()->depth)
682 cursor.par->FirstPhysicalPar()->depth--;
684 if (cursor.par == sel_end_cursor.par)
686 cursor.par = cursor.par->Next();
689 RedoParagraphs(sel_start_cursor, endpar);
691 // we have to reset the selection, because the
692 // geometry could have changed
693 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
695 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
696 UpdateCounters(cursor.row);
699 SetCursor(tmpcursor.par, tmpcursor.pos);
703 // set font over selection and make a total rebreak of those paragraphs
704 void LyXText::SetFont(LyXFont const & font, bool toggleall)
706 // if there is no selection just set the current_font
708 // Determine basis font
710 if (cursor.pos < BeginningOfMainBody(cursor.par))
711 layoutfont = GetFont(cursor.par, -2);
713 layoutfont = GetFont(cursor.par, -1);
714 // Update current font
715 real_current_font.update(font, bparams->language_info, toggleall);
717 // Reduce to implicit settings
718 current_font = real_current_font;
719 current_font.reduce(layoutfont);
720 // And resolve it completely
721 real_current_font.realize(layoutfont);
725 LyXCursor tmpcursor = cursor; // store the current cursor
727 // ok we have a selection. This is always between sel_start_cursor
728 // and sel_end cursor
731 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->previous,
732 sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)->next);
733 cursor = sel_start_cursor;
734 while (cursor.par != sel_end_cursor.par ||
735 (cursor.par->footnoteflag == sel_start_cursor.par->footnoteflag
736 && cursor.pos < sel_end_cursor.pos))
738 if (cursor.pos < cursor.par->Last()
739 && cursor.par->footnoteflag
740 == sel_start_cursor.par->footnoteflag) {
741 // an open footnote should behave
743 LyXFont newfont = GetFont(cursor.par, cursor.pos);
744 newfont.update(font, bparams->language_info, toggleall);
745 SetCharFont(cursor.par, cursor.pos, newfont);
749 cursor.par = cursor.par->Next();
753 RedoParagraphs(sel_start_cursor, sel_end_cursor.par->Next());
755 // we have to reset the selection, because the
756 // geometry could have changed
757 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
759 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
762 SetCursor(tmpcursor.par, tmpcursor.pos);
766 void LyXText::RedoHeightOfParagraph(LyXCursor const & cur)
768 Row * tmprow = cur.row;
769 long y = cur.y - tmprow->baseline;
771 SetHeightOfRow(tmprow);
772 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
773 // find the first row of the paragraph
774 if (first_phys_par != tmprow->par)
775 while (tmprow->previous
776 && tmprow->previous->par != first_phys_par) {
777 tmprow = tmprow->previous;
779 SetHeightOfRow(tmprow);
781 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
782 tmprow = tmprow->previous;
784 SetHeightOfRow(tmprow);
787 // we can set the refreshing parameters now
788 status = LyXText::NEED_MORE_REFRESH;
790 refresh_row = tmprow;
791 SetCursor(cur.par, cur.pos);
795 void LyXText::RedoDrawingOfParagraph(LyXCursor const & cur)
797 Row * tmprow = cur.row;
799 long y = cur.y - tmprow->baseline;
800 SetHeightOfRow(tmprow);
801 LyXParagraph * first_phys_par = tmprow->par->FirstPhysicalPar();
802 // find the first row of the paragraph
803 if (first_phys_par != tmprow->par)
804 while (tmprow->previous && tmprow->previous->par != first_phys_par) {
805 tmprow = tmprow->previous;
808 while (tmprow->previous && tmprow->previous->par == first_phys_par) {
809 tmprow = tmprow->previous;
813 // we can set the refreshing parameters now
814 if (status == LyXText::UNCHANGED || y < refresh_y) {
816 refresh_row = tmprow;
818 status = LyXText::NEED_MORE_REFRESH;
819 SetCursor(cur.par, cur.pos);
823 /* deletes and inserts again all paragaphs between the cursor
824 * and the specified par
825 * This function is needed after SetLayout and SetFont etc. */
826 void LyXText::RedoParagraphs(LyXCursor const & cur,
827 LyXParagraph const * endpar) const
830 LyXParagraph * tmppar, * first_phys_par;
832 Row * tmprow = cur.row;
834 long y = cur.y - tmprow->baseline;
836 if (!tmprow->previous){
837 first_phys_par = FirstParagraph(); // a trick/hack for UNDO
839 first_phys_par = tmprow->par->FirstPhysicalPar();
840 // find the first row of the paragraph
841 if (first_phys_par != tmprow->par)
842 while (tmprow->previous &&
843 (tmprow->previous->par != first_phys_par)) {
844 tmprow = tmprow->previous;
847 while (tmprow->previous
848 && tmprow->previous->par == first_phys_par) {
849 tmprow = tmprow->previous;
854 // we can set the refreshing parameters now
855 status = LyXText::NEED_MORE_REFRESH;
857 refresh_row = tmprow->previous; /* the real refresh row will
858 be deleted, so I store
862 tmppar = tmprow->next->par;
865 while (tmppar != endpar) {
866 RemoveRow(tmprow->next);
868 tmppar = tmprow->next->par;
873 // remove the first one
874 tmprow2 = tmprow; /* this is because tmprow->previous
876 tmprow = tmprow->previous;
879 tmppar = first_phys_par;
883 InsertParagraph(tmppar, tmprow);
886 while (tmprow->next && tmprow->next->par == tmppar)
887 tmprow = tmprow->next;
888 tmppar = tmppar->Next();
890 } while (tmppar != endpar);
892 // this is because of layout changes
894 refresh_y -= refresh_row->height;
895 SetHeightOfRow(refresh_row);
897 refresh_row = firstrow;
899 SetHeightOfRow(refresh_row);
902 if (tmprow && tmprow->next)
903 SetHeightOfRow(tmprow->next);
907 int LyXText::FullRebreak()
909 if (need_break_row) {
910 BreakAgain(need_break_row);
918 /* important for the screen */
921 /* the cursor set functions have a special mechanism. When they
922 * realize, that you left an empty paragraph, they will delete it.
923 * They also delet the corresponding row */
925 // need the selection cursor:
926 void LyXText::SetSelection()
929 last_sel_cursor = sel_cursor;
930 sel_start_cursor = sel_cursor;
931 sel_end_cursor = sel_cursor;
936 // first the toggling area
937 if (cursor.y < last_sel_cursor.y ||
938 (cursor.y == last_sel_cursor.y && cursor.x < last_sel_cursor.x)) {
939 toggle_end_cursor = last_sel_cursor;
940 toggle_cursor = cursor;
943 toggle_end_cursor = cursor;
944 toggle_cursor = last_sel_cursor;
947 last_sel_cursor = cursor;
949 // and now the whole selection
951 if (sel_cursor.par == cursor.par)
952 if (sel_cursor.pos < cursor.pos) {
953 sel_end_cursor = cursor;
954 sel_start_cursor = sel_cursor;
956 sel_end_cursor = sel_cursor;
957 sel_start_cursor = cursor;
959 else if (sel_cursor.y < cursor.y ||
960 (sel_cursor.y == cursor.y && sel_cursor.x < cursor.x)) {
961 sel_end_cursor = cursor;
962 sel_start_cursor = sel_cursor;
965 sel_end_cursor = sel_cursor;
966 sel_start_cursor = cursor;
969 // a selection with no contents is not a selection
970 if (sel_start_cursor.x == sel_end_cursor.x &&
971 sel_start_cursor.y == sel_end_cursor.y)
976 void LyXText::ClearSelection() const
983 void LyXText::CursorHome() const
985 SetCursor(cursor.par, cursor.row->pos);
989 void LyXText::CursorEnd() const
991 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
992 SetCursor(cursor.par, RowLast(cursor.row) + 1);
994 if (cursor.par->Last() &&
995 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
996 || cursor.par->IsNewline(RowLast(cursor.row))))
997 SetCursor(cursor.par, RowLast(cursor.row));
999 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1001 if (cursor.par->table) {
1002 int cell = NumberOfCell(cursor.par, cursor.pos);
1003 if (cursor.par->table->RowHasContRow(cell) &&
1004 cursor.par->table->CellHasContRow(cell)<0) {
1005 if (!cursor.row->next || cursor.row->next->par != cursor.row->par)
1006 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1008 if (cursor.par->Last() &&
1009 (cursor.par->GetChar(RowLast(cursor.row)) == ' '
1010 || cursor.par->IsNewline(RowLast(cursor.row))))
1011 SetCursor(cursor.par, RowLast(cursor.row));
1013 SetCursor(cursor.par, RowLast(cursor.row) + 1);
1020 void LyXText::CursorTop() const
1022 while (cursor.par->Previous())
1023 cursor.par = cursor.par->Previous();
1024 SetCursor(cursor.par, 0);
1028 void LyXText::CursorBottom() const
1030 while (cursor.par->Next())
1031 cursor.par = cursor.par->Next();
1032 SetCursor(cursor.par, cursor.par->Last());
1036 /* returns a pointer to the row near the specified y-coordinate
1037 * (relative to the whole text). y is set to the real beginning
1039 Row * LyXText::GetRowNearY(long & y) const
1045 tmprow = currentrow;
1046 tmpy = currentrow_y;
1053 while (tmprow->next && tmpy + tmprow->height <= y) {
1054 tmpy += tmprow->height;
1055 tmprow = tmprow->next;
1058 while (tmprow->previous && tmpy > y) {
1059 tmprow = tmprow->previous;
1060 tmpy -= tmprow->height;
1063 currentrow = tmprow;
1064 currentrow_y = tmpy;
1066 y = tmpy; // return the real y
1071 void LyXText::ToggleFree(LyXFont const & font, bool toggleall)
1073 // If the mask is completely neutral, tell user
1074 if (font == LyXFont(LyXFont::ALL_IGNORE)) {
1075 // Could only happen with user style
1076 owner_->owner()->getMiniBuffer()
1077 ->Set(_("No font change defined. Use Character under"
1078 " the Layout menu to define font change."));
1082 // Try implicit word selection
1083 LyXCursor resetCursor = cursor;
1084 int implicitSelection = SelectWordWhenUnderCursor();
1087 SetFont(font, toggleall);
1089 /* Implicit selections are cleared afterwards and cursor is set to the
1090 original position. */
1091 if (implicitSelection) {
1093 cursor = resetCursor;
1094 SetCursor( cursor.par, cursor.pos );
1095 sel_cursor = cursor;
1100 LyXParagraph::size_type LyXText::BeginningOfMainBody(LyXParagraph * par) const
1102 if (textclasslist.Style(bparams->textclass,
1103 par->GetLayout()).labeltype != LABEL_MANUAL)
1106 return par->BeginningOfMainBody();
1110 /* if there is a selection, reset every environment you can find
1111 * in the selection, otherwise just the environment you are in */
1112 void LyXText::MeltFootnoteEnvironment()
1114 LyXParagraph * tmppar, * firsttmppar;
1118 /* is is only allowed, if the cursor is IN an open footnote.
1119 * Otherwise it is too dangerous */
1120 if (cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE)
1123 SetUndo(Undo::FINISH,
1124 cursor.par->PreviousBeforeFootnote()->previous,
1125 cursor.par->NextAfterFootnote()->next);
1127 /* ok, move to the beginning of the footnote. */
1128 while (cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
1129 cursor.par = cursor.par->Previous();
1131 SetCursor(cursor.par, cursor.par->Last());
1132 /* this is just faster than using CursorLeft(); */
1134 firsttmppar = cursor.par->ParFromPos(cursor.pos);
1135 tmppar = firsttmppar;
1136 /* tmppar is now the paragraph right before the footnote */
1138 bool first_footnote_par_is_not_empty = tmppar->next->size();
1141 && tmppar->next->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1142 tmppar = tmppar->next; /* I use next instead of Next(),
1143 * because there cannot be any
1144 * footnotes in a footnote
1146 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
1148 /* remember the captions and empty paragraphs */
1149 if ((textclasslist.Style(bparams->textclass,
1150 tmppar->GetLayout())
1151 .labeltype == LABEL_SENSITIVE)
1153 tmppar->SetLayout(0);
1156 // now we will paste the ex-footnote, if the layouts allow it
1157 // first restore the layout of the paragraph right behind
1160 tmppar->next->MakeSameLayout(cursor.par);
1163 if ((!tmppar->GetLayout() && !tmppar->table)
1165 && (!tmppar->Next()->Last()
1166 || tmppar->Next()->HasSameLayout(tmppar)))) {
1167 if (tmppar->Next()->Last()
1168 && tmppar->Next()->IsLineSeparator(0))
1169 tmppar->Next()->Erase(0);
1170 tmppar->PasteParagraph();
1173 tmppar = tmppar->Next(); /* make sure tmppar cannot be touched
1174 * by the pasting of the beginning */
1176 /* then the beginning */
1177 /* if there is no space between the text and the footnote, so we insert
1179 * (only if the previous par and the footnotepar are not empty!) */
1180 if ((!firsttmppar->next->GetLayout() && !firsttmppar->next->table)
1181 || firsttmppar->HasSameLayout(firsttmppar->next)) {
1182 if (firsttmppar->size()
1183 && !firsttmppar->IsSeparator(firsttmppar->size() - 1)
1184 && first_footnote_par_is_not_empty) {
1185 firsttmppar->next->InsertChar(0, ' ');
1187 firsttmppar->PasteParagraph();
1190 /* now redo the paragaphs */
1191 RedoParagraphs(cursor, tmppar);
1193 SetCursor(cursor.par, cursor.pos);
1195 /* sometimes it can happen, that there is a counter change */
1196 Row * row = cursor.row;
1197 while (row->next && row->par != tmppar && row->next->par != tmppar)
1199 UpdateCounters(row);
1206 /* the DTP switches for paragraphs. LyX will store them in the
1207 * first physicla paragraph. When a paragraph is broken, the top settings
1208 * rest, the bottom settings are given to the new one. So I can make shure,
1209 * they do not duplicate themself and you cannnot make dirty things with
1212 void LyXText::SetParagraph(bool line_top, bool line_bottom,
1213 bool pagebreak_top, bool pagebreak_bottom,
1214 VSpace const & space_top,
1215 VSpace const & space_bottom,
1217 string labelwidthstring,
1220 LyXCursor tmpcursor = cursor;
1222 sel_start_cursor = cursor;
1223 sel_end_cursor = cursor;
1226 // make sure that the depth behind the selection are restored, too
1227 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1228 LyXParagraph * undoendpar = endpar;
1230 if (endpar && endpar->GetDepth()) {
1231 while (endpar && endpar->GetDepth()) {
1232 endpar = endpar->LastPhysicalPar()->Next();
1233 undoendpar = endpar;
1237 endpar = endpar->Next(); // because of parindents etc.
1242 .par->ParFromPos(sel_start_cursor.pos)->previous,
1246 LyXParagraph * tmppar = sel_end_cursor.par;
1247 while (tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1248 SetCursor(tmppar->FirstPhysicalPar(), 0);
1249 status = LyXText::NEED_MORE_REFRESH;
1250 refresh_row = cursor.row;
1251 refresh_y = cursor.y - cursor.row->baseline;
1252 if (cursor.par->footnoteflag ==
1253 sel_start_cursor.par->footnoteflag) {
1254 cursor.par->line_top = line_top;
1255 cursor.par->line_bottom = line_bottom;
1256 cursor.par->pagebreak_top = pagebreak_top;
1257 cursor.par->pagebreak_bottom = pagebreak_bottom;
1258 cursor.par->added_space_top = space_top;
1259 cursor.par->added_space_bottom = space_bottom;
1260 // does the layout allow the new alignment?
1261 if (align == LYX_ALIGN_LAYOUT)
1262 align = textclasslist
1263 .Style(bparams->textclass,
1264 cursor.par->GetLayout()).align;
1265 if (align & textclasslist
1266 .Style(bparams->textclass,
1267 cursor.par->GetLayout()).alignpossible) {
1268 if (align == textclasslist
1269 .Style(bparams->textclass,
1270 cursor.par->GetLayout()).align)
1271 cursor.par->align = LYX_ALIGN_LAYOUT;
1273 cursor.par->align = align;
1275 cursor.par->SetLabelWidthString(labelwidthstring);
1276 cursor.par->noindent = noindent;
1279 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1282 RedoParagraphs(sel_start_cursor, endpar);
1285 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1286 sel_cursor = cursor;
1287 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1289 SetCursor(tmpcursor.par, tmpcursor.pos);
1293 void LyXText::SetParagraphExtraOpt(int type,
1295 char const * widthp,
1296 int alignment, bool hfill,
1297 bool start_minipage)
1299 LyXCursor tmpcursor = cursor;
1300 LyXParagraph * tmppar;
1302 sel_start_cursor = cursor;
1303 sel_end_cursor = cursor;
1306 // make sure that the depth behind the selection are restored, too
1307 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1308 LyXParagraph * undoendpar = endpar;
1310 if (endpar && endpar->GetDepth()) {
1311 while (endpar && endpar->GetDepth()) {
1312 endpar = endpar->LastPhysicalPar()->Next();
1313 undoendpar = endpar;
1317 endpar = endpar->Next(); // because of parindents etc.
1322 .par->ParFromPos(sel_start_cursor.pos)->previous,
1325 tmppar = sel_end_cursor.par;
1326 while(tmppar != sel_start_cursor.par->FirstPhysicalPar()->Previous()) {
1327 SetCursor(tmppar->FirstPhysicalPar(), 0);
1328 status = LyXText::NEED_MORE_REFRESH;
1329 refresh_row = cursor.row;
1330 refresh_y = cursor.y - cursor.row->baseline;
1331 if (cursor.par->footnoteflag ==
1332 sel_start_cursor.par->footnoteflag) {
1333 if (type == LyXParagraph::PEXTRA_NONE) {
1334 if (cursor.par->pextra_type != LyXParagraph::PEXTRA_NONE) {
1335 cursor.par->UnsetPExtraType();
1336 cursor.par->pextra_type = LyXParagraph::PEXTRA_NONE;
1339 cursor.par->SetPExtraType(type, width, widthp);
1340 cursor.par->pextra_hfill = hfill;
1341 cursor.par->pextra_start_minipage = start_minipage;
1342 cursor.par->pextra_alignment = alignment;
1345 tmppar = cursor.par->FirstPhysicalPar()->Previous();
1347 RedoParagraphs(sel_start_cursor, endpar);
1349 SetCursor(sel_start_cursor.par, sel_start_cursor.pos);
1350 sel_cursor = cursor;
1351 SetCursor(sel_end_cursor.par, sel_end_cursor.pos);
1353 SetCursor(tmpcursor.par, tmpcursor.pos);
1357 char loweralphaCounter(int n)
1359 if (n < 1 || n > 26)
1365 char alphaCounter(int n)
1367 if (n < 1 || n > 26)
1373 char hebrewCounter(int n)
1375 static const char hebrew[22] = {
1376 'à ', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è',
1377 'é', 'ë', 'ì', 'î', 'ð', 'ñ', 'ò', 'ô', 'ö',
1378 '÷', 'ø', 'ù', 'ú'
1380 if (n < 1 || n > 22)
1386 static char const * romanCounter(int n)
1388 static char const * roman[20] = {
1389 "i", "ii", "iii", "iv", "v",
1390 "vi", "vii", "viii", "ix", "x",
1391 "xi", "xii", "xiii", "xiv", "xv",
1392 "xvi", "xvii", "xviii", "xix", "xx"
1394 if (n < 1 || n > 20)
1400 // set the counter of a paragraph. This includes the labels
1401 void LyXText::SetCounter(LyXParagraph * par) const
1403 // this is only relevant for the beginning of paragraph
1404 par = par->FirstPhysicalPar();
1406 LyXLayout const & layout = textclasslist.Style(bparams->textclass,
1409 LyXTextClass const & textclass =
1410 textclasslist.TextClass(bparams->textclass);
1412 /* copy the prev-counters to this one, unless this is the start of a
1413 footnote or of a bibliography or the very first paragraph */
1415 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1416 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1417 && par->footnotekind == LyXParagraph::FOOTNOTE)
1418 && !(textclasslist.Style(bparams->textclass,
1419 par->Previous()->GetLayout()
1420 ).labeltype != LABEL_BIBLIO
1421 && layout.labeltype == LABEL_BIBLIO)) {
1422 for (int i = 0; i < 10; ++i) {
1423 par->setCounter(i, par->Previous()->GetFirstCounter(i));
1425 par->appendix = par->Previous()->FirstPhysicalPar()->appendix;
1426 if (!par->appendix && par->start_of_appendix){
1427 par->appendix = true;
1428 for (int i = 0; i < 10; ++i) {
1429 par->setCounter(i, 0);
1432 par->enumdepth = par->Previous()->FirstPhysicalPar()->enumdepth;
1433 par->itemdepth = par->Previous()->FirstPhysicalPar()->itemdepth;
1436 for (int i = 0; i < 10; ++i) {
1437 par->setCounter(i, 0);
1439 par->appendix = par->start_of_appendix;
1444 // if this is an open marginnote and this is the first
1445 // entry in the marginnote and the enclosing
1446 // environment is an enum/item then correct for the
1447 // LaTeX behaviour (ARRae)
1448 if(par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1449 && par->footnotekind == LyXParagraph::MARGIN
1451 && par->Previous()->footnoteflag != LyXParagraph::OPEN_FOOTNOTE
1452 && (par->PreviousBeforeFootnote()
1453 && textclasslist.Style(bparams->textclass,
1454 par->PreviousBeforeFootnote()->GetLayout()
1455 ).labeltype >= LABEL_COUNTER_ENUMI)) {
1456 // Any itemize or enumerate environment in a marginnote
1457 // that is embedded in an itemize or enumerate
1458 // paragraph is seen by LaTeX as being at a deeper
1459 // level within that enclosing itemization/enumeration
1460 // even if there is a "standard" layout at the start of
1466 /* Maybe we have to increment the enumeration depth.
1467 * BUT, enumeration in a footnote is considered in isolation from its
1468 * surrounding paragraph so don't increment if this is the
1469 * first line of the footnote
1470 * AND, bibliographies can't have their depth changed ie. they
1471 * are always of depth 0
1474 && par->Previous()->GetDepth() < par->GetDepth()
1475 && textclasslist.Style(bparams->textclass,
1476 par->Previous()->GetLayout()
1477 ).labeltype == LABEL_COUNTER_ENUMI
1478 && par->enumdepth < 3
1479 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1480 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1481 && par->footnotekind == LyXParagraph::FOOTNOTE)
1482 && layout.labeltype != LABEL_BIBLIO) {
1486 /* Maybe we have to decrement the enumeration depth, see note above */
1488 && par->Previous()->GetDepth() > par->GetDepth()
1489 && !(par->Previous()->footnoteflag == LyXParagraph::NO_FOOTNOTE
1490 && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1491 && par->footnotekind == LyXParagraph::FOOTNOTE)
1492 && layout.labeltype != LABEL_BIBLIO) {
1493 par->enumdepth = par->DepthHook(par->GetDepth())->enumdepth;
1494 par->setCounter(6 + par->enumdepth,
1495 par->DepthHook(par->GetDepth())->getCounter(6 + par->enumdepth));
1496 /* reset the counters.
1497 * A depth change is like a breaking layout
1499 for (int i = 6 + par->enumdepth + 1; i < 10; ++i)
1500 par->setCounter(i, 0);
1503 if (!par->labelstring.empty()) {
1504 par->labelstring.clear();
1507 if (layout.margintype == MARGIN_MANUAL) {
1508 if (par->labelwidthstring.empty()) {
1509 par->SetLabelWidthString(layout.labelstring());
1512 par->SetLabelWidthString(string());
1515 /* is it a layout that has an automatic label ? */
1516 if (layout.labeltype >= LABEL_FIRST_COUNTER) {
1518 int i = layout.labeltype - LABEL_FIRST_COUNTER;
1519 if (i >= 0 && i<= bparams->secnumdepth) {
1520 par->incCounter(i); // increment the counter
1522 // Is there a label? Useful for Chapter layout
1523 if (!par->appendix){
1524 if (!layout.labelstring().empty())
1525 par->labelstring = layout.labelstring();
1527 par->labelstring.clear();
1529 if (!layout.labelstring_appendix().empty())
1530 par->labelstring = layout.labelstring_appendix();
1532 par->labelstring.clear();
1536 std::ostringstream s;
1540 if (!par->appendix) {
1541 switch (2 * LABEL_FIRST_COUNTER -
1542 textclass.maxcounter() + i) {
1543 case LABEL_COUNTER_CHAPTER:
1544 s << par->getCounter(i);
1546 case LABEL_COUNTER_SECTION:
1547 s << par->getCounter(i - 1) << '.'
1548 << par->getCounter(i);
1550 case LABEL_COUNTER_SUBSECTION:
1551 s << par->getCounter(i - 2) << '.'
1552 << par->getCounter(i - 1) << '.'
1553 << par->getCounter(i);
1555 case LABEL_COUNTER_SUBSUBSECTION:
1556 s << par->getCounter(i - 3) << '.'
1557 << par->getCounter(i - 2) << '.'
1558 << par->getCounter(i - 1) << '.'
1559 << par->getCounter(i);
1562 case LABEL_COUNTER_PARAGRAPH:
1563 s << par->getCounter(i - 4) << '.'
1564 << par->getCounter(i - 3) << '.'
1565 << par->getCounter(i - 2) << '.'
1566 << par->getCounter(i - 1) << '.'
1567 << par->getCounter(i);
1569 case LABEL_COUNTER_SUBPARAGRAPH:
1570 s << par->getCounter(i - 5) << '.'
1571 << par->getCounter(i - 4) << '.'
1572 << par->getCounter(i - 3) << '.'
1573 << par->getCounter(i - 2) << '.'
1574 << par->getCounter(i - 1) << '.'
1575 << par->getCounter(i);
1579 s << par->getCounter(i) << '.';
1582 } else { // appendix
1583 switch (2 * LABEL_FIRST_COUNTER - textclass.maxcounter() + i) {
1584 case LABEL_COUNTER_CHAPTER:
1585 if (par->isRightToLeftPar())
1586 s << hebrewCounter(par->getCounter(i));
1588 s << alphaCounter(par->getCounter(i));
1590 case LABEL_COUNTER_SECTION:
1591 if (par->isRightToLeftPar())
1592 s << hebrewCounter(par->getCounter(i - 1));
1594 s << alphaCounter(par->getCounter(i - 1));
1597 << par->getCounter(i);
1600 case LABEL_COUNTER_SUBSECTION:
1601 if (par->isRightToLeftPar())
1602 s << hebrewCounter(par->getCounter(i - 2));
1604 s << alphaCounter(par->getCounter(i - 2));
1607 << par->getCounter(i-1) << '.'
1608 << par->getCounter(i);
1611 case LABEL_COUNTER_SUBSUBSECTION:
1612 if (par->isRightToLeftPar())
1613 s << hebrewCounter(par->getCounter(i-3));
1615 s << alphaCounter(par->getCounter(i-3));
1618 << par->getCounter(i-2) << '.'
1619 << par->getCounter(i-1) << '.'
1620 << par->getCounter(i);
1623 case LABEL_COUNTER_PARAGRAPH:
1624 if (par->isRightToLeftPar())
1625 s << hebrewCounter(par->getCounter(i-4));
1627 s << alphaCounter(par->getCounter(i-4));
1630 << par->getCounter(i-3) << '.'
1631 << par->getCounter(i-2) << '.'
1632 << par->getCounter(i-1) << '.'
1633 << par->getCounter(i);
1636 case LABEL_COUNTER_SUBPARAGRAPH:
1637 if (par->isRightToLeftPar())
1638 s << hebrewCounter(par->getCounter(i-5));
1640 s << alphaCounter(par->getCounter(i-5));
1643 << par->getCounter(i-4) << '.'
1644 << par->getCounter(i-3) << '.'
1645 << par->getCounter(i-2) << '.'
1646 << par->getCounter(i-1) << '.'
1647 << par->getCounter(i);
1651 // Can this ever be reached? And in the
1652 // case it is, how can this be correct?
1654 s << static_cast<unsigned char>(par->getCounter(i)) << '.';
1660 par->labelstring += s.str().c_str();
1661 // We really want to remove the c_str as soon as
1665 char * tmps = s.str();
1666 par->labelstring += tmps;
1670 for (i++; i < 10; ++i) {
1671 // reset the following counters
1672 par->setCounter(i, 0);
1674 } else if (layout.labeltype < LABEL_COUNTER_ENUMI) {
1675 for (i++; i < 10; ++i) {
1676 // reset the following counters
1677 par->setCounter(i, 0);
1679 } else if (layout.labeltype == LABEL_COUNTER_ENUMI) {
1680 par->incCounter(i + par->enumdepth);
1681 int number = par->getCounter(i + par->enumdepth);
1684 std::ostringstream s;
1688 switch (par->enumdepth) {
1690 if (par->isRightToLeftPar())
1692 << hebrewCounter(number)
1696 << loweralphaCounter(number)
1700 if (par->isRightToLeftPar())
1701 s << '.' << romanCounter(number);
1703 s << romanCounter(number) << '.';
1706 if (par->isRightToLeftPar())
1708 << alphaCounter(number);
1710 s << alphaCounter(number)
1714 if (par->isRightToLeftPar())
1721 par->labelstring = s.str().c_str();
1722 // we really want to get rid of that c_str()
1725 char * tmps = s.str();
1726 par->labelstring = tmps;
1730 for (i += par->enumdepth + 1; i < 10; ++i)
1731 par->setCounter(i, 0); /* reset the following counters */
1734 } else if (layout.labeltype == LABEL_BIBLIO) {// ale970302
1735 int i = LABEL_COUNTER_ENUMI - LABEL_FIRST_COUNTER + par->enumdepth;
1737 int number = par->getCounter(i);
1739 par->bibkey = new InsetBibKey();
1740 par->bibkey->setCounter(number);
1741 par->labelstring = layout.labelstring();
1743 // In biblio should't be following counters but...
1745 string s = layout.labelstring();
1747 // the caption hack:
1749 if (layout.labeltype == LABEL_SENSITIVE) {
1750 if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1751 && (par->footnotekind == LyXParagraph::FIG
1752 || par->footnotekind == LyXParagraph::WIDE_FIG))
1753 s = (par->getParLanguage()->lang == "hebrew")
1754 ? ":øåéà " : "Figure:";
1755 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1756 && (par->footnotekind == LyXParagraph::TAB
1757 || par->footnotekind == LyXParagraph::WIDE_TAB))
1758 s = (par->getParLanguage()->lang == "hebrew")
1759 ? ":äìáè" : "Table:";
1760 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1761 && par->footnotekind == LyXParagraph::ALGORITHM)
1762 s = (par->getParLanguage()->lang == "hebrew")
1763 ? ":Ãúéøåâìà " : "Algorithm:";
1765 /* par->SetLayout(0);
1766 s = layout->labelstring; */
1767 s = (par->getParLanguage()->lang == "hebrew")
1768 ? " :úåòîùî øñç" : "Senseless: ";
1771 par->labelstring = s;
1773 /* reset the enumeration counter. They are always resetted
1774 * when there is any other layout between */
1775 for (int i = 6 + par->enumdepth; i < 10; ++i)
1776 par->setCounter(i, 0);
1781 /* Updates all counters BEHIND the row. Changed paragraphs
1782 * with a dynamic left margin will be rebroken. */
1783 void LyXText::UpdateCounters(Row * row) const
1792 && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1793 par = row->par->LastPhysicalPar()->Next();
1795 par = row->par->next;
1800 while (row->par != par)
1805 /* now check for the headline layouts. remember that they
1806 * have a dynamic left margin */
1808 && ( textclasslist.Style(bparams->textclass, par->layout).margintype == MARGIN_DYNAMIC
1809 || textclasslist.Style(bparams->textclass, par->layout).labeltype == LABEL_SENSITIVE)
1812 /* Rebreak the paragraph */
1813 RemoveParagraph(row);
1814 AppendParagraph(row);
1816 /* think about the damned open footnotes! */
1817 while (par->Next() &&
1818 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1819 || par->Next()->IsDummy())){
1821 if (par->IsDummy()) {
1822 while (row->par != par)
1824 RemoveParagraph(row);
1825 AppendParagraph(row);
1830 par = par->LastPhysicalPar()->Next();
1836 /* insets an inset. */
1837 void LyXText::InsertInset(Inset *inset)
1839 if (!cursor.par->InsertInsetAllowed(inset))
1841 SetUndo(Undo::INSERT,
1842 cursor.par->ParFromPos(cursor.pos)->previous,
1843 cursor.par->ParFromPos(cursor.pos)->next);
1844 cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1845 cursor.par->InsertInset(cursor.pos, inset);
1846 InsertChar(LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
1847 * The character will not be inserted a
1852 #ifdef USE_OLD_CUT_AND_PASTE
1853 // this is for the simple cut and paste mechanism
1854 static LyXParagraph * simple_cut_buffer = 0;
1855 static char simple_cut_buffer_textclass = 0;
1857 void DeleteSimpleCutBuffer()
1859 if (!simple_cut_buffer)
1861 LyXParagraph * tmppar;
1863 while (simple_cut_buffer) {
1864 tmppar = simple_cut_buffer;
1865 simple_cut_buffer = simple_cut_buffer->next;
1868 simple_cut_buffer = 0;
1872 void LyXText::copyEnvironmentType()
1874 copylayouttype = cursor.par->GetLayout();
1878 void LyXText::pasteEnvironmentType()
1880 SetLayout(copylayouttype);
1883 #ifdef USE_OLD_CUT_AND_PASTE
1884 void LyXText::CutSelection(bool doclear)
1886 // This doesn't make sense, if there is no selection
1890 // OK, we have a selection. This is always between sel_start_cursor
1891 // and sel_end cursor
1892 LyXParagraph * tmppar;
1894 // Check whether there are half footnotes in the selection
1895 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1896 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1897 tmppar = sel_start_cursor.par;
1898 while (tmppar != sel_end_cursor.par){
1899 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
1900 WriteAlert(_("Impossible operation"),
1901 _("Don't know what to do with half floats."),
1905 tmppar = tmppar->Next();
1909 /* table stuff -- begin */
1910 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
1911 if ( sel_start_cursor.par != sel_end_cursor.par) {
1912 WriteAlert(_("Impossible operation"),
1913 _("Don't know what to do with half tables."),
1917 sel_start_cursor.par->table->Reinit();
1919 /* table stuff -- end */
1921 // make sure that the depth behind the selection are restored, too
1922 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1923 LyXParagraph * undoendpar = endpar;
1925 if (endpar && endpar->GetDepth()) {
1926 while (endpar && endpar->GetDepth()) {
1927 endpar = endpar->LastPhysicalPar()->Next();
1928 undoendpar = endpar;
1930 } else if (endpar) {
1931 endpar = endpar->Next(); // because of parindents etc.
1934 SetUndo(Undo::DELETE,
1936 .par->ParFromPos(sel_start_cursor.pos)->previous,
1939 // clear the simple_cut_buffer
1940 DeleteSimpleCutBuffer();
1942 // set the textclass
1943 simple_cut_buffer_textclass = bparams->textclass;
1945 #ifdef WITH_WARNINGS
1946 #warning Asger: Make cut more intelligent here.
1949 White paper for "intelligent" cutting:
1951 Example: "This is our text."
1952 Using " our " as selection, cutting will give "This istext.".
1953 Using "our" as selection, cutting will give "This is text.".
1954 Using " our" as selection, cutting will give "This is text.".
1955 Using "our " as selection, cutting will give "This is text.".
1957 All those four selections will (however) paste identically:
1958 Pasting with the cursor right after the "is" will give the
1959 original text with all four selections.
1961 The rationale is to be intelligent such that words are copied,
1962 cut and pasted in a functional manner.
1964 This is not implemented yet. (Asger)
1966 The changes below sees to do a lot of what you want. However
1967 I have not verified that all cases work as they should:
1969 - cut in multiple row
1971 - cut across footnotes and paragraph
1972 My simplistic tests show that the idea are basically sound but
1973 there are some items to fix up...we only need to find them
1976 As do redo Asger's example above (with | beeing the cursor in the
1977 result after cutting.):
1979 Example: "This is our text."
1980 Using " our " as selection, cutting will give "This is|text.".
1981 Using "our" as selection, cutting will give "This is | text.".
1982 Using " our" as selection, cutting will give "This is| text.".
1983 Using "our " as selection, cutting will give "This is |text.".
1988 #ifndef FIX_DOUBLE_SPACE
1989 bool space_wrapped =
1990 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
1991 if (sel_end_cursor.pos > 0
1992 && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
1993 // please break before a space at the end
1994 sel_end_cursor.pos--;
1995 space_wrapped = true;
1997 // cut behind a space if there is one
1998 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
1999 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2000 && (sel_start_cursor.par != sel_end_cursor.par
2001 || sel_start_cursor.pos < sel_end_cursor.pos))
2002 sel_start_cursor.pos++;
2004 // there are two cases: cut only within one paragraph or
2005 // more than one paragraph
2007 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2008 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2009 // only within one paragraph
2010 simple_cut_buffer = new LyXParagraph;
2011 LyXParagraph::size_type i =
2012 sel_start_cursor.pos;
2013 for (; i < sel_end_cursor.pos; ++i) {
2014 /* table stuff -- begin */
2015 if (sel_start_cursor.par->table
2016 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)) {
2017 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2018 sel_start_cursor.pos++;
2020 /* table stuff -- end */
2021 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2022 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2024 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
2026 #ifndef FIX_DOUBLE_SPACE
2027 // check for double spaces
2028 if (sel_start_cursor.pos &&
2029 sel_start_cursor.par->Last() > sel_start_cursor.pos
2030 && sel_start_cursor.par
2031 ->IsLineSeparator(sel_start_cursor.pos - 1)
2032 && sel_start_cursor.par
2033 ->IsLineSeparator(sel_start_cursor.pos)) {
2034 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2037 simple_cut_buffer->InsertChar(i - sel_start_cursor.pos,
2040 endpar = sel_end_cursor.par->Next();
2042 // cut more than one paragraph
2045 ->BreakParagraphConservative(sel_end_cursor.pos);
2046 #ifndef FIX_DOUBLE_SPACE
2047 // insert a space at the end if there was one
2050 ->InsertChar(sel_end_cursor.par->Last(), ' ');
2052 sel_end_cursor.par = sel_end_cursor.par->Next();
2053 sel_end_cursor.pos = 0;
2055 cursor = sel_end_cursor;
2057 #ifndef FIX_DOUBLE_SPACE
2058 // please break behind a space, if there is one.
2059 // The space should be copied too
2060 if (sel_start_cursor.par
2061 ->IsLineSeparator(sel_start_cursor.pos))
2062 sel_start_cursor.pos++;
2064 sel_start_cursor.par
2065 ->BreakParagraphConservative(sel_start_cursor.pos);
2066 #ifndef FIX_DOUBLE_SPACE
2067 if (!sel_start_cursor.pos
2068 || sel_start_cursor.par
2069 ->IsLineSeparator(sel_start_cursor.pos - 1)
2070 || sel_start_cursor.par
2071 ->IsNewline(sel_start_cursor.pos - 1)) {
2072 sel_start_cursor.par->Next()->InsertChar(0, ' ');
2075 // store the endparagraph for redoing later
2076 endpar = sel_end_cursor.par->Next(); /* needed because
2081 // store the selection
2082 simple_cut_buffer = sel_start_cursor.par
2083 ->ParFromPos(sel_start_cursor.pos)->next;
2084 simple_cut_buffer->previous = 0;
2085 sel_end_cursor.par->previous->next = 0;
2087 // cut the selection
2088 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
2089 = sel_end_cursor.par;
2091 sel_end_cursor.par->previous
2092 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2094 // care about footnotes
2095 if (simple_cut_buffer->footnoteflag) {
2096 LyXParagraph * tmppar = simple_cut_buffer;
2098 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2099 tmppar = tmppar->next;
2103 // the cut selection should begin with standard layout
2104 simple_cut_buffer->Clear();
2106 // paste the paragraphs again, if possible
2108 sel_start_cursor.par->Next()->ClearParagraph();
2109 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
2111 !sel_start_cursor.par->Next()->Last())
2112 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
2114 #ifndef FIX_DOUBLE_SPACE
2115 // maybe a forgotten blank
2116 if (sel_start_cursor.pos
2117 && sel_start_cursor.par
2118 ->IsLineSeparator(sel_start_cursor.pos)
2119 && sel_start_cursor.par
2120 ->IsLineSeparator(sel_start_cursor.pos - 1)) {
2121 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2126 // sometimes necessary
2128 sel_start_cursor.par->ClearParagraph();
2130 RedoParagraphs(sel_start_cursor, endpar);
2133 cursor = sel_start_cursor;
2134 SetCursor(cursor.par, cursor.pos);
2135 sel_cursor = cursor;
2136 UpdateCounters(cursor.row);
2139 #else ///////////////////////////////////////////////////////////////////
2141 void LyXText::CutSelection(bool doclear)
2143 // This doesn't make sense, if there is no selection
2147 // OK, we have a selection. This is always between sel_start_cursor
2148 // and sel_end cursor
2149 LyXParagraph * tmppar;
2151 // Check whether there are half footnotes in the selection
2152 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2153 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2154 tmppar = sel_start_cursor.par;
2155 while (tmppar != sel_end_cursor.par){
2156 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
2157 WriteAlert(_("Impossible operation"),
2158 _("Don't know what to do with half floats."),
2162 tmppar = tmppar->Next();
2166 /* table stuff -- begin */
2167 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
2168 if ( sel_start_cursor.par != sel_end_cursor.par) {
2169 WriteAlert(_("Impossible operation"),
2170 _("Don't know what to do with half tables."),
2174 sel_start_cursor.par->table->Reinit();
2176 /* table stuff -- end */
2178 // make sure that the depth behind the selection are restored, too
2179 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
2180 LyXParagraph * undoendpar = endpar;
2182 if (endpar && endpar->GetDepth()) {
2183 while (endpar && endpar->GetDepth()) {
2184 endpar = endpar->LastPhysicalPar()->Next();
2185 undoendpar = endpar;
2187 } else if (endpar) {
2188 endpar = endpar->Next(); // because of parindents etc.
2191 SetUndo(Undo::DELETE, sel_start_cursor
2192 .par->ParFromPos(sel_start_cursor.pos)->previous, undoendpar);
2196 // there are two cases: cut only within one paragraph or
2197 // more than one paragraph
2198 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2199 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2200 // only within one paragraph
2201 endpar = sel_start_cursor.par;
2202 cap.cutSelection(sel_start_cursor.par, &endpar,
2203 sel_start_cursor.pos, sel_end_cursor.pos,
2204 bparams->textclass, doclear);
2206 endpar = sel_end_cursor.par;
2208 cap.cutSelection(sel_start_cursor.par, &endpar,
2209 sel_start_cursor.pos, sel_end_cursor.pos,
2210 bparams->textclass, doclear);
2211 cursor.par = sel_end_cursor.par = endpar;
2212 cursor.pos = sel_end_cursor.pos;
2214 endpar = sel_end_cursor.par->Next();
2216 // sometimes necessary
2218 sel_start_cursor.par->ClearParagraph();
2220 RedoParagraphs(sel_start_cursor, endpar);
2223 cursor = sel_start_cursor;
2224 SetCursor(cursor.par, cursor.pos);
2225 sel_cursor = cursor;
2226 UpdateCounters(cursor.row);
2230 #ifdef USE_OLD_CUT_AND_PASTE
2231 void LyXText::CopySelection()
2233 // this doesnt make sense, if there is no selection
2237 // ok we have a selection. This is always between sel_start_cursor
2238 // and sel_end cursor
2239 LyXParagraph * tmppar;
2241 /* check wether there are half footnotes in the selection */
2242 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2243 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2244 tmppar = sel_start_cursor.par;
2245 while (tmppar != sel_end_cursor.par) {
2246 if (tmppar->footnoteflag !=
2247 sel_end_cursor.par->footnoteflag) {
2248 WriteAlert(_("Impossible operation"),
2249 _("Don't know what to do"
2250 " with half floats."),
2254 tmppar = tmppar->Next();
2258 /* table stuff -- begin */
2259 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2260 if ( sel_start_cursor.par != sel_end_cursor.par){
2261 WriteAlert(_("Impossible operation"),
2262 _("Don't know what to do with half tables."),
2267 /* table stuff -- end */
2269 // delete the simple_cut_buffer
2270 DeleteSimpleCutBuffer();
2272 // set the textclass
2273 simple_cut_buffer_textclass = bparams->textclass;
2275 #ifdef FIX_DOUBLE_SPACE
2276 // copy behind a space if there is one
2277 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2278 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2279 && (sel_start_cursor.par != sel_end_cursor.par
2280 || sel_start_cursor.pos < sel_end_cursor.pos))
2281 sel_start_cursor.pos++;
2283 // there are two cases: copy only within one paragraph
2284 // or more than one paragraph
2285 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2286 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2287 // only within one paragraph
2288 simple_cut_buffer = new LyXParagraph;
2289 LyXParagraph::size_type i = 0;
2290 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2291 sel_start_cursor.par->CopyIntoMinibuffer(i);
2292 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2295 // copy more than one paragraph
2296 // clone the paragraphs within the selection
2298 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2299 simple_cut_buffer = tmppar->Clone();
2300 LyXParagraph *tmppar2 = simple_cut_buffer;
2302 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2304 tmppar = tmppar->next;
2305 tmppar2->next = tmppar->Clone();
2306 tmppar2->next->previous = tmppar2;
2307 tmppar2 = tmppar2->next;
2311 // care about footnotes
2312 if (simple_cut_buffer->footnoteflag) {
2313 tmppar = simple_cut_buffer;
2315 tmppar->footnoteflag =
2316 LyXParagraph::NO_FOOTNOTE;
2317 tmppar = tmppar->next;
2321 // the simple_cut_buffer paragraph is too big
2322 LyXParagraph::size_type tmpi2 =
2323 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2324 for (; tmpi2; --tmpi2)
2325 simple_cut_buffer->Erase(0);
2327 // now tmppar 2 is too big, delete all after sel_end_cursor.pos
2329 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2330 while (tmppar2->size() > tmpi2) {
2331 tmppar2->Erase(tmppar2->size() - 1);
2336 #else //////////////////////////////////////////////////////////////////////
2338 void LyXText::CopySelection()
2340 // this doesnt make sense, if there is no selection
2344 // ok we have a selection. This is always between sel_start_cursor
2345 // and sel_end cursor
2346 LyXParagraph * tmppar;
2348 /* check wether there are half footnotes in the selection */
2349 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2350 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2351 tmppar = sel_start_cursor.par;
2352 while (tmppar != sel_end_cursor.par) {
2353 if (tmppar->footnoteflag !=
2354 sel_end_cursor.par->footnoteflag) {
2355 WriteAlert(_("Impossible operation"),
2356 _("Don't know what to do"
2357 " with half floats."),
2361 tmppar = tmppar->Next();
2365 /* table stuff -- begin */
2366 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2367 if ( sel_start_cursor.par != sel_end_cursor.par){
2368 WriteAlert(_("Impossible operation"),
2369 _("Don't know what to do with half tables."),
2374 /* table stuff -- end */
2376 #ifdef FIX_DOUBLE_SPACE
2377 // copy behind a space if there is one
2378 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2379 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2380 && (sel_start_cursor.par != sel_end_cursor.par
2381 || sel_start_cursor.pos < sel_end_cursor.pos))
2382 sel_start_cursor.pos++;
2387 cap.copySelection(sel_start_cursor.par, sel_end_cursor.par,
2388 sel_start_cursor.pos, sel_end_cursor.pos,
2389 bparams->textclass);
2393 #ifdef USE_OLD_CUT_AND_PASTE
2394 void LyXText::PasteSelection()
2396 // this does not make sense, if there is nothing to paste
2397 if (!simple_cut_buffer)
2400 LyXParagraph * tmppar;
2401 LyXParagraph * endpar;
2403 LyXCursor tmpcursor;
2405 // be carefull with footnotes in footnotes
2406 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2408 // check whether the cut_buffer includes a footnote
2409 tmppar = simple_cut_buffer;
2411 && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2412 tmppar = tmppar->next;
2415 WriteAlert(_("Impossible operation"),
2416 _("Can't paste float into float!"),
2422 /* table stuff -- begin */
2423 if (cursor.par->table) {
2424 if (simple_cut_buffer->next) {
2425 WriteAlert(_("Impossible operation"),
2426 _("Table cell cannot include more than one paragraph!"),
2431 /* table stuff -- end */
2433 SetUndo(Undo::INSERT,
2434 cursor.par->ParFromPos(cursor.pos)->previous,
2435 cursor.par->ParFromPos(cursor.pos)->next);
2439 // There are two cases: cutbuffer only one paragraph or many
2440 if (!simple_cut_buffer->next) {
2441 // only within a paragraph
2443 #ifndef FIX_DOUBLE_SPACE
2444 // please break behind a space, if there is one
2445 while (tmpcursor.par->Last() > tmpcursor.pos
2446 && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2449 tmppar = simple_cut_buffer->Clone();
2450 /* table stuff -- begin */
2451 bool table_too_small = false;
2452 if (tmpcursor.par->table) {
2453 while (simple_cut_buffer->size()
2454 && !table_too_small) {
2455 if (simple_cut_buffer->IsNewline(0)){
2456 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2458 simple_cut_buffer->Erase(0);
2459 if (tmpcursor.pos < tmpcursor.par->Last())
2462 table_too_small = true;
2464 #ifdef FIX_DOUBLE_SPACE
2465 // This is an attempt to fix the
2466 // "never insert a space at the
2467 // beginning of a paragraph" problem.
2468 if (tmpcursor.pos == 0
2469 && simple_cut_buffer->IsLineSeparator(0)) {
2470 simple_cut_buffer->Erase(0);
2472 simple_cut_buffer->CutIntoMinibuffer(0);
2473 simple_cut_buffer->Erase(0);
2474 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2478 simple_cut_buffer->CutIntoMinibuffer(0);
2479 simple_cut_buffer->Erase(0);
2480 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2486 /* table stuff -- end */
2487 // Some provisions should be done here for checking
2488 // if we are inserting at the beginning of a
2489 // paragraph. If there are a space at the beginning
2490 // of the text to insert and we are inserting at
2491 // the beginning of the paragraph the space should
2493 while (simple_cut_buffer->size()) {
2494 #ifdef FIX_DOUBLE_SPACE
2495 // This is an attempt to fix the
2496 // "never insert a space at the
2497 // beginning of a paragraph" problem.
2498 if (tmpcursor.pos == 0
2499 && simple_cut_buffer->IsLineSeparator(0)) {
2500 simple_cut_buffer->Erase(0);
2502 simple_cut_buffer->CutIntoMinibuffer(0);
2503 simple_cut_buffer->Erase(0);
2504 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2508 simple_cut_buffer->CutIntoMinibuffer(0);
2509 simple_cut_buffer->Erase(0);
2510 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2515 delete simple_cut_buffer;
2516 simple_cut_buffer = tmppar;
2517 endpar = tmpcursor.par->Next();
2522 // make a copy of the simple cut_buffer
2523 tmppar = simple_cut_buffer;
2524 LyXParagraph * simple_cut_clone = tmppar->Clone();
2525 LyXParagraph * tmppar2 = simple_cut_clone;
2526 if (cursor.par->footnoteflag){
2527 tmppar->footnoteflag = cursor.par->footnoteflag;
2528 tmppar->footnotekind = cursor.par->footnotekind;
2530 while (tmppar->next) {
2531 tmppar = tmppar->next;
2532 tmppar2->next = tmppar->Clone();
2533 tmppar2->next->previous = tmppar2;
2534 tmppar2 = tmppar2->next;
2535 if (cursor.par->footnoteflag){
2536 tmppar->footnoteflag = cursor.par->footnoteflag;
2537 tmppar->footnotekind = cursor.par->footnotekind;
2541 // make sure there is no class difference
2542 cap.SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2546 // make the simple_cut_buffer exactly the same layout than
2547 // the cursor paragraph
2548 simple_cut_buffer->MakeSameLayout(cursor.par);
2550 // find the end of the buffer
2551 LyXParagraph * lastbuffer = simple_cut_buffer;
2552 while (lastbuffer->Next())
2553 lastbuffer = lastbuffer->Next();
2555 #ifndef FIX_DOUBLE_SPACE
2556 // Please break behind a space, if there is one. The space
2557 // should be copied too.
2558 if (cursor.par->Last() > cursor.pos
2559 && cursor.par->IsLineSeparator(cursor.pos))
2562 bool paste_the_end = false;
2564 // open the paragraph for inserting the simple_cut_buffer
2566 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2567 cursor.par->BreakParagraphConservative(cursor.pos);
2568 paste_the_end = true;
2571 #ifndef FIX_DOUBLE_SPACE
2572 // be careful with double spaces
2573 if ((!cursor.par->Last()
2574 || cursor.par->IsLineSeparator(cursor.pos - 1)
2575 || cursor.par->IsNewline(cursor.pos - 1))
2576 && simple_cut_buffer->text.size()
2577 && simple_cut_buffer->IsLineSeparator(0))
2578 simple_cut_buffer->Erase(0);
2580 // set the end for redoing later
2581 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2584 lastbuffer->ParFromPos(lastbuffer->Last())->next =
2585 cursor.par->ParFromPos(cursor.pos)->next;
2586 cursor.par->ParFromPos(cursor.pos)->next->previous =
2587 lastbuffer->ParFromPos(lastbuffer->Last());
2589 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2590 simple_cut_buffer->previous =
2591 cursor.par->ParFromPos(cursor.pos);
2593 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2594 lastbuffer = cursor.par;
2596 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2598 // store the new cursor position
2599 tmpcursor.par = lastbuffer;
2600 tmpcursor.pos = lastbuffer->Last();
2602 // maybe some pasting
2603 if (lastbuffer->Next() && paste_the_end) {
2604 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2605 #ifndef FIX_DOUBLE_SPACE
2606 // be careful with double spaces
2607 if ((!lastbuffer->Last()
2608 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2609 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2610 && lastbuffer->Next()->Last()
2611 && lastbuffer->Next()->IsLineSeparator(0))
2612 lastbuffer->Next()->Erase(0);
2614 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2616 } else if (!lastbuffer->Next()->Last()) {
2617 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2618 #ifndef FIX_DOUBLE_SPACE
2619 // be careful witth double spaces
2620 if ((!lastbuffer->Last()
2621 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2622 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2623 && lastbuffer->Next()->Last()
2624 && lastbuffer->Next()->IsLineSeparator(0))
2625 lastbuffer->Next()->Erase(0);
2627 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2629 } else if (!lastbuffer->Last()) {
2630 lastbuffer->MakeSameLayout(lastbuffer->next);
2631 #ifndef FIX_DOUBLE_SPACE
2632 // be careful witth double spaces
2633 if ((!lastbuffer->Last()
2634 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2635 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2636 && lastbuffer->Next()->Last()
2637 && lastbuffer->Next()->IsLineSeparator(0))
2638 lastbuffer->Next()->Erase(0);
2640 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2643 lastbuffer->Next()->ClearParagraph();
2646 // restore the simple cut buffer
2647 simple_cut_buffer = simple_cut_clone;
2650 RedoParagraphs(cursor, endpar);
2652 SetCursor(cursor.par, cursor.pos);
2655 sel_cursor = cursor;
2656 SetCursor(tmpcursor.par, tmpcursor.pos);
2658 UpdateCounters(cursor.row);
2661 #else ////////////////////////////////////////////////////////////////////
2663 void LyXText::PasteSelection()
2667 // this does not make sense, if there is nothing to paste
2668 if (!cap.checkPastePossible(cursor.par, cursor.pos))
2671 SetUndo(Undo::INSERT,
2672 cursor.par->ParFromPos(cursor.pos)->previous,
2673 cursor.par->ParFromPos(cursor.pos)->next);
2675 LyXParagraph *endpar;
2676 LyXParagraph *actpar = cursor.par;
2677 int endpos = cursor.pos;
2679 cap.pasteSelection(&actpar, &endpar, endpos, bparams->textclass);
2681 RedoParagraphs(cursor, endpar);
2683 SetCursor(cursor.par, cursor.pos);
2686 sel_cursor = cursor;
2687 SetCursor(actpar, endpos);
2689 UpdateCounters(cursor.row);
2693 // returns a pointer to the very first LyXParagraph
2694 LyXParagraph * LyXText::FirstParagraph() const
2696 return buffer->paragraph;
2700 // returns true if the specified string is at the specified position
2701 bool LyXText::IsStringInText(LyXParagraph * par,
2702 LyXParagraph::size_type pos,
2703 char const * str) const
2707 while (pos + i < par->Last() && str[i] &&
2708 str[i] == par->GetChar(pos + i)) {
2718 // sets the selection over the number of characters of string, no check!!
2719 void LyXText::SetSelectionOverString(char const * string)
2721 sel_cursor = cursor;
2722 for (int i = 0; string[i]; ++i)
2728 // simple replacing. The font of the first selected character is used
2729 void LyXText::ReplaceSelectionWithString(char const * str)
2734 if (!selection) { // create a dummy selection
2735 sel_end_cursor = cursor;
2736 sel_start_cursor = cursor;
2739 // Get font setting before we cut
2740 LyXParagraph::size_type pos = sel_end_cursor.pos;
2741 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2743 // Insert the new string
2744 for (int i = 0; str[i]; ++i) {
2745 sel_end_cursor.par->InsertChar(pos, str[i]);
2746 sel_end_cursor.par->SetFont(pos, font);
2750 // Cut the selection
2757 // if the string can be found: return true and set the cursor to
2759 bool LyXText::SearchForward(char const * str) const
2761 LyXParagraph * par = cursor.par;
2762 LyXParagraph::size_type pos = cursor.pos;
2763 while (par && !IsStringInText(par, pos, str)) {
2764 if (pos < par->Last() - 1)
2772 SetCursor(par, pos);
2780 bool LyXText::SearchBackward(char const * string) const
2782 LyXParagraph * par = cursor.par;
2783 int pos = cursor.pos;
2789 // We skip empty paragraphs (Asger)
2791 par = par->Previous();
2793 pos = par->Last() - 1;
2794 } while (par && pos < 0);
2796 } while (par && !IsStringInText(par, pos, string));
2799 SetCursor(par, pos);
2806 // needed to insert the selection
2807 void LyXText::InsertStringA(string const & str)
2809 LyXParagraph * par = cursor.par;
2810 LyXParagraph::size_type pos = cursor.pos;
2811 LyXParagraph::size_type a = 0;
2813 LyXParagraph * endpar = cursor.par->Next();
2818 textclasslist.Style(bparams->textclass,
2819 cursor.par->GetLayout()).isEnvironment();
2820 // only to be sure, should not be neccessary
2823 // insert the string, don't insert doublespace
2824 string::size_type i = 0;
2825 while (i < str.length()) {
2826 if (str[i] != '\n') {
2828 && i + 1 < str.length() && str[i + 1] != ' '
2829 && pos && par->GetChar(pos - 1)!= ' ') {
2830 par->InsertChar(pos,' ');
2831 par->SetFont(pos, current_font);
2833 } else if (par->table) {
2834 if (str[i] == '\t') {
2835 while((pos < par->size()) &&
2836 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2838 if (pos < par->size())
2840 else // no more fields to fill skip the rest
2842 } else if ((str[i] != 13) &&
2843 ((str[i] & 127) >= ' ')) {
2844 par->InsertChar(pos, str[i]);
2845 par->SetFont(pos, current_font);
2848 } else if (str[i] == ' ') {
2850 InsetSpecialChar * new_inset =
2851 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2852 if (par->InsertInsetAllowed(new_inset)) {
2853 par->InsertChar(pos, LyXParagraph::META_INSET);
2854 par->SetFont(pos, current_font);
2855 par->InsertInset(pos, new_inset);
2860 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2861 par->SetFont(pos, current_font);
2864 } else if (str[i] == '\t') {
2865 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2867 InsetSpecialChar * new_inset =
2868 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2869 if (par->InsertInsetAllowed(new_inset)) {
2870 par->InsertChar(pos, LyXParagraph::META_INSET);
2871 par->SetFont(pos, current_font);
2872 par->InsertInset(pos, new_inset);
2877 par->InsertChar(a, LyXParagraph::META_PROTECTED_SEPARATOR);
2878 par->SetFont(a, current_font);
2882 } else if (str[i] != 13 &&
2883 // Ignore unprintables
2884 (str[i] & 127) >= ' ') {
2885 par->InsertChar(pos, str[i]);
2886 par->SetFont(pos, current_font);
2891 if (i + 1 >= str.length()) {
2895 while((pos < par->size()) &&
2896 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2899 cell = NumberOfCell(par, pos);
2900 while((pos < par->size()) &&
2901 !(par->table->IsFirstCell(cell))) {
2903 while((pos < par->size()) &&
2904 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2907 cell = NumberOfCell(par, pos);
2909 if (pos >= par->size())
2910 // no more fields to fill skip the rest
2913 if (!par->size()) { // par is empty
2915 InsetSpecialChar * new_inset =
2916 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2917 if (par->InsertInsetAllowed(new_inset)) {
2918 par->InsertChar(pos, LyXParagraph::META_INSET);
2919 par->SetFont(pos, current_font);
2920 par->InsertInset(pos, new_inset);
2925 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2926 par->SetFont(pos, current_font);
2930 par->BreakParagraph(pos, flag);
2938 RedoParagraphs(cursor, endpar);
2939 SetCursor(cursor.par, cursor.pos);
2940 sel_cursor = cursor;
2941 SetCursor(par, pos);
2946 /* turns double-CR to single CR, others where converted into one blank and 13s
2947 * that are ignored .Double spaces are also converted into one. Spaces at
2948 * the beginning of a paragraph are forbidden. tabs are converted into one
2949 * space. then InsertStringA is called */
2950 void LyXText::InsertStringB(string const & s)
2953 LyXParagraph * par = cursor.par;
2954 string::size_type i = 1;
2955 while (i < str.length()) {
2956 if (str[i] == '\t' && !par->table)
2958 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2960 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2961 if (str[i + 1] != '\n') {
2962 if (str[i - 1] != ' ')
2967 while (i + 1 < str.length()
2968 && (str[i + 1] == ' '
2969 || str[i + 1] == '\t'
2970 || str[i + 1] == '\n'
2971 || str[i + 1] == 13)) {
2982 bool LyXText::GotoNextError() const
2984 LyXCursor res = cursor;
2986 if (res.pos < res.par->Last() - 1) {
2990 res.par = res.par->Next();
2995 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
2996 && res.par->GetInset(res.pos)->AutoDelete()));
2999 SetCursor(res.par, res.pos);
3006 bool LyXText::GotoNextNote() const
3008 LyXCursor res = cursor;
3010 if (res.pos < res.par->Last() - 1) {
3013 res.par = res.par->Next();
3018 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
3019 && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
3022 SetCursor(res.par, res.pos);
3029 void LyXText::CheckParagraph(LyXParagraph * par,
3030 LyXParagraph::size_type pos)
3033 LyXCursor tmpcursor;
3035 /* table stuff -- begin*/
3038 CheckParagraphInTable(par, pos);
3041 /* table stuff -- end*/
3044 LyXParagraph::size_type z;
3045 Row * row = GetRow(par, pos, y);
3047 // is there a break one row above
3048 if (row->previous && row->previous->par == row->par) {
3049 z = NextBreakPoint(row->previous, paperwidth);
3050 if ( z >= row->pos) {
3051 // set the dimensions of the row above
3052 y -= row->previous->height;
3054 refresh_row = row->previous;
3055 status = LyXText::NEED_MORE_REFRESH;
3057 BreakAgain(row->previous);
3059 // set the cursor again. Otherwise
3060 // dangling pointers are possible
3061 SetCursor(cursor.par, cursor.pos);
3062 sel_cursor = cursor;
3067 int tmpheight = row->height;
3068 LyXParagraph::size_type tmplast = RowLast(row);
3073 if (row->height == tmpheight && RowLast(row) == tmplast)
3074 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3076 status = LyXText::NEED_MORE_REFRESH;
3078 // check the special right address boxes
3079 if (textclasslist.Style(bparams->textclass,
3080 par->GetLayout()).margintype
3081 == MARGIN_RIGHT_ADDRESS_BOX) {
3082 tmpcursor.par = par;
3083 tmpcursor.row = row;
3086 tmpcursor.x_fix = 0;
3087 tmpcursor.pos = pos;
3088 RedoDrawingOfParagraph(tmpcursor);
3093 // set the cursor again. Otherwise dangling pointers are possible
3094 // also set the selection
3098 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
3099 sel_cursor = cursor;
3100 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
3101 sel_start_cursor = cursor;
3102 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
3103 sel_end_cursor = cursor;
3104 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
3105 last_sel_cursor = cursor;
3108 SetCursorIntern(cursor.par, cursor.pos);
3112 // returns 0 if inset wasn't found
3113 int LyXText::UpdateInset(Inset * inset)
3115 // first check the current paragraph
3116 int pos = cursor.par->GetPositionOfInset(inset);
3118 CheckParagraph(cursor.par, pos);
3122 // check every paragraph
3124 LyXParagraph * par = FirstParagraph();
3126 // make sure the paragraph is open
3127 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
3128 pos = par->GetPositionOfInset(inset);
3130 CheckParagraph(par, pos);
3141 void LyXText::SetCursor(LyXParagraph * par,
3142 LyXParagraph::size_type pos, bool setfont) const
3144 LyXCursor old_cursor = cursor;
3145 SetCursorIntern(par, pos, setfont);
3146 DeleteEmptyParagraphMechanism(old_cursor);
3150 void LyXText::SetCursorIntern(LyXParagraph * par,
3151 LyXParagraph::size_type pos, bool setfont) const
3153 // correct the cursor position if impossible
3154 if (pos > par->Last()){
3155 LyXParagraph * tmppar = par->ParFromPos(pos);
3156 pos = par->PositionInParFromPos(pos);
3159 if (par->IsDummy() && par->previous &&
3160 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3161 while (par->previous &&
3162 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
3163 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
3164 par = par->previous ;
3165 if (par->IsDummy() &&
3166 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3167 pos += par->size() + 1;
3169 if (par->previous) {
3170 par = par->previous;
3172 pos += par->size() + 1;
3180 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
3181 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3183 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3184 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3186 current_font = cursor.par->GetFontSettings(cursor.pos);
3187 real_current_font = GetFont(cursor.par, cursor.pos);
3190 /* get the cursor y position in text */
3192 Row * row = GetRow(par, pos, y);
3193 /* y is now the beginning of the cursor row */
3195 /* y is now the cursor baseline */
3198 /* now get the cursors x position */
3200 float fill_separator, fill_hfill, fill_label_hfill;
3201 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3202 LyXParagraph::size_type cursor_vpos;
3203 LyXParagraph::size_type last = RowLastPrintable(row);
3205 if (pos > last + 1) // This shouldn't happen.
3208 if (last < row->pos)
3210 else if (pos > last ||
3211 (pos - 1 >= row->pos &&
3212 (row->par->IsSeparator(pos) ||
3213 (row->par->table && row->par->IsNewline(pos))
3215 /// Place cursor after char at (logical) position pos-1
3216 cursor_vpos = (bidi_level(pos-1) % 2 == 0)
3217 ? log2vis(pos-1) + 1 : log2vis(pos-1);
3219 /// Place cursor before char at (logical) position pos
3220 cursor_vpos = (bidi_level(pos) % 2 == 0)
3221 ? log2vis(pos) : log2vis(pos) + 1;
3223 /* table stuff -- begin*/
3224 if (row->par->table) {
3225 int cell = NumberOfCell(row->par, row->pos);
3227 x += row->par->table->GetBeginningOfTextInCell(cell);
3228 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3229 pos = vis2log(vpos);
3230 if (row->par->IsNewline(pos)) {
3231 x = x_old + row->par->table->WidthOfColumn(cell);
3234 x += row->par->table->GetBeginningOfTextInCell(cell);
3236 x += SingleWidth(row->par, pos);
3240 /* table stuff -- end*/
3241 LyXParagraph::size_type main_body =
3242 BeginningOfMainBody(row->par);
3243 if (main_body > 0 &&
3244 (main_body-1 > last ||
3245 !row->par->IsLineSeparator(main_body-1)))
3248 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3249 pos = vis2log(vpos);
3250 if (main_body > 0 && pos == main_body-1) {
3251 x += fill_label_hfill +
3252 lyxfont::width(textclasslist
3253 .Style(bparams->textclass,
3254 row->par->GetLayout())
3256 GetFont(row->par, -2));
3257 if (row->par->IsLineSeparator(main_body-1))
3258 x -= SingleWidth(row->par, main_body-1);
3260 if (HfillExpansion(row, pos)) {
3261 x += SingleWidth(row->par, pos);
3262 if (pos >= main_body)
3265 x += fill_label_hfill;
3267 else if (row->par->IsSeparator(pos)) {
3268 x += SingleWidth(row->par, pos);
3269 if (pos >= main_body)
3270 x += fill_separator;
3272 x += SingleWidth(row->par, pos);
3278 cursor.x_fix = cursor.x;
3283 void LyXText::SetCursorFromCoordinates(int x, long y) const
3285 LyXCursor old_cursor = cursor;
3287 /* get the row first */
3289 Row * row = GetRowNearY(y);
3291 cursor.par = row->par;
3293 int column = GetColumnNearX(row, x);
3294 cursor.pos = row->pos + column;
3296 cursor.y = y + row->baseline;
3301 (cursor.pos == cursor.par->Last()
3302 || cursor.par->IsSeparator(cursor.pos)
3303 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3304 && !cursor.par->IsSeparator(cursor.pos))
3305 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3307 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3308 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3310 current_font = cursor.par->GetFontSettings(cursor.pos);
3311 real_current_font = GetFont(cursor.par, cursor.pos);
3313 DeleteEmptyParagraphMechanism(old_cursor);
3316 void LyXText::SetCursorFromCoordinates(LyXCursor & cur, int x, long y) const
3318 /* get the row first */
3320 Row * row = GetRowNearY(y);
3321 int column = GetColumnNearX(row, x);
3324 cur.pos = row->pos + column;
3326 cur.y = y + row->baseline;
3331 void LyXText::CursorLeft() const
3334 if (cursor.par->table) {
3335 int cell = NumberOfCell(cursor.par, cursor.pos);
3336 if (cursor.par->table->IsContRow(cell) &&
3337 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell)) < 0) {
3344 void LyXText::CursorLeftIntern() const
3346 if (cursor.pos > 0) {
3347 SetCursor(cursor.par, cursor.pos - 1);
3349 else if (cursor.par->Previous()) { // steps into the above paragraph.
3350 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3355 void LyXText::CursorRight() const
3357 CursorRightIntern();
3358 if (cursor.par->table) {
3359 int cell = NumberOfCell(cursor.par, cursor.pos);
3360 if (cursor.par->table->IsContRow(cell) &&
3361 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3368 void LyXText::CursorRightIntern() const
3370 if (cursor.pos < cursor.par->Last()) {
3371 SetCursor(cursor.par, cursor.pos + 1);
3373 else if (cursor.par->Next()) {
3374 SetCursor(cursor.par->Next(), 0);
3379 void LyXText::CursorUp() const
3381 SetCursorFromCoordinates(cursor.x_fix,
3382 cursor.y - cursor.row->baseline - 1);
3383 if (cursor.par->table) {
3384 int cell = NumberOfCell(cursor.par, cursor.pos);
3385 if (cursor.par->table->IsContRow(cell) &&
3386 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3393 void LyXText::CursorDown() const
3395 if (cursor.par->table &&
3396 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3399 SetCursorFromCoordinates(cursor.x_fix,
3400 cursor.y - cursor.row->baseline
3401 + cursor.row->height + 1);
3402 if (cursor.par->table) {
3403 int cell = NumberOfCell(cursor.par, cursor.pos);
3404 int cell_above = cursor.par->table->GetCellAbove(cell);
3405 while(cursor.par->table &&
3406 cursor.par->table->IsContRow(cell) &&
3407 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3408 SetCursorFromCoordinates(cursor.x_fix,
3409 cursor.y - cursor.row->baseline
3410 + cursor.row->height + 1);
3411 if (cursor.par->table) {
3412 cell = NumberOfCell(cursor.par, cursor.pos);
3413 cell_above = cursor.par->table->GetCellAbove(cell);
3420 void LyXText::CursorUpParagraph() const
3422 if (cursor.pos > 0) {
3423 SetCursor(cursor.par, 0);
3425 else if (cursor.par->Previous()) {
3426 SetCursor(cursor.par->Previous(), 0);
3431 void LyXText::CursorDownParagraph() const
3433 if (cursor.par->Next()) {
3434 SetCursor(cursor.par->Next(), 0);
3436 SetCursor(cursor.par, cursor.par->Last());
3442 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3444 // Would be wrong to delete anything if we have a selection.
3445 if (selection) return;
3447 // We allow all kinds of "mumbo-jumbo" when freespacing.
3448 if (textclasslist.Style(bparams->textclass,
3449 old_cursor.par->GetLayout()).free_spacing)
3452 bool deleted = false;
3454 #ifdef FIX_DOUBLE_SPACE
3455 /* Ok I'll put some comments here about what is missing.
3456 I have fixed BackSpace (and thus Delete) to not delete
3457 double-spaces automagically. I have also changed Cut,
3458 Copy and Paste to hopefully do some sensible things.
3459 There are still some small problems that can lead to
3460 double spaces stored in the document file or space at
3461 the beginning of paragraphs. This happens if you have
3462 the cursor betwenn to spaces and then save. Or if you
3463 cut and paste and the selection have a space at the
3464 beginning and then save right after the paste. I am
3465 sure none of these are very hard to fix, but I will
3466 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3467 that I can get some feedback. (Lgb)
3470 // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3471 // delete the LineSeparator.
3474 // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3475 // delete the LineSeparator.
3478 // If the pos around the old_cursor were spaces, delete one of them.
3479 if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) { // Only if the cursor has really moved
3481 if (old_cursor.pos > 0
3482 && old_cursor.pos < old_cursor.par->Last()
3483 && old_cursor.par->IsLineSeparator(old_cursor.pos)
3484 && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3485 old_cursor.par->Erase(old_cursor.pos - 1);
3486 status = LyXText::NEED_MORE_REFRESH;
3487 RedoParagraphs(old_cursor, old_cursor.par->Next());
3489 if (old_cursor.par == cursor.par &&
3490 cursor.pos > old_cursor.pos) {
3491 SetCursorIntern(cursor.par, cursor.pos - 1);
3498 // Do not delete empty paragraphs with keepempty set.
3499 if ((textclasslist.Style(bparams->textclass,
3500 old_cursor.par->GetLayout())).keepempty)
3503 LyXCursor tmpcursor;
3505 if (old_cursor.par != cursor.par) {
3506 if ( (old_cursor.par->Last() == 0
3507 || (old_cursor.par->Last() == 1
3508 && old_cursor.par->IsLineSeparator(0)))
3509 && old_cursor.par->FirstPhysicalPar()
3510 == old_cursor.par->LastPhysicalPar()) {
3511 // ok, we will delete anything
3513 // make sure that you do not delete any environments
3514 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3515 !(old_cursor.row->previous
3516 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3517 && !(old_cursor.row->next
3518 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3519 || (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3520 && ((old_cursor.row->previous
3521 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3522 || (old_cursor.row->next
3523 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3525 status = LyXText::NEED_MORE_REFRESH;
3528 if (old_cursor.row->previous) {
3529 refresh_row = old_cursor.row->previous;
3530 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3532 cursor = old_cursor; // that undo can restore the right cursor position
3533 LyXParagraph * endpar = old_cursor.par->next;
3534 if (endpar && endpar->GetDepth()) {
3535 while (endpar && endpar->GetDepth()) {
3536 endpar = endpar->LastPhysicalPar()->Next();
3539 SetUndo(Undo::DELETE,
3540 old_cursor.par->previous,
3545 RemoveRow(old_cursor.row);
3546 if (buffer->paragraph == old_cursor.par) {
3547 buffer->paragraph = buffer->paragraph->next;
3550 delete old_cursor.par;
3552 /* Breakagain the next par. Needed
3553 * because of the parindent that
3554 * can occur or dissappear. The
3555 * next row can change its height,
3556 * if there is another layout before */
3557 if (refresh_row->next) {
3558 BreakAgain(refresh_row->next);
3559 UpdateCounters(refresh_row);
3561 SetHeightOfRow(refresh_row);
3563 refresh_row = old_cursor.row->next;
3564 refresh_y = old_cursor.y - old_cursor.row->baseline;
3567 cursor = old_cursor; // that undo can restore the right cursor position
3568 LyXParagraph *endpar = old_cursor.par->next;
3569 if (endpar && endpar->GetDepth()) {
3570 while (endpar && endpar->GetDepth()) {
3571 endpar = endpar->LastPhysicalPar()->Next();
3574 SetUndo(Undo::DELETE,
3575 old_cursor.par->previous,
3580 RemoveRow(old_cursor.row);
3582 if (buffer->paragraph == old_cursor.par) {
3583 buffer->paragraph = buffer->paragraph->next;
3585 delete old_cursor.par;
3587 /* Breakagain the next par. Needed
3588 because of the parindent that can
3589 occur or dissappear.
3590 The next row can change its height,
3591 if there is another layout before
3594 BreakAgain(refresh_row);
3595 UpdateCounters(refresh_row->previous);
3601 SetCursorIntern(cursor.par, cursor.pos);
3603 SetCursor(cursor.par, cursor.pos);
3605 /* if (cursor.y > old_cursor.y)
3606 cursor.y -= old_cursor.row->height; */
3608 if (sel_cursor.par == old_cursor.par
3609 && sel_cursor.pos == sel_cursor.pos) {
3610 // correct selection
3611 sel_cursor = cursor;
3616 if (old_cursor.par->ClearParagraph()) {
3617 RedoParagraphs(old_cursor, old_cursor.par->Next());
3620 SetCursorIntern(cursor.par, cursor.pos);
3622 SetCursor(cursor.par, cursor.pos);
3624 sel_cursor = cursor;
3632 LyXParagraph * LyXText::GetParFromID(int id)
3634 LyXParagraph * result = FirstParagraph();
3635 while (result && result->id() != id)
3636 result = result->next;
3642 bool LyXText::TextUndo()
3644 // returns false if no undo possible
3645 Undo * undo = buffer->undostack.pop();
3650 .push(CreateUndo(undo->kind,
3651 GetParFromID(undo->number_of_before_par),
3652 GetParFromID(undo->number_of_behind_par)));
3654 return TextHandleUndo(undo);
3658 bool LyXText::TextRedo()
3660 // returns false if no redo possible
3661 Undo * undo = buffer->redostack.pop();
3666 .push(CreateUndo(undo->kind,
3667 GetParFromID(undo->number_of_before_par),
3668 GetParFromID(undo->number_of_behind_par)));
3670 return TextHandleUndo(undo);
3674 bool LyXText::TextHandleUndo(Undo * undo)
3676 // returns false if no undo possible
3677 bool result = false;
3679 LyXParagraph * before =
3680 GetParFromID(undo->number_of_before_par);
3681 LyXParagraph * behind =
3682 GetParFromID(undo->number_of_behind_par);
3683 LyXParagraph * tmppar;
3684 LyXParagraph * tmppar2;
3685 LyXParagraph * endpar;
3686 LyXParagraph * tmppar5;
3688 // if there's no before take the beginning
3689 // of the document for redoing
3691 SetCursorIntern(FirstParagraph(), 0);
3693 // replace the paragraphs with the undo informations
3695 LyXParagraph * tmppar3 = undo->par;
3696 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3697 LyXParagraph * tmppar4 = tmppar3;
3699 while (tmppar4->next)
3700 tmppar4 = tmppar4->next;
3701 } // get last undo par
3703 // now remove the old text if there is any
3704 if (before != behind || (!behind && !before)){
3706 tmppar5 = before->next;
3708 tmppar5 = buffer->paragraph;
3710 while (tmppar5 && tmppar5 != behind){
3712 tmppar5 = tmppar5->next;
3713 // a memory optimization for edit: Only layout information
3714 // is stored in the undo. So restore the text informations.
3715 if (undo->kind == Undo::EDIT) {
3716 tmppar2->setContentsFromPar(tmppar);
3717 tmppar->clearContents();
3718 //tmppar2->text = tmppar->text;
3719 //tmppar->text.clear();
3720 tmppar2 = tmppar2->next;
3722 if ( currentrow && currentrow->par == tmppar )
3723 currentrow = currentrow -> previous;
3724 // Commenting out this might remove the error
3725 // reported by Purify, but it might also
3726 // introduce a memory leak. We need to
3732 // put the new stuff in the list if there is one
3735 before->next = tmppar3;
3737 buffer->paragraph = tmppar3;
3738 tmppar3->previous = before;
3742 buffer->paragraph = behind;
3745 tmppar4->next = behind;
3747 behind->previous = tmppar4;
3751 // Set the cursor for redoing
3753 SetCursorIntern(before->FirstSelfrowPar(), 0);
3754 // check wether before points to a closed float and open it if necessary
3755 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3756 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3758 while (tmppar4->previous &&
3759 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3760 tmppar4 = tmppar4->previous;
3761 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3762 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3763 tmppar4 = tmppar4->next;
3768 // open a cosed footnote at the end if necessary
3769 if (behind && behind->previous &&
3770 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3771 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3772 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3773 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3774 behind = behind->next;
3778 // calculate the endpar for redoing the paragraphs.
3780 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3781 endpar = behind->LastPhysicalPar()->Next();
3783 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3788 tmppar = GetParFromID(undo->number_of_cursor_par);
3789 RedoParagraphs(cursor, endpar);
3791 SetCursorIntern(tmppar, undo->cursor_pos);
3792 UpdateCounters(cursor.row);
3802 void LyXText::FinishUndo()
3804 // makes sure the next operation will be stored
3805 undo_finished = True;
3809 void LyXText::FreezeUndo()
3811 // this is dangerous and for internal use only
3816 void LyXText::UnFreezeUndo()
3818 // this is dangerous and for internal use only
3819 undo_frozen = false;
3823 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3824 LyXParagraph const * behind) const
3827 buffer->undostack.push(CreateUndo(kind, before, behind));
3828 buffer->redostack.clear();
3832 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3833 LyXParagraph const * behind)
3835 buffer->redostack.push(CreateUndo(kind, before, behind));
3839 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3840 LyXParagraph const * behind) const
3842 int before_number = -1;
3843 int behind_number = -1;
3845 before_number = before->id();
3847 behind_number = behind->id();
3848 // Undo::EDIT and Undo::FINISH are
3849 // always finished. (no overlapping there)
3850 // overlapping only with insert and delete inside one paragraph:
3851 // Nobody wants all removed character
3852 // appear one by one when undoing.
3853 // EDIT is special since only layout information, not the
3854 // contents of a paragaph are stored.
3855 if (!undo_finished && kind != Undo::EDIT &&
3856 kind != Undo::FINISH){
3857 // check wether storing is needed
3858 if (!buffer->undostack.empty() &&
3859 buffer->undostack.top()->kind == kind &&
3860 buffer->undostack.top()->number_of_before_par == before_number &&
3861 buffer->undostack.top()->number_of_behind_par == behind_number ){
3866 // create a new Undo
3867 LyXParagraph * undopar;
3868 LyXParagraph * tmppar;
3869 LyXParagraph * tmppar2;
3871 LyXParagraph * start = 0;
3872 LyXParagraph * end = 0;
3875 start = before->next;
3877 start = FirstParagraph();
3879 end = behind->previous;
3881 end = FirstParagraph();
3887 && start != end->next
3888 && (before != behind || (!before && !behind))) {
3890 tmppar2 = tmppar->Clone();
3891 tmppar2->id(tmppar->id());
3893 // a memory optimization: Just store the layout information
3895 if (kind == Undo::EDIT){
3896 //tmppar2->text.clear();
3897 tmppar2->clearContents();
3902 while (tmppar != end && tmppar->next) {
3903 tmppar = tmppar->next;
3904 tmppar2->next = tmppar->Clone();
3905 tmppar2->next->id(tmppar->id());
3906 // a memory optimization: Just store the layout
3907 // information when only edit
3908 if (kind == Undo::EDIT){
3909 //tmppar2->next->text.clear();
3910 tmppar2->clearContents();
3912 tmppar2->next->previous = tmppar2;
3913 tmppar2 = tmppar2->next;
3917 undopar = 0; // nothing to replace (undo of delete maybe)
3919 int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
3920 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
3922 Undo * undo = new Undo(kind,
3923 before_number, behind_number,
3924 cursor_par, cursor_pos,
3927 undo_finished = false;
3932 void LyXText::SetCursorParUndo()
3934 SetUndo(Undo::FINISH,
3935 cursor.par->ParFromPos(cursor.pos)->previous,
3936 cursor.par->ParFromPos(cursor.pos)->next);
3940 void LyXText::RemoveTableRow(LyXCursor * cur) const
3946 // move to the previous row
3947 int cell_act = NumberOfCell(cur->par, cur->pos);
3950 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3953 !cur->par->table->IsFirstCell(cell_act)) {
3955 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3960 // now we have to pay attention if the actual table is the
3961 // main row of TableContRows and if yes to delete all of them
3966 // delete up to the next row
3967 while (cur->pos < cur->par->Last() &&
3969 || !cur->par->table->IsFirstCell(cell_act))) {
3970 while (cur->pos < cur->par->Last() &&
3971 !cur->par->IsNewline(cur->pos))
3972 cur->par->Erase(cur->pos);
3975 if (cur->pos < cur->par->Last())
3976 cur->par->Erase(cur->pos);
3978 if (cur->pos && cur->pos == cur->par->Last()) {
3980 cur->par->Erase(cur->pos); // no newline at very end!
3982 } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
3983 !cur->par->table->IsContRow(cell_org) &&
3984 cur->par->table->IsContRow(cell));
3985 cur->par->table->DeleteRow(cell_org);
3990 bool LyXText::IsEmptyTableCell() const
3992 LyXParagraph::size_type pos = cursor.pos - 1;
3993 while (pos >= 0 && pos < cursor.par->Last()
3994 && !cursor.par->IsNewline(pos))
3996 return cursor.par->IsNewline(pos + 1);
4000 void LyXText::toggleAppendix(){
4001 LyXParagraph * par = cursor.par->FirstPhysicalPar();
4002 bool start = !par->start_of_appendix;
4004 // ensure that we have only one start_of_appendix in this document
4005 LyXParagraph * tmp = FirstParagraph();
4006 for (; tmp; tmp = tmp->next)
4007 tmp->start_of_appendix = 0;
4008 par->start_of_appendix = start;
4010 // we can set the refreshing parameters now
4011 status = LyXText::NEED_MORE_REFRESH;
4013 refresh_row = 0; // not needed for full update
4015 SetCursor(cursor.par, cursor.pos);