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)
58 parameters = &p->params;
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(parameters->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(parameters->textclass,
178 par->GetLayout()).font);
179 par_depth = par->GetDepth();
183 tmpfont.realize(textclasslist.TextClass(parameters->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(parameters->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(parameters->textclass,
226 tp->GetLayout()).font);
230 layoutfont.realize(textclasslist.TextClass(parameters->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(parameters->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(parameters->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(parameters->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(parameters->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, parameters->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, parameters->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(parameters->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(parameters->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(parameters->textclass,
1264 cursor.par->GetLayout()).align;
1265 if (align & textclasslist
1266 .Style(parameters->textclass,
1267 cursor.par->GetLayout()).alignpossible) {
1268 if (align == textclasslist
1269 .Style(parameters->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(parameters->textclass,
1409 LyXTextClass const & textclass =
1410 textclasslist.TextClass(parameters->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(parameters->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(parameters->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(parameters->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<= parameters->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->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1586 s << alphaCounter(par->getCounter(i));
1588 s << hebrewCounter(par->getCounter(i));
1590 case LABEL_COUNTER_SECTION:
1591 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1592 s << alphaCounter(par->getCounter(i - 1));
1594 s << hebrewCounter(par->getCounter(i - 1));
1597 << par->getCounter(i);
1600 case LABEL_COUNTER_SUBSECTION:
1601 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1602 s << alphaCounter(par->getCounter(i - 2));
1604 s << hebrewCounter(par->getCounter(i - 2));
1607 << par->getCounter(i-1) << '.'
1608 << par->getCounter(i);
1611 case LABEL_COUNTER_SUBSUBSECTION:
1612 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1613 s << alphaCounter(par->getCounter(i-3));
1615 s << hebrewCounter(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->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1625 s << alphaCounter(par->getCounter(i-4));
1627 s << hebrewCounter(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->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1638 s << alphaCounter(par->getCounter(i-5));
1640 s << hebrewCounter(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->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1692 << loweralphaCounter(number)
1696 << hebrewCounter(number)
1700 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1701 s << romanCounter(number) << '.';
1703 s << '.' << romanCounter(number);
1706 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1707 s << alphaCounter(number)
1711 << alphaCounter(number);
1714 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
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 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1757 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1758 && (par->footnotekind == LyXParagraph::TAB
1759 || par->footnotekind == LyXParagraph::WIDE_TAB))
1760 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1764 else if (par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1765 && par->footnotekind == LyXParagraph::ALGORITHM)
1766 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1769 s = ":Ãúéøåâìà ";
1771 /* par->SetLayout(0);
1772 s = layout->labelstring; */
1773 if (par->getParDirection() == LYX_DIR_LEFT_TO_RIGHT)
1776 s = " :úåòîùî øñç";
1780 par->labelstring = s;
1782 /* reset the enumeration counter. They are always resetted
1783 * when there is any other layout between */
1784 for (int i = 6 + par->enumdepth; i < 10; ++i)
1785 par->setCounter(i, 0);
1790 /* Updates all counters BEHIND the row. Changed paragraphs
1791 * with a dynamic left margin will be rebroken. */
1792 void LyXText::UpdateCounters(Row * row) const
1801 && row->par->next->footnoteflag != LyXParagraph::OPEN_FOOTNOTE) {
1802 par = row->par->LastPhysicalPar()->Next();
1804 par = row->par->next;
1809 while (row->par != par)
1814 /* now check for the headline layouts. remember that they
1815 * have a dynamic left margin */
1817 && ( textclasslist.Style(parameters->textclass, par->layout).margintype == MARGIN_DYNAMIC
1818 || textclasslist.Style(parameters->textclass, par->layout).labeltype == LABEL_SENSITIVE)
1821 /* Rebreak the paragraph */
1822 RemoveParagraph(row);
1823 AppendParagraph(row);
1825 /* think about the damned open footnotes! */
1826 while (par->Next() &&
1827 (par->Next()->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
1828 || par->Next()->IsDummy())){
1830 if (par->IsDummy()) {
1831 while (row->par != par)
1833 RemoveParagraph(row);
1834 AppendParagraph(row);
1839 par = par->LastPhysicalPar()->Next();
1845 /* insets an inset. */
1846 void LyXText::InsertInset(Inset *inset)
1848 if (!cursor.par->InsertInsetAllowed(inset))
1850 SetUndo(Undo::INSERT,
1851 cursor.par->ParFromPos(cursor.pos)->previous,
1852 cursor.par->ParFromPos(cursor.pos)->next);
1853 cursor.par->InsertChar(cursor.pos, LyXParagraph::META_INSET);
1854 cursor.par->InsertInset(cursor.pos, inset);
1855 InsertChar(LyXParagraph::META_INSET); /* just to rebreak and refresh correctly.
1856 * The character will not be inserted a
1861 #ifdef USE_OLD_CUT_AND_PASTE
1862 // this is for the simple cut and paste mechanism
1863 static LyXParagraph * simple_cut_buffer = 0;
1864 static char simple_cut_buffer_textclass = 0;
1866 void DeleteSimpleCutBuffer()
1868 if (!simple_cut_buffer)
1870 LyXParagraph * tmppar;
1872 while (simple_cut_buffer) {
1873 tmppar = simple_cut_buffer;
1874 simple_cut_buffer = simple_cut_buffer->next;
1877 simple_cut_buffer = 0;
1881 void LyXText::copyEnvironmentType()
1883 copylayouttype = cursor.par->GetLayout();
1887 void LyXText::pasteEnvironmentType()
1889 SetLayout(copylayouttype);
1892 #ifdef USE_OLD_CUT_AND_PASTE
1893 void LyXText::CutSelection(bool doclear)
1895 // This doesn't make sense, if there is no selection
1899 // OK, we have a selection. This is always between sel_start_cursor
1900 // and sel_end cursor
1901 LyXParagraph * tmppar;
1903 // Check whether there are half footnotes in the selection
1904 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
1905 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1906 tmppar = sel_start_cursor.par;
1907 while (tmppar != sel_end_cursor.par){
1908 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
1909 WriteAlert(_("Impossible operation"),
1910 _("Don't know what to do with half floats."),
1914 tmppar = tmppar->Next();
1918 /* table stuff -- begin */
1919 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
1920 if ( sel_start_cursor.par != sel_end_cursor.par) {
1921 WriteAlert(_("Impossible operation"),
1922 _("Don't know what to do with half tables."),
1926 sel_start_cursor.par->table->Reinit();
1928 /* table stuff -- end */
1930 // make sure that the depth behind the selection are restored, too
1931 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
1932 LyXParagraph * undoendpar = endpar;
1934 if (endpar && endpar->GetDepth()) {
1935 while (endpar && endpar->GetDepth()) {
1936 endpar = endpar->LastPhysicalPar()->Next();
1937 undoendpar = endpar;
1939 } else if (endpar) {
1940 endpar = endpar->Next(); // because of parindents etc.
1943 SetUndo(Undo::DELETE,
1945 .par->ParFromPos(sel_start_cursor.pos)->previous,
1948 // clear the simple_cut_buffer
1949 DeleteSimpleCutBuffer();
1951 // set the textclass
1952 simple_cut_buffer_textclass = parameters->textclass;
1954 #ifdef WITH_WARNINGS
1955 #warning Asger: Make cut more intelligent here.
1958 White paper for "intelligent" cutting:
1960 Example: "This is our text."
1961 Using " our " as selection, cutting will give "This istext.".
1962 Using "our" as selection, cutting will give "This is text.".
1963 Using " our" as selection, cutting will give "This is text.".
1964 Using "our " as selection, cutting will give "This is text.".
1966 All those four selections will (however) paste identically:
1967 Pasting with the cursor right after the "is" will give the
1968 original text with all four selections.
1970 The rationale is to be intelligent such that words are copied,
1971 cut and pasted in a functional manner.
1973 This is not implemented yet. (Asger)
1975 The changes below sees to do a lot of what you want. However
1976 I have not verified that all cases work as they should:
1978 - cut in multiple row
1980 - cut across footnotes and paragraph
1981 My simplistic tests show that the idea are basically sound but
1982 there are some items to fix up...we only need to find them
1985 As do redo Asger's example above (with | beeing the cursor in the
1986 result after cutting.):
1988 Example: "This is our text."
1989 Using " our " as selection, cutting will give "This is|text.".
1990 Using "our" as selection, cutting will give "This is | text.".
1991 Using " our" as selection, cutting will give "This is| text.".
1992 Using "our " as selection, cutting will give "This is |text.".
1997 #ifndef FIX_DOUBLE_SPACE
1998 bool space_wrapped =
1999 sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos);
2000 if (sel_end_cursor.pos > 0
2001 && sel_end_cursor.par->IsLineSeparator(sel_end_cursor.pos - 1)) {
2002 // please break before a space at the end
2003 sel_end_cursor.pos--;
2004 space_wrapped = true;
2006 // cut behind a space if there is one
2007 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2008 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2009 && (sel_start_cursor.par != sel_end_cursor.par
2010 || sel_start_cursor.pos < sel_end_cursor.pos))
2011 sel_start_cursor.pos++;
2013 // there are two cases: cut only within one paragraph or
2014 // more than one paragraph
2016 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2017 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2018 // only within one paragraph
2019 simple_cut_buffer = new LyXParagraph;
2020 LyXParagraph::size_type i =
2021 sel_start_cursor.pos;
2022 for (; i < sel_end_cursor.pos; ++i) {
2023 /* table stuff -- begin */
2024 if (sel_start_cursor.par->table
2025 && sel_start_cursor.par->IsNewline(sel_start_cursor.pos)) {
2026 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2027 sel_start_cursor.pos++;
2029 /* table stuff -- end */
2030 sel_start_cursor.par->CopyIntoMinibuffer(sel_start_cursor.pos);
2031 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2033 simple_cut_buffer->InsertFromMinibuffer(simple_cut_buffer->Last());
2035 #ifndef FIX_DOUBLE_SPACE
2036 // check for double spaces
2037 if (sel_start_cursor.pos &&
2038 sel_start_cursor.par->Last() > sel_start_cursor.pos
2039 && sel_start_cursor.par
2040 ->IsLineSeparator(sel_start_cursor.pos - 1)
2041 && sel_start_cursor.par
2042 ->IsLineSeparator(sel_start_cursor.pos)) {
2043 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2046 simple_cut_buffer->InsertChar(i - sel_start_cursor.pos,
2049 endpar = sel_end_cursor.par->Next();
2051 // cut more than one paragraph
2054 ->BreakParagraphConservative(sel_end_cursor.pos);
2055 #ifndef FIX_DOUBLE_SPACE
2056 // insert a space at the end if there was one
2059 ->InsertChar(sel_end_cursor.par->Last(), ' ');
2061 sel_end_cursor.par = sel_end_cursor.par->Next();
2062 sel_end_cursor.pos = 0;
2064 cursor = sel_end_cursor;
2066 #ifndef FIX_DOUBLE_SPACE
2067 // please break behind a space, if there is one.
2068 // The space should be copied too
2069 if (sel_start_cursor.par
2070 ->IsLineSeparator(sel_start_cursor.pos))
2071 sel_start_cursor.pos++;
2073 sel_start_cursor.par
2074 ->BreakParagraphConservative(sel_start_cursor.pos);
2075 #ifndef FIX_DOUBLE_SPACE
2076 if (!sel_start_cursor.pos
2077 || sel_start_cursor.par
2078 ->IsLineSeparator(sel_start_cursor.pos - 1)
2079 || sel_start_cursor.par
2080 ->IsNewline(sel_start_cursor.pos - 1)) {
2081 sel_start_cursor.par->Next()->InsertChar(0, ' ');
2084 // store the endparagraph for redoing later
2085 endpar = sel_end_cursor.par->Next(); /* needed because
2090 // store the selection
2091 simple_cut_buffer = sel_start_cursor.par
2092 ->ParFromPos(sel_start_cursor.pos)->next;
2093 simple_cut_buffer->previous = 0;
2094 sel_end_cursor.par->previous->next = 0;
2096 // cut the selection
2097 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->next
2098 = sel_end_cursor.par;
2100 sel_end_cursor.par->previous
2101 = sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2103 // care about footnotes
2104 if (simple_cut_buffer->footnoteflag) {
2105 LyXParagraph * tmppar = simple_cut_buffer;
2107 tmppar->footnoteflag = LyXParagraph::NO_FOOTNOTE;
2108 tmppar = tmppar->next;
2112 // the cut selection should begin with standard layout
2113 simple_cut_buffer->Clear();
2115 // paste the paragraphs again, if possible
2117 sel_start_cursor.par->Next()->ClearParagraph();
2118 if (sel_start_cursor.par->FirstPhysicalPar()->HasSameLayout(sel_start_cursor.par->Next())
2120 !sel_start_cursor.par->Next()->Last())
2121 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)->PasteParagraph();
2123 #ifndef FIX_DOUBLE_SPACE
2124 // maybe a forgotten blank
2125 if (sel_start_cursor.pos
2126 && sel_start_cursor.par
2127 ->IsLineSeparator(sel_start_cursor.pos)
2128 && sel_start_cursor.par
2129 ->IsLineSeparator(sel_start_cursor.pos - 1)) {
2130 sel_start_cursor.par->Erase(sel_start_cursor.pos);
2135 // sometimes necessary
2137 sel_start_cursor.par->ClearParagraph();
2139 RedoParagraphs(sel_start_cursor, endpar);
2142 cursor = sel_start_cursor;
2143 SetCursor(cursor.par, cursor.pos);
2144 sel_cursor = cursor;
2145 UpdateCounters(cursor.row);
2148 #else ///////////////////////////////////////////////////////////////////
2150 void LyXText::CutSelection(bool doclear)
2152 // This doesn't make sense, if there is no selection
2156 // OK, we have a selection. This is always between sel_start_cursor
2157 // and sel_end cursor
2158 LyXParagraph * tmppar;
2160 // Check whether there are half footnotes in the selection
2161 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2162 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2163 tmppar = sel_start_cursor.par;
2164 while (tmppar != sel_end_cursor.par){
2165 if (tmppar->footnoteflag != sel_end_cursor.par->footnoteflag) {
2166 WriteAlert(_("Impossible operation"),
2167 _("Don't know what to do with half floats."),
2171 tmppar = tmppar->Next();
2175 /* table stuff -- begin */
2176 if (sel_start_cursor.par->table || sel_end_cursor.par->table) {
2177 if ( sel_start_cursor.par != sel_end_cursor.par) {
2178 WriteAlert(_("Impossible operation"),
2179 _("Don't know what to do with half tables."),
2183 sel_start_cursor.par->table->Reinit();
2185 /* table stuff -- end */
2187 // make sure that the depth behind the selection are restored, too
2188 LyXParagraph * endpar = sel_end_cursor.par->LastPhysicalPar()->Next();
2189 LyXParagraph * undoendpar = endpar;
2191 if (endpar && endpar->GetDepth()) {
2192 while (endpar && endpar->GetDepth()) {
2193 endpar = endpar->LastPhysicalPar()->Next();
2194 undoendpar = endpar;
2196 } else if (endpar) {
2197 endpar = endpar->Next(); // because of parindents etc.
2200 SetUndo(Undo::DELETE, sel_start_cursor
2201 .par->ParFromPos(sel_start_cursor.pos)->previous, undoendpar);
2205 // there are two cases: cut only within one paragraph or
2206 // more than one paragraph
2207 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2208 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2209 // only within one paragraph
2210 endpar = sel_start_cursor.par;
2211 cap.cutSelection(sel_start_cursor.par, &endpar,
2212 sel_start_cursor.pos, sel_end_cursor.pos,
2213 parameters->textclass, doclear);
2215 endpar = sel_end_cursor.par;
2217 cap.cutSelection(sel_start_cursor.par, &endpar,
2218 sel_start_cursor.pos, sel_end_cursor.pos,
2219 parameters->textclass, doclear);
2220 cursor.par = sel_end_cursor.par = endpar;
2221 cursor.pos = sel_end_cursor.pos;
2223 endpar = sel_end_cursor.par->Next();
2225 // sometimes necessary
2227 sel_start_cursor.par->ClearParagraph();
2229 RedoParagraphs(sel_start_cursor, endpar);
2232 cursor = sel_start_cursor;
2233 SetCursor(cursor.par, cursor.pos);
2234 sel_cursor = cursor;
2235 UpdateCounters(cursor.row);
2239 #ifdef USE_OLD_CUT_AND_PASTE
2240 void LyXText::CopySelection()
2242 // this doesnt make sense, if there is no selection
2246 // ok we have a selection. This is always between sel_start_cursor
2247 // and sel_end cursor
2248 LyXParagraph * tmppar;
2250 /* check wether there are half footnotes in the selection */
2251 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2252 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2253 tmppar = sel_start_cursor.par;
2254 while (tmppar != sel_end_cursor.par) {
2255 if (tmppar->footnoteflag !=
2256 sel_end_cursor.par->footnoteflag) {
2257 WriteAlert(_("Impossible operation"),
2258 _("Don't know what to do"
2259 " with half floats."),
2263 tmppar = tmppar->Next();
2267 /* table stuff -- begin */
2268 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2269 if ( sel_start_cursor.par != sel_end_cursor.par){
2270 WriteAlert(_("Impossible operation"),
2271 _("Don't know what to do with half tables."),
2276 /* table stuff -- end */
2278 // delete the simple_cut_buffer
2279 DeleteSimpleCutBuffer();
2281 // set the textclass
2282 simple_cut_buffer_textclass = parameters->textclass;
2284 #ifdef FIX_DOUBLE_SPACE
2285 // copy behind a space if there is one
2286 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2287 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2288 && (sel_start_cursor.par != sel_end_cursor.par
2289 || sel_start_cursor.pos < sel_end_cursor.pos))
2290 sel_start_cursor.pos++;
2292 // there are two cases: copy only within one paragraph
2293 // or more than one paragraph
2294 if (sel_start_cursor.par->ParFromPos(sel_start_cursor.pos)
2295 == sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)) {
2296 // only within one paragraph
2297 simple_cut_buffer = new LyXParagraph;
2298 LyXParagraph::size_type i = 0;
2299 for (i = sel_start_cursor.pos; i < sel_end_cursor.pos; ++i){
2300 sel_start_cursor.par->CopyIntoMinibuffer(i);
2301 simple_cut_buffer->InsertFromMinibuffer(i - sel_start_cursor.pos);
2304 // copy more than one paragraph
2305 // clone the paragraphs within the selection
2307 sel_start_cursor.par->ParFromPos(sel_start_cursor.pos);
2308 simple_cut_buffer = tmppar->Clone();
2309 LyXParagraph *tmppar2 = simple_cut_buffer;
2311 while (tmppar != sel_end_cursor.par->ParFromPos(sel_end_cursor.pos)
2313 tmppar = tmppar->next;
2314 tmppar2->next = tmppar->Clone();
2315 tmppar2->next->previous = tmppar2;
2316 tmppar2 = tmppar2->next;
2320 // care about footnotes
2321 if (simple_cut_buffer->footnoteflag) {
2322 tmppar = simple_cut_buffer;
2324 tmppar->footnoteflag =
2325 LyXParagraph::NO_FOOTNOTE;
2326 tmppar = tmppar->next;
2330 // the simple_cut_buffer paragraph is too big
2331 LyXParagraph::size_type tmpi2 =
2332 sel_start_cursor.par->PositionInParFromPos(sel_start_cursor.pos);
2333 for (; tmpi2; --tmpi2)
2334 simple_cut_buffer->Erase(0);
2336 // now tmppar 2 is too big, delete all after sel_end_cursor.pos
2338 tmpi2 = sel_end_cursor.par->PositionInParFromPos(sel_end_cursor.pos);
2339 while (tmppar2->size() > tmpi2) {
2340 tmppar2->Erase(tmppar2->size() - 1);
2345 #else //////////////////////////////////////////////////////////////////////
2347 void LyXText::CopySelection()
2349 // this doesnt make sense, if there is no selection
2353 // ok we have a selection. This is always between sel_start_cursor
2354 // and sel_end cursor
2355 LyXParagraph * tmppar;
2357 /* check wether there are half footnotes in the selection */
2358 if (sel_start_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2359 || sel_end_cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2360 tmppar = sel_start_cursor.par;
2361 while (tmppar != sel_end_cursor.par) {
2362 if (tmppar->footnoteflag !=
2363 sel_end_cursor.par->footnoteflag) {
2364 WriteAlert(_("Impossible operation"),
2365 _("Don't know what to do"
2366 " with half floats."),
2370 tmppar = tmppar->Next();
2374 /* table stuff -- begin */
2375 if (sel_start_cursor.par->table || sel_end_cursor.par->table){
2376 if ( sel_start_cursor.par != sel_end_cursor.par){
2377 WriteAlert(_("Impossible operation"),
2378 _("Don't know what to do with half tables."),
2383 /* table stuff -- end */
2385 #ifdef FIX_DOUBLE_SPACE
2386 // copy behind a space if there is one
2387 while (sel_start_cursor.par->Last() > sel_start_cursor.pos
2388 && sel_start_cursor.par->IsLineSeparator(sel_start_cursor.pos)
2389 && (sel_start_cursor.par != sel_end_cursor.par
2390 || sel_start_cursor.pos < sel_end_cursor.pos))
2391 sel_start_cursor.pos++;
2396 cap.copySelection(sel_start_cursor.par, sel_end_cursor.par,
2397 sel_start_cursor.pos, sel_end_cursor.pos,
2398 parameters->textclass);
2402 #ifdef USE_OLD_CUT_AND_PASTE
2403 void LyXText::PasteSelection()
2405 // this does not make sense, if there is nothing to paste
2406 if (!simple_cut_buffer)
2409 LyXParagraph * tmppar;
2410 LyXParagraph * endpar;
2412 LyXCursor tmpcursor;
2414 // be carefull with footnotes in footnotes
2415 if (cursor.par->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
2417 // check whether the cut_buffer includes a footnote
2418 tmppar = simple_cut_buffer;
2420 && tmppar->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2421 tmppar = tmppar->next;
2424 WriteAlert(_("Impossible operation"),
2425 _("Can't paste float into float!"),
2431 /* table stuff -- begin */
2432 if (cursor.par->table) {
2433 if (simple_cut_buffer->next) {
2434 WriteAlert(_("Impossible operation"),
2435 _("Table cell cannot include more than one paragraph!"),
2440 /* table stuff -- end */
2442 SetUndo(Undo::INSERT,
2443 cursor.par->ParFromPos(cursor.pos)->previous,
2444 cursor.par->ParFromPos(cursor.pos)->next);
2448 // There are two cases: cutbuffer only one paragraph or many
2449 if (!simple_cut_buffer->next) {
2450 // only within a paragraph
2452 #ifndef FIX_DOUBLE_SPACE
2453 // please break behind a space, if there is one
2454 while (tmpcursor.par->Last() > tmpcursor.pos
2455 && tmpcursor.par->IsLineSeparator(tmpcursor.pos))
2458 tmppar = simple_cut_buffer->Clone();
2459 /* table stuff -- begin */
2460 bool table_too_small = false;
2461 if (tmpcursor.par->table) {
2462 while (simple_cut_buffer->size()
2463 && !table_too_small) {
2464 if (simple_cut_buffer->IsNewline(0)){
2465 while(tmpcursor.pos < tmpcursor.par->Last() && !tmpcursor.par->IsNewline(tmpcursor.pos))
2467 simple_cut_buffer->Erase(0);
2468 if (tmpcursor.pos < tmpcursor.par->Last())
2471 table_too_small = true;
2473 #ifdef FIX_DOUBLE_SPACE
2474 // This is an attempt to fix the
2475 // "never insert a space at the
2476 // beginning of a paragraph" problem.
2477 if (tmpcursor.pos == 0
2478 && simple_cut_buffer->IsLineSeparator(0)) {
2479 simple_cut_buffer->Erase(0);
2481 simple_cut_buffer->CutIntoMinibuffer(0);
2482 simple_cut_buffer->Erase(0);
2483 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2487 simple_cut_buffer->CutIntoMinibuffer(0);
2488 simple_cut_buffer->Erase(0);
2489 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2495 /* table stuff -- end */
2496 // Some provisions should be done here for checking
2497 // if we are inserting at the beginning of a
2498 // paragraph. If there are a space at the beginning
2499 // of the text to insert and we are inserting at
2500 // the beginning of the paragraph the space should
2502 while (simple_cut_buffer->size()) {
2503 #ifdef FIX_DOUBLE_SPACE
2504 // This is an attempt to fix the
2505 // "never insert a space at the
2506 // beginning of a paragraph" problem.
2507 if (tmpcursor.pos == 0
2508 && simple_cut_buffer->IsLineSeparator(0)) {
2509 simple_cut_buffer->Erase(0);
2511 simple_cut_buffer->CutIntoMinibuffer(0);
2512 simple_cut_buffer->Erase(0);
2513 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2517 simple_cut_buffer->CutIntoMinibuffer(0);
2518 simple_cut_buffer->Erase(0);
2519 tmpcursor.par->InsertFromMinibuffer(tmpcursor.pos);
2524 delete simple_cut_buffer;
2525 simple_cut_buffer = tmppar;
2526 endpar = tmpcursor.par->Next();
2531 // make a copy of the simple cut_buffer
2532 tmppar = simple_cut_buffer;
2533 LyXParagraph * simple_cut_clone = tmppar->Clone();
2534 LyXParagraph * tmppar2 = simple_cut_clone;
2535 if (cursor.par->footnoteflag){
2536 tmppar->footnoteflag = cursor.par->footnoteflag;
2537 tmppar->footnotekind = cursor.par->footnotekind;
2539 while (tmppar->next) {
2540 tmppar = tmppar->next;
2541 tmppar2->next = tmppar->Clone();
2542 tmppar2->next->previous = tmppar2;
2543 tmppar2 = tmppar2->next;
2544 if (cursor.par->footnoteflag){
2545 tmppar->footnoteflag = cursor.par->footnoteflag;
2546 tmppar->footnotekind = cursor.par->footnotekind;
2550 // make sure there is no class difference
2551 cap.SwitchLayoutsBetweenClasses(simple_cut_buffer_textclass,
2552 parameters->textclass,
2555 // make the simple_cut_buffer exactly the same layout than
2556 // the cursor paragraph
2557 simple_cut_buffer->MakeSameLayout(cursor.par);
2559 // find the end of the buffer
2560 LyXParagraph * lastbuffer = simple_cut_buffer;
2561 while (lastbuffer->Next())
2562 lastbuffer = lastbuffer->Next();
2564 #ifndef FIX_DOUBLE_SPACE
2565 // Please break behind a space, if there is one. The space
2566 // should be copied too.
2567 if (cursor.par->Last() > cursor.pos
2568 && cursor.par->IsLineSeparator(cursor.pos))
2571 bool paste_the_end = false;
2573 // open the paragraph for inserting the simple_cut_buffer
2575 if (cursor.par->Last() > cursor.pos || !cursor.par->Next()){
2576 cursor.par->BreakParagraphConservative(cursor.pos);
2577 paste_the_end = true;
2580 #ifndef FIX_DOUBLE_SPACE
2581 // be careful with double spaces
2582 if ((!cursor.par->Last()
2583 || cursor.par->IsLineSeparator(cursor.pos - 1)
2584 || cursor.par->IsNewline(cursor.pos - 1))
2585 && simple_cut_buffer->text.size()
2586 && simple_cut_buffer->IsLineSeparator(0))
2587 simple_cut_buffer->Erase(0);
2589 // set the end for redoing later
2590 endpar = cursor.par->ParFromPos(cursor.pos)->next->Next();
2593 lastbuffer->ParFromPos(lastbuffer->Last())->next =
2594 cursor.par->ParFromPos(cursor.pos)->next;
2595 cursor.par->ParFromPos(cursor.pos)->next->previous =
2596 lastbuffer->ParFromPos(lastbuffer->Last());
2598 cursor.par->ParFromPos(cursor.pos)->next = simple_cut_buffer;
2599 simple_cut_buffer->previous =
2600 cursor.par->ParFromPos(cursor.pos);
2602 if (cursor.par->ParFromPos(cursor.pos)->Next() == lastbuffer)
2603 lastbuffer = cursor.par;
2605 cursor.par->ParFromPos(cursor.pos)->PasteParagraph();
2607 // store the new cursor position
2608 tmpcursor.par = lastbuffer;
2609 tmpcursor.pos = lastbuffer->Last();
2611 // maybe some pasting
2612 if (lastbuffer->Next() && paste_the_end) {
2613 if (lastbuffer->Next()->HasSameLayout(lastbuffer)) {
2614 #ifndef FIX_DOUBLE_SPACE
2615 // be careful with double spaces
2616 if ((!lastbuffer->Last()
2617 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2618 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2619 && lastbuffer->Next()->Last()
2620 && lastbuffer->Next()->IsLineSeparator(0))
2621 lastbuffer->Next()->Erase(0);
2623 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2625 } else if (!lastbuffer->Next()->Last()) {
2626 lastbuffer->Next()->MakeSameLayout(lastbuffer);
2627 #ifndef FIX_DOUBLE_SPACE
2628 // be careful witth double spaces
2629 if ((!lastbuffer->Last()
2630 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2631 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2632 && lastbuffer->Next()->Last()
2633 && lastbuffer->Next()->IsLineSeparator(0))
2634 lastbuffer->Next()->Erase(0);
2636 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2638 } else if (!lastbuffer->Last()) {
2639 lastbuffer->MakeSameLayout(lastbuffer->next);
2640 #ifndef FIX_DOUBLE_SPACE
2641 // be careful witth double spaces
2642 if ((!lastbuffer->Last()
2643 || lastbuffer->IsLineSeparator(lastbuffer->Last() - 1)
2644 || lastbuffer->IsNewline(lastbuffer->Last() - 1))
2645 && lastbuffer->Next()->Last()
2646 && lastbuffer->Next()->IsLineSeparator(0))
2647 lastbuffer->Next()->Erase(0);
2649 lastbuffer->ParFromPos(lastbuffer->Last())->PasteParagraph();
2652 lastbuffer->Next()->ClearParagraph();
2655 // restore the simple cut buffer
2656 simple_cut_buffer = simple_cut_clone;
2659 RedoParagraphs(cursor, endpar);
2661 SetCursor(cursor.par, cursor.pos);
2664 sel_cursor = cursor;
2665 SetCursor(tmpcursor.par, tmpcursor.pos);
2667 UpdateCounters(cursor.row);
2670 #else ////////////////////////////////////////////////////////////////////
2672 void LyXText::PasteSelection()
2676 // this does not make sense, if there is nothing to paste
2677 if (!cap.checkPastePossible(cursor.par, cursor.pos))
2680 SetUndo(Undo::INSERT,
2681 cursor.par->ParFromPos(cursor.pos)->previous,
2682 cursor.par->ParFromPos(cursor.pos)->next);
2684 LyXParagraph *endpar;
2685 LyXParagraph *actpar = cursor.par;
2686 int endpos = cursor.pos;
2688 cap.pasteSelection(&actpar, &endpar, endpos, parameters->textclass);
2690 RedoParagraphs(cursor, endpar);
2692 SetCursor(cursor.par, cursor.pos);
2695 sel_cursor = cursor;
2696 SetCursor(actpar, endpos);
2698 UpdateCounters(cursor.row);
2702 // returns a pointer to the very first LyXParagraph
2703 LyXParagraph * LyXText::FirstParagraph() const
2705 return params->paragraph;
2709 // returns true if the specified string is at the specified position
2710 bool LyXText::IsStringInText(LyXParagraph * par,
2711 LyXParagraph::size_type pos,
2712 char const * str) const
2716 while (pos + i < par->Last() && str[i] &&
2717 str[i] == par->GetChar(pos + i)) {
2727 // sets the selection over the number of characters of string, no check!!
2728 void LyXText::SetSelectionOverString(char const * string)
2730 sel_cursor = cursor;
2731 for (int i = 0; string[i]; ++i)
2737 // simple replacing. The font of the first selected character is used
2738 void LyXText::ReplaceSelectionWithString(char const * str)
2743 if (!selection) { // create a dummy selection
2744 sel_end_cursor = cursor;
2745 sel_start_cursor = cursor;
2748 // Get font setting before we cut
2749 LyXParagraph::size_type pos = sel_end_cursor.pos;
2750 LyXFont font = sel_start_cursor.par->GetFontSettings(sel_start_cursor.pos);
2752 // Insert the new string
2753 for (int i = 0; str[i]; ++i) {
2754 sel_end_cursor.par->InsertChar(pos, str[i]);
2755 sel_end_cursor.par->SetFont(pos, font);
2759 // Cut the selection
2766 // if the string can be found: return true and set the cursor to
2768 bool LyXText::SearchForward(char const * str) const
2770 LyXParagraph * par = cursor.par;
2771 LyXParagraph::size_type pos = cursor.pos;
2772 while (par && !IsStringInText(par, pos, str)) {
2773 if (pos < par->Last() - 1)
2781 SetCursor(par, pos);
2789 bool LyXText::SearchBackward(char const * string) const
2791 LyXParagraph * par = cursor.par;
2792 int pos = cursor.pos;
2798 // We skip empty paragraphs (Asger)
2800 par = par->Previous();
2802 pos = par->Last() - 1;
2803 } while (par && pos < 0);
2805 } while (par && !IsStringInText(par, pos, string));
2808 SetCursor(par, pos);
2815 // needed to insert the selection
2816 void LyXText::InsertStringA(string const & str)
2818 LyXParagraph * par = cursor.par;
2819 LyXParagraph::size_type pos = cursor.pos;
2820 LyXParagraph::size_type a = 0;
2822 LyXParagraph * endpar = cursor.par->Next();
2827 textclasslist.Style(parameters->textclass,
2828 cursor.par->GetLayout()).isEnvironment();
2829 // only to be sure, should not be neccessary
2832 // insert the string, don't insert doublespace
2833 string::size_type i = 0;
2834 while (i < str.length()) {
2835 if (str[i] != '\n') {
2837 && i + 1 < str.length() && str[i + 1] != ' '
2838 && pos && par->GetChar(pos - 1)!= ' ') {
2839 par->InsertChar(pos,' ');
2840 par->SetFont(pos, current_font);
2842 } else if (par->table) {
2843 if (str[i] == '\t') {
2844 while((pos < par->size()) &&
2845 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2847 if (pos < par->size())
2849 else // no more fields to fill skip the rest
2851 } else if ((str[i] != 13) &&
2852 ((str[i] & 127) >= ' ')) {
2853 par->InsertChar(pos, str[i]);
2854 par->SetFont(pos, current_font);
2857 } else if (str[i] == ' ') {
2859 InsetSpecialChar * new_inset =
2860 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2861 if (par->InsertInsetAllowed(new_inset)) {
2862 par->InsertChar(pos, LyXParagraph::META_INSET);
2863 par->SetFont(pos, current_font);
2864 par->InsertInset(pos, new_inset);
2869 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2870 par->SetFont(pos, current_font);
2873 } else if (str[i] == '\t') {
2874 for (a = pos; a < (pos / 8 + 1) * 8 ; ++a) {
2876 InsetSpecialChar * new_inset =
2877 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2878 if (par->InsertInsetAllowed(new_inset)) {
2879 par->InsertChar(pos, LyXParagraph::META_INSET);
2880 par->SetFont(pos, current_font);
2881 par->InsertInset(pos, new_inset);
2886 par->InsertChar(a, LyXParagraph::META_PROTECTED_SEPARATOR);
2887 par->SetFont(a, current_font);
2891 } else if (str[i] != 13 &&
2892 // Ignore unprintables
2893 (str[i] & 127) >= ' ') {
2894 par->InsertChar(pos, str[i]);
2895 par->SetFont(pos, current_font);
2900 if (i + 1 >= str.length()) {
2904 while((pos < par->size()) &&
2905 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2908 cell = NumberOfCell(par, pos);
2909 while((pos < par->size()) &&
2910 !(par->table->IsFirstCell(cell))) {
2912 while((pos < par->size()) &&
2913 (par->GetChar(pos) != LyXParagraph::META_NEWLINE))
2916 cell = NumberOfCell(par, pos);
2918 if (pos >= par->size())
2919 // no more fields to fill skip the rest
2922 if (!par->size()) { // par is empty
2924 InsetSpecialChar * new_inset =
2925 new InsetSpecialChar(InsetSpecialChar::PROTECTED_SEPARATOR);
2926 if (par->InsertInsetAllowed(new_inset)) {
2927 par->InsertChar(pos, LyXParagraph::META_INSET);
2928 par->SetFont(pos, current_font);
2929 par->InsertInset(pos, new_inset);
2934 par->InsertChar(pos, LyXParagraph::META_PROTECTED_SEPARATOR);
2935 par->SetFont(pos, current_font);
2939 par->BreakParagraph(pos, flag);
2947 RedoParagraphs(cursor, endpar);
2948 SetCursor(cursor.par, cursor.pos);
2949 sel_cursor = cursor;
2950 SetCursor(par, pos);
2955 /* turns double-CR to single CR, others where converted into one blank and 13s
2956 * that are ignored .Double spaces are also converted into one. Spaces at
2957 * the beginning of a paragraph are forbidden. tabs are converted into one
2958 * space. then InsertStringA is called */
2959 void LyXText::InsertStringB(string const & s)
2962 LyXParagraph * par = cursor.par;
2963 string::size_type i = 1;
2964 while (i < str.length()) {
2965 if (str[i] == '\t' && !par->table)
2967 if (str[i] == ' ' && i + 1 < str.length() && str[i + 1] == ' ')
2969 if (str[i] == '\n' && i + 1 < str.length() && !par->table){
2970 if (str[i + 1] != '\n') {
2971 if (str[i - 1] != ' ')
2976 while (i + 1 < str.length()
2977 && (str[i + 1] == ' '
2978 || str[i + 1] == '\t'
2979 || str[i + 1] == '\n'
2980 || str[i + 1] == 13)) {
2991 bool LyXText::GotoNextError() const
2993 LyXCursor res = cursor;
2995 if (res.pos < res.par->Last() - 1) {
2999 res.par = res.par->Next();
3004 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
3005 && res.par->GetInset(res.pos)->AutoDelete()));
3008 SetCursor(res.par, res.pos);
3015 bool LyXText::GotoNextNote() const
3017 LyXCursor res = cursor;
3019 if (res.pos < res.par->Last() - 1) {
3022 res.par = res.par->Next();
3027 !(res.par->GetChar(res.pos) == LyXParagraph::META_INSET
3028 && res.par->GetInset(res.pos)->LyxCode() == Inset::IGNORE_CODE));
3031 SetCursor(res.par, res.pos);
3038 void LyXText::CheckParagraph(LyXParagraph * par,
3039 LyXParagraph::size_type pos)
3042 LyXCursor tmpcursor;
3044 /* table stuff -- begin*/
3047 CheckParagraphInTable(par, pos);
3050 /* table stuff -- end*/
3053 LyXParagraph::size_type z;
3054 Row * row = GetRow(par, pos, y);
3056 // is there a break one row above
3057 if (row->previous && row->previous->par == row->par) {
3058 z = NextBreakPoint(row->previous, paperwidth);
3059 if ( z >= row->pos) {
3060 // set the dimensions of the row above
3061 y -= row->previous->height;
3063 refresh_row = row->previous;
3064 status = LyXText::NEED_MORE_REFRESH;
3066 BreakAgain(row->previous);
3068 // set the cursor again. Otherwise
3069 // dangling pointers are possible
3070 SetCursor(cursor.par, cursor.pos);
3071 sel_cursor = cursor;
3076 int tmpheight = row->height;
3077 LyXParagraph::size_type tmplast = RowLast(row);
3082 if (row->height == tmpheight && RowLast(row) == tmplast)
3083 status = LyXText::NEED_VERY_LITTLE_REFRESH;
3085 status = LyXText::NEED_MORE_REFRESH;
3087 // check the special right address boxes
3088 if (textclasslist.Style(parameters->textclass,
3089 par->GetLayout()).margintype
3090 == MARGIN_RIGHT_ADDRESS_BOX) {
3091 tmpcursor.par = par;
3092 tmpcursor.row = row;
3095 tmpcursor.x_fix = 0;
3096 tmpcursor.pos = pos;
3097 RedoDrawingOfParagraph(tmpcursor);
3102 // set the cursor again. Otherwise dangling pointers are possible
3103 // also set the selection
3107 SetCursorIntern(sel_cursor.par, sel_cursor.pos);
3108 sel_cursor = cursor;
3109 SetCursorIntern(sel_start_cursor.par, sel_start_cursor.pos);
3110 sel_start_cursor = cursor;
3111 SetCursorIntern(sel_end_cursor.par, sel_end_cursor.pos);
3112 sel_end_cursor = cursor;
3113 SetCursorIntern(last_sel_cursor.par, last_sel_cursor.pos);
3114 last_sel_cursor = cursor;
3117 SetCursorIntern(cursor.par, cursor.pos);
3121 // returns 0 if inset wasn't found
3122 int LyXText::UpdateInset(Inset * inset)
3124 // first check the current paragraph
3125 int pos = cursor.par->GetPositionOfInset(inset);
3127 CheckParagraph(cursor.par, pos);
3131 // check every paragraph
3133 LyXParagraph * par = FirstParagraph();
3135 // make sure the paragraph is open
3136 if (par->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE){
3137 pos = par->GetPositionOfInset(inset);
3139 CheckParagraph(par, pos);
3150 void LyXText::SetCursor(LyXParagraph * par,
3151 LyXParagraph::size_type pos, bool setfont) const
3153 LyXCursor old_cursor = cursor;
3154 SetCursorIntern(par, pos, setfont);
3155 DeleteEmptyParagraphMechanism(old_cursor);
3159 void LyXText::SetCursorIntern(LyXParagraph * par,
3160 LyXParagraph::size_type pos, bool setfont) const
3162 // correct the cursor position if impossible
3163 if (pos > par->Last()){
3164 LyXParagraph * tmppar = par->ParFromPos(pos);
3165 pos = par->PositionInParFromPos(pos);
3168 if (par->IsDummy() && par->previous &&
3169 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
3170 while (par->previous &&
3171 ((par->previous->IsDummy() && par->previous->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) ||
3172 (par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))) {
3173 par = par->previous ;
3174 if (par->IsDummy() &&
3175 par->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3176 pos += par->size() + 1;
3178 if (par->previous) {
3179 par = par->previous;
3181 pos += par->size() + 1;
3189 (cursor.pos == cursor.par->Last() || cursor.par->IsSeparator(cursor.pos)
3190 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3191 && !cursor.par->IsSeparator(cursor.pos))
3192 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3194 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3195 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3197 current_font = cursor.par->GetFontSettings(cursor.pos);
3198 real_current_font = GetFont(cursor.par, cursor.pos);
3201 /* get the cursor y position in text */
3203 Row * row = GetRow(par, pos, y);
3204 /* y is now the beginning of the cursor row */
3206 /* y is now the cursor baseline */
3209 /* now get the cursors x position */
3211 float fill_separator, fill_hfill, fill_label_hfill;
3212 PrepareToPrint(row, x, fill_separator, fill_hfill, fill_label_hfill);
3213 LyXParagraph::size_type cursor_vpos;
3214 LyXParagraph::size_type last = RowLast(row);
3215 if (row->pos > last)
3217 else if (pos > last)
3218 cursor_vpos = (row->par->getLetterDirection(last) == LYX_DIR_LEFT_TO_RIGHT)
3219 ? log2vis(last)+1 : log2vis(last);
3221 LyXDirection letter_direction =
3222 row->par->getLetterDirection(pos);
3223 LyXDirection font_direction =
3224 (real_current_font.isVisibleRightToLeft())
3225 ? LYX_DIR_RIGHT_TO_LEFT : LYX_DIR_LEFT_TO_RIGHT;
3226 if (letter_direction == font_direction
3228 || (row->par->table && row->par->IsNewline(pos-1)))
3229 cursor_vpos = (letter_direction == LYX_DIR_LEFT_TO_RIGHT)
3230 ? log2vis(pos) : log2vis(pos) + 1;
3232 cursor_vpos = (font_direction == LYX_DIR_LEFT_TO_RIGHT)
3233 ? log2vis(pos-1) + 1 : log2vis(pos - 1);
3236 /* table stuff -- begin*/
3237 if (row->par->table) {
3238 int cell = NumberOfCell(row->par, row->pos);
3240 x += row->par->table->GetBeginningOfTextInCell(cell);
3241 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3242 pos = vis2log(vpos);
3243 if (row->par->IsNewline(pos)) {
3244 x = x_old + row->par->table->WidthOfColumn(cell);
3247 x += row->par->table->GetBeginningOfTextInCell(cell);
3249 x += SingleWidth(row->par, pos);
3253 /* table stuff -- end*/
3254 LyXParagraph::size_type main_body =
3255 BeginningOfMainBody(row->par);
3256 if (main_body > 0 &&
3257 (main_body-1 > last ||
3258 !row->par->IsLineSeparator(main_body-1)))
3261 for (LyXParagraph::size_type vpos = row->pos; vpos < cursor_vpos; ++vpos) {
3262 pos = vis2log(vpos);
3263 if (main_body > 0 && pos == main_body-1) {
3264 x += fill_label_hfill +
3265 lyxfont::width(textclasslist
3266 .Style(parameters->textclass,
3267 row->par->GetLayout())
3269 GetFont(row->par, -2));
3270 if (row->par->IsLineSeparator(main_body-1))
3271 x -= SingleWidth(row->par, main_body-1);
3273 if (HfillExpansion(row, pos)) {
3274 x += SingleWidth(row->par, pos);
3275 if (pos >= main_body)
3278 x += fill_label_hfill;
3280 else if (row->par->IsSeparator(pos)) {
3283 row->next->par != row->par ||
3284 row->par->getParDirection() ==
3285 row->par->getLetterDirection(last)) {
3286 x += SingleWidth(row->par, pos);
3287 if (pos >= main_body)
3288 x += fill_separator;
3291 x += SingleWidth(row->par, pos);
3297 cursor.x_fix = cursor.x;
3302 void LyXText::SetCursorFromCoordinates(int x, long y) const
3304 LyXCursor old_cursor = cursor;
3306 /* get the row first */
3308 Row * row = GetRowNearY(y);
3310 cursor.par = row->par;
3312 int column = GetColumnNearX(row, x);
3313 cursor.pos = row->pos + column;
3315 cursor.y = y + row->baseline;
3320 (cursor.pos == cursor.par->Last()
3321 || cursor.par->IsSeparator(cursor.pos)
3322 || (cursor.pos && cursor.pos == BeginningOfMainBody(cursor.par)
3323 && !cursor.par->IsSeparator(cursor.pos))
3324 || (cursor.par->table && cursor.par->IsNewline(cursor.pos))
3326 current_font = cursor.par->GetFontSettings(cursor.pos - 1);
3327 real_current_font = GetFont(cursor.par, cursor.pos - 1);
3329 current_font = cursor.par->GetFontSettings(cursor.pos);
3330 real_current_font = GetFont(cursor.par, cursor.pos);
3332 DeleteEmptyParagraphMechanism(old_cursor);
3335 void LyXText::SetCursorFromCoordinates(LyXCursor & cur, int x, long y) const
3337 /* get the row first */
3339 Row * row = GetRowNearY(y);
3340 int column = GetColumnNearX(row, x);
3343 cur.pos = row->pos + column;
3345 cur.y = y + row->baseline;
3350 void LyXText::CursorLeft() const
3353 if (cursor.par->table) {
3354 int cell = NumberOfCell(cursor.par, cursor.pos);
3355 if (cursor.par->table->IsContRow(cell) &&
3356 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell)) < 0) {
3363 void LyXText::CursorLeftIntern() const
3365 if (cursor.pos > 0) {
3366 SetCursor(cursor.par, cursor.pos - 1);
3368 else if (cursor.par->Previous()) { // steps into the above paragraph.
3369 SetCursor(cursor.par->Previous(), cursor.par->Previous()->Last());
3374 void LyXText::CursorRight() const
3376 CursorRightIntern();
3377 if (cursor.par->table) {
3378 int cell = NumberOfCell(cursor.par, cursor.pos);
3379 if (cursor.par->table->IsContRow(cell) &&
3380 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3387 void LyXText::CursorRightIntern() const
3389 if (cursor.pos < cursor.par->Last()) {
3390 SetCursor(cursor.par, cursor.pos + 1);
3392 else if (cursor.par->Next()) {
3393 SetCursor(cursor.par->Next(), 0);
3398 void LyXText::CursorUp() const
3400 SetCursorFromCoordinates(cursor.x_fix,
3401 cursor.y - cursor.row->baseline - 1);
3402 if (cursor.par->table) {
3403 int cell = NumberOfCell(cursor.par, cursor.pos);
3404 if (cursor.par->table->IsContRow(cell) &&
3405 cursor.par->table->CellHasContRow(cursor.par->table->GetCellAbove(cell))<0) {
3412 void LyXText::CursorDown() const
3414 if (cursor.par->table &&
3415 cursor.par->table->ShouldBeVeryLastRow(NumberOfCell(cursor.par, cursor.pos)) &&
3418 SetCursorFromCoordinates(cursor.x_fix,
3419 cursor.y - cursor.row->baseline
3420 + cursor.row->height + 1);
3421 if (cursor.par->table) {
3422 int cell = NumberOfCell(cursor.par, cursor.pos);
3423 int cell_above = cursor.par->table->GetCellAbove(cell);
3424 while(cursor.par->table &&
3425 cursor.par->table->IsContRow(cell) &&
3426 (cursor.par->table->CellHasContRow(cell_above)<0)) {
3427 SetCursorFromCoordinates(cursor.x_fix,
3428 cursor.y - cursor.row->baseline
3429 + cursor.row->height + 1);
3430 if (cursor.par->table) {
3431 cell = NumberOfCell(cursor.par, cursor.pos);
3432 cell_above = cursor.par->table->GetCellAbove(cell);
3439 void LyXText::CursorUpParagraph() const
3441 if (cursor.pos > 0) {
3442 SetCursor(cursor.par, 0);
3444 else if (cursor.par->Previous()) {
3445 SetCursor(cursor.par->Previous(), 0);
3450 void LyXText::CursorDownParagraph() const
3452 if (cursor.par->Next()) {
3453 SetCursor(cursor.par->Next(), 0);
3455 SetCursor(cursor.par, cursor.par->Last());
3461 void LyXText::DeleteEmptyParagraphMechanism(LyXCursor const & old_cursor) const
3463 // Would be wrong to delete anything if we have a selection.
3464 if (selection) return;
3466 // We allow all kinds of "mumbo-jumbo" when freespacing.
3467 if (textclasslist.Style(parameters->textclass,
3468 old_cursor.par->GetLayout()).free_spacing)
3471 bool deleted = false;
3473 #ifdef FIX_DOUBLE_SPACE
3474 /* Ok I'll put some comments here about what is missing.
3475 I have fixed BackSpace (and thus Delete) to not delete
3476 double-spaces automagically. I have also changed Cut,
3477 Copy and Paste to hopefully do some sensible things.
3478 There are still some small problems that can lead to
3479 double spaces stored in the document file or space at
3480 the beginning of paragraphs. This happens if you have
3481 the cursor betwenn to spaces and then save. Or if you
3482 cut and paste and the selection have a space at the
3483 beginning and then save right after the paste. I am
3484 sure none of these are very hard to fix, but I will
3485 put out 1.1.4pre2 with FIX_DOUBLE_SPACE defined so
3486 that I can get some feedback. (Lgb)
3489 // If old_cursor.pos == 0 and old_cursor.pos(1) == LineSeparator
3490 // delete the LineSeparator.
3493 // If old_cursor.pos == 1 and old_cursor.pos(0) == LineSeparator
3494 // delete the LineSeparator.
3497 // If the pos around the old_cursor were spaces, delete one of them.
3498 if (old_cursor.par != cursor.par || old_cursor.pos != cursor.pos) { // Only if the cursor has really moved
3500 if (old_cursor.pos > 0
3501 && old_cursor.pos < old_cursor.par->Last()
3502 && old_cursor.par->IsLineSeparator(old_cursor.pos)
3503 && old_cursor.par->IsLineSeparator(old_cursor.pos - 1)) {
3504 old_cursor.par->Erase(old_cursor.pos - 1);
3505 status = LyXText::NEED_MORE_REFRESH;
3507 if (old_cursor.par == cursor.par &&
3508 cursor.pos > old_cursor.pos) {
3509 SetCursorIntern(cursor.par, cursor.pos - 1);
3516 // Do not delete empty paragraphs with keepempty set.
3517 if ((textclasslist.Style(parameters->textclass,
3518 old_cursor.par->GetLayout())).keepempty)
3521 LyXCursor tmpcursor;
3523 if (old_cursor.par != cursor.par) {
3524 if ( (old_cursor.par->Last() == 0
3525 || (old_cursor.par->Last() == 1
3526 && old_cursor.par->IsLineSeparator(0)))
3527 && old_cursor.par->FirstPhysicalPar()
3528 == old_cursor.par->LastPhysicalPar()) {
3529 // ok, we will delete anything
3531 // make sure that you do not delete any environments
3532 if ((old_cursor.par->footnoteflag != LyXParagraph::OPEN_FOOTNOTE &&
3533 !(old_cursor.row->previous
3534 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3535 && !(old_cursor.row->next
3536 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3537 || (old_cursor.par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE
3538 && ((old_cursor.row->previous
3539 && old_cursor.row->previous->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE)
3540 || (old_cursor.row->next
3541 && old_cursor.row->next->par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE))
3543 status = LyXText::NEED_MORE_REFRESH;
3546 if (old_cursor.row->previous) {
3547 refresh_row = old_cursor.row->previous;
3548 refresh_y = old_cursor.y - old_cursor.row->baseline - refresh_row->height;
3550 cursor = old_cursor; // that undo can restore the right cursor position
3551 LyXParagraph * endpar = old_cursor.par->next;
3552 if (endpar && endpar->GetDepth()) {
3553 while (endpar && endpar->GetDepth()) {
3554 endpar = endpar->LastPhysicalPar()->Next();
3557 SetUndo(Undo::DELETE,
3558 old_cursor.par->previous,
3563 RemoveRow(old_cursor.row);
3564 if (params->paragraph == old_cursor.par) {
3565 params->paragraph = params->paragraph->next;
3568 delete old_cursor.par;
3570 /* Breakagain the next par. Needed
3571 * because of the parindent that
3572 * can occur or dissappear. The
3573 * next row can change its height,
3574 * if there is another layout before */
3575 if (refresh_row->next) {
3576 BreakAgain(refresh_row->next);
3577 UpdateCounters(refresh_row);
3579 SetHeightOfRow(refresh_row);
3581 refresh_row = old_cursor.row->next;
3582 refresh_y = old_cursor.y - old_cursor.row->baseline;
3585 cursor = old_cursor; // that undo can restore the right cursor position
3586 LyXParagraph *endpar = old_cursor.par->next;
3587 if (endpar && endpar->GetDepth()) {
3588 while (endpar && endpar->GetDepth()) {
3589 endpar = endpar->LastPhysicalPar()->Next();
3592 SetUndo(Undo::DELETE,
3593 old_cursor.par->previous,
3598 RemoveRow(old_cursor.row);
3600 if (params->paragraph == old_cursor.par) {
3601 params->paragraph = params->paragraph->next;
3603 delete old_cursor.par;
3605 /* Breakagain the next par. Needed
3606 because of the parindent that can
3607 occur or dissappear.
3608 The next row can change its height,
3609 if there is another layout before
3612 BreakAgain(refresh_row);
3613 UpdateCounters(refresh_row->previous);
3619 SetCursorIntern(cursor.par, cursor.pos);
3621 SetCursor(cursor.par, cursor.pos);
3623 /* if (cursor.y > old_cursor.y)
3624 cursor.y -= old_cursor.row->height; */
3626 if (sel_cursor.par == old_cursor.par
3627 && sel_cursor.pos == sel_cursor.pos) {
3628 // correct selection
3629 sel_cursor = cursor;
3634 if (old_cursor.par->ClearParagraph()) {
3635 RedoParagraphs(old_cursor, old_cursor.par->Next());
3638 SetCursorIntern(cursor.par, cursor.pos);
3640 SetCursor(cursor.par, cursor.pos);
3642 sel_cursor = cursor;
3650 LyXParagraph * LyXText::GetParFromID(int id)
3652 LyXParagraph * result = FirstParagraph();
3653 while (result && result->id() != id)
3654 result = result->next;
3660 bool LyXText::TextUndo()
3662 // returns false if no undo possible
3663 Undo * undo = params->undostack.pop();
3668 .push(CreateUndo(undo->kind,
3669 GetParFromID(undo->number_of_before_par),
3670 GetParFromID(undo->number_of_behind_par)));
3672 return TextHandleUndo(undo);
3676 bool LyXText::TextRedo()
3678 // returns false if no redo possible
3679 Undo * undo = params->redostack.pop();
3684 .push(CreateUndo(undo->kind,
3685 GetParFromID(undo->number_of_before_par),
3686 GetParFromID(undo->number_of_behind_par)));
3688 return TextHandleUndo(undo);
3692 bool LyXText::TextHandleUndo(Undo * undo)
3694 // returns false if no undo possible
3695 bool result = false;
3697 LyXParagraph * before =
3698 GetParFromID(undo->number_of_before_par);
3699 LyXParagraph * behind =
3700 GetParFromID(undo->number_of_behind_par);
3701 LyXParagraph * tmppar;
3702 LyXParagraph * tmppar2;
3703 LyXParagraph * endpar;
3704 LyXParagraph * tmppar5;
3706 // if there's no before take the beginning
3707 // of the document for redoing
3709 SetCursorIntern(FirstParagraph(), 0);
3711 // replace the paragraphs with the undo informations
3713 LyXParagraph * tmppar3 = undo->par;
3714 undo->par = 0; // otherwise the undo destructor would delete the paragraph
3715 LyXParagraph * tmppar4 = tmppar3;
3717 while (tmppar4->next)
3718 tmppar4 = tmppar4->next;
3719 } // get last undo par
3721 // now remove the old text if there is any
3722 if (before != behind || (!behind && !before)){
3724 tmppar5 = before->next;
3726 tmppar5 = params->paragraph;
3728 while (tmppar5 && tmppar5 != behind){
3730 tmppar5 = tmppar5->next;
3731 // a memory optimization for edit: Only layout information
3732 // is stored in the undo. So restore the text informations.
3733 if (undo->kind == Undo::EDIT) {
3734 tmppar2->setContentsFromPar(tmppar);
3735 tmppar->clearContents();
3736 //tmppar2->text = tmppar->text;
3737 //tmppar->text.clear();
3738 tmppar2 = tmppar2->next;
3740 if ( currentrow && currentrow->par == tmppar )
3741 currentrow = currentrow -> previous;
3742 // Commenting out this might remove the error
3743 // reported by Purify, but it might also
3744 // introduce a memory leak. We need to
3750 // put the new stuff in the list if there is one
3753 before->next = tmppar3;
3755 params->paragraph = tmppar3;
3756 tmppar3->previous = before;
3760 params->paragraph = behind;
3763 tmppar4->next = behind;
3765 behind->previous = tmppar4;
3769 // Set the cursor for redoing
3771 SetCursorIntern(before->FirstSelfrowPar(), 0);
3772 // check wether before points to a closed float and open it if necessary
3773 if (before && before->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE
3774 && before->next && before->next->footnoteflag != LyXParagraph::NO_FOOTNOTE){
3776 while (tmppar4->previous &&
3777 tmppar4->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
3778 tmppar4 = tmppar4->previous;
3779 while (tmppar4 && tmppar4->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3780 tmppar4->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3781 tmppar4 = tmppar4->next;
3786 // open a cosed footnote at the end if necessary
3787 if (behind && behind->previous &&
3788 behind->previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
3789 behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3790 while (behind && behind->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE){
3791 behind->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
3792 behind = behind->next;
3796 // calculate the endpar for redoing the paragraphs.
3798 if (behind->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
3799 endpar = behind->LastPhysicalPar()->Next();
3801 endpar = behind->NextAfterFootnote()->LastPhysicalPar()->Next();
3806 tmppar = GetParFromID(undo->number_of_cursor_par);
3807 RedoParagraphs(cursor, endpar);
3809 SetCursorIntern(tmppar, undo->cursor_pos);
3810 UpdateCounters(cursor.row);
3820 void LyXText::FinishUndo()
3822 // makes sure the next operation will be stored
3823 undo_finished = True;
3827 void LyXText::FreezeUndo()
3829 // this is dangerous and for internal use only
3834 void LyXText::UnFreezeUndo()
3836 // this is dangerous and for internal use only
3837 undo_frozen = false;
3841 void LyXText::SetUndo(Undo::undo_kind kind, LyXParagraph const * before,
3842 LyXParagraph const * behind) const
3845 params->undostack.push(CreateUndo(kind, before, behind));
3846 params->redostack.clear();
3850 void LyXText::SetRedo(Undo::undo_kind kind, LyXParagraph const * before,
3851 LyXParagraph const * behind)
3853 params->redostack.push(CreateUndo(kind, before, behind));
3857 Undo * LyXText::CreateUndo(Undo::undo_kind kind, LyXParagraph const * before,
3858 LyXParagraph const * behind) const
3860 int before_number = -1;
3861 int behind_number = -1;
3863 before_number = before->id();
3865 behind_number = behind->id();
3866 // Undo::EDIT and Undo::FINISH are
3867 // always finished. (no overlapping there)
3868 // overlapping only with insert and delete inside one paragraph:
3869 // Nobody wants all removed character
3870 // appear one by one when undoing.
3871 // EDIT is special since only layout information, not the
3872 // contents of a paragaph are stored.
3873 if (!undo_finished && kind != Undo::EDIT &&
3874 kind != Undo::FINISH){
3875 // check wether storing is needed
3876 if (!params->undostack.empty() &&
3877 params->undostack.top()->kind == kind &&
3878 params->undostack.top()->number_of_before_par == before_number &&
3879 params->undostack.top()->number_of_behind_par == behind_number ){
3884 // create a new Undo
3885 LyXParagraph * undopar;
3886 LyXParagraph * tmppar;
3887 LyXParagraph * tmppar2;
3889 LyXParagraph * start = 0;
3890 LyXParagraph * end = 0;
3893 start = before->next;
3895 start = FirstParagraph();
3897 end = behind->previous;
3899 end = FirstParagraph();
3905 && start != end->next
3906 && (before != behind || (!before && !behind))) {
3908 tmppar2 = tmppar->Clone();
3909 tmppar2->id(tmppar->id());
3911 // a memory optimization: Just store the layout information
3913 if (kind == Undo::EDIT){
3914 //tmppar2->text.clear();
3915 tmppar2->clearContents();
3920 while (tmppar != end && tmppar->next) {
3921 tmppar = tmppar->next;
3922 tmppar2->next = tmppar->Clone();
3923 tmppar2->next->id(tmppar->id());
3924 // a memory optimization: Just store the layout
3925 // information when only edit
3926 if (kind == Undo::EDIT){
3927 //tmppar2->next->text.clear();
3928 tmppar2->clearContents();
3930 tmppar2->next->previous = tmppar2;
3931 tmppar2 = tmppar2->next;
3935 undopar = 0; // nothing to replace (undo of delete maybe)
3937 int cursor_par = cursor.par->ParFromPos(cursor.pos)->id();
3938 int cursor_pos = cursor.par->PositionInParFromPos(cursor.pos);
3940 Undo * undo = new Undo(kind,
3941 before_number, behind_number,
3942 cursor_par, cursor_pos,
3945 undo_finished = false;
3950 void LyXText::SetCursorParUndo()
3952 SetUndo(Undo::FINISH,
3953 cursor.par->ParFromPos(cursor.pos)->previous,
3954 cursor.par->ParFromPos(cursor.pos)->next);
3958 void LyXText::RemoveTableRow(LyXCursor * cur) const
3964 // move to the previous row
3965 int cell_act = NumberOfCell(cur->par, cur->pos);
3968 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3971 !cur->par->table->IsFirstCell(cell_act)) {
3973 while (cur->pos && !cur->par->IsNewline(cur->pos - 1))
3978 // now we have to pay attention if the actual table is the
3979 // main row of TableContRows and if yes to delete all of them
3984 // delete up to the next row
3985 while (cur->pos < cur->par->Last() &&
3987 || !cur->par->table->IsFirstCell(cell_act))) {
3988 while (cur->pos < cur->par->Last() &&
3989 !cur->par->IsNewline(cur->pos))
3990 cur->par->Erase(cur->pos);
3993 if (cur->pos < cur->par->Last())
3994 cur->par->Erase(cur->pos);
3996 if (cur->pos && cur->pos == cur->par->Last()) {
3998 cur->par->Erase(cur->pos); // no newline at very end!
4000 } while (((cell + 1) < cur->par->table->GetNumberOfCells()) &&
4001 !cur->par->table->IsContRow(cell_org) &&
4002 cur->par->table->IsContRow(cell));
4003 cur->par->table->DeleteRow(cell_org);
4008 bool LyXText::IsEmptyTableCell() const
4010 LyXParagraph::size_type pos = cursor.pos - 1;
4011 while (pos >= 0 && pos < cursor.par->Last()
4012 && !cursor.par->IsNewline(pos))
4014 return cursor.par->IsNewline(pos + 1);
4018 void LyXText::toggleAppendix(){
4019 LyXParagraph * par = cursor.par->FirstPhysicalPar();
4020 bool start = !par->start_of_appendix;
4022 // ensure that we have only one start_of_appendix in this document
4023 LyXParagraph * tmp = FirstParagraph();
4024 for (; tmp; tmp = tmp->next)
4025 tmp->start_of_appendix = 0;
4026 par->start_of_appendix = start;
4028 // we can set the refreshing parameters now
4029 status = LyXText::NEED_MORE_REFRESH;
4031 refresh_row = 0; // not needed for full update
4033 SetCursor(cursor.par, cursor.pos);