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 * ====================================================== */
14 #pragma implementation "lyxparagraph.h"
21 #include "lyxparagraph.h"
22 #include "support/textutils.h"
25 #include "tex-strings.h"
27 #include "bufferparams.h"
28 #include "support/FileInfo.h"
29 #include "support/LAssert.h"
31 #include "LaTeXFeatures.h"
32 #include "insets/insetinclude.h"
33 #include "insets/insetbib.h"
34 #include "insets/insettext.h"
35 #include "support/filetools.h"
36 #include "lyx_gui_misc.h"
38 #include "support/lyxmanip.h"
39 #include "BufferView.h"
41 #include "ParameterStruct.h"
47 using std::lower_bound;
48 using std::upper_bound;
51 int tex_code_break_column = 72; // needs non-zero initialization. set later.
52 // this is a bad idea, but how can LyXParagraph find its buffer to get
53 // parameters? (JMarc)
55 extern string bibitemWidest(Buffer const *);
57 // this is a minibuffer
58 static char minibuffer_char;
59 static LyXFont minibuffer_font;
60 static Inset * minibuffer_inset;
63 extern BufferView * current_view;
65 // Initialization of the counter for the paragraph id's,
66 // declared in lyxparagraph.h
67 unsigned int LyXParagraph::paragraph_id = 0;
69 // Initialize static member.
70 ShareContainer<LyXFont> LyXParagraph::FontTable::container;
73 LyXParagraph::LyXParagraph()
75 text.reserve(500); // is this number too big?
76 for (int i = 0; i < 10; ++i) setCounter(i , 0);
82 footnoteflag = LyXParagraph::NO_FOOTNOTE;
83 footnotekind = LyXParagraph::FOOTNOTE; // should not be needed
88 bibkey = 0; // ale970302
93 // This konstruktor inserts the new paragraph in a list.
94 LyXParagraph::LyXParagraph(LyXParagraph * par)
99 for (int i = 0; i < 10; ++i) setCounter(i, 0);
102 // double linked list begin
105 next->previous = this;
107 previous->next = this;
110 footnoteflag = LyXParagraph::NO_FOOTNOTE;
111 footnotekind = LyXParagraph::FOOTNOTE;
114 id_ = paragraph_id++;
116 bibkey = 0; // ale970302
122 void LyXParagraph::writeFile(Buffer const * buf, ostream & os,
123 BufferParams const & bparams,
124 char footflag, char dth) const
128 footnoteflag != LyXParagraph::NO_FOOTNOTE ||
130 || previous->footnoteflag == LyXParagraph::NO_FOOTNOTE
135 // The beginning or the end of a footnote environment?
136 if (footflag != footnoteflag) {
137 footflag = footnoteflag;
139 os << "\n\\begin_float "
140 << string_footnotekinds[footnotekind]
143 os << "\n\\end_float ";
147 // The beginning or end of a deeper (i.e. nested) area?
148 if (dth != params.depth()) {
149 if (params.depth() > dth) {
150 while (params.depth() > dth) {
151 os << "\n\\begin_deeper ";
155 while (params.depth() < dth) {
156 os << "\n\\end_deeper ";
162 // First write the layout
164 << textclasslist.NameOfLayout(bparams.textclass, layout)
167 // Maybe some vertical spaces.
168 if (params.spaceTop().kind() != VSpace::NONE)
169 os << "\\added_space_top "
170 << params.spaceTop().asLyXCommand() << " ";
171 if (params.spaceBottom().kind() != VSpace::NONE)
172 os << "\\added_space_bottom "
173 << params.spaceBottom().asLyXCommand() << " ";
175 // Maybe the paragraph has special spacing
176 params.spacing().writeFile(os, true);
178 // The labelwidth string used in lists.
179 if (!params.labelWidthString().empty())
180 os << "\\labelwidthstring "
181 << params.labelWidthString() << '\n';
183 // Lines above or below?
184 if (params.lineTop())
186 if (params.lineBottom())
187 os << "\\line_bottom ";
189 // Pagebreaks above or below?
190 if (params.pagebreakTop())
191 os << "\\pagebreak_top ";
192 if (params.pagebreakBottom())
193 os << "\\pagebreak_bottom ";
195 // Start of appendix?
196 if (params.startOfAppendix())
197 os << "\\start_of_appendix ";
200 if (params.noindent())
204 if (params.align() != LYX_ALIGN_LAYOUT) {
206 switch (params.align()) {
207 case LYX_ALIGN_LEFT: h = 1; break;
208 case LYX_ALIGN_RIGHT: h = 2; break;
209 case LYX_ALIGN_CENTER: h = 3; break;
210 default: h = 0; break;
212 os << "\\align " << string_align[h] << " ";
214 if (params.pextraType() != PEXTRA_NONE) {
215 os << "\\pextra_type " << params.pextraType();
216 if (params.pextraType() == PEXTRA_MINIPAGE) {
217 os << " \\pextra_alignment "
218 << params.pextraAlignment();
219 if (params.pextraHfill())
220 os << " \\pextra_hfill "
221 << params.pextraHfill();
222 if (params.pextraStartMinipage())
223 os << " \\pextra_start_minipage "
224 << params.pextraStartMinipage();
226 if (!params.pextraWidth().empty()) {
227 os << " \\pextra_width "
228 << VSpace(params.pextraWidth()).asLyXCommand();
229 } else if (!params.pextraWidthp().empty()) {
230 os << " \\pextra_widthp "
231 << params.pextraWidthp();
237 // Dummy layout. This means that a footnote ended.
238 os << "\n\\end_float ";
239 footflag = LyXParagraph::NO_FOOTNOTE;
245 bibkey->Write(buf, os);
247 LyXFont font1(LyXFont::ALL_INHERIT, bparams.language);
250 for (size_type i = 0; i < size(); ++i) {
256 // Write font changes
257 LyXFont font2 = GetFontSettings(bparams, i);
258 if (font2 != font1) {
259 font2.lyxWriteChanges(font1, os);
264 value_type const c = GetChar(i);
268 Inset const * inset = GetInset(i);
270 if (inset->DirectWrite()) {
271 // international char, let it write
272 // code directly so it's shorter in
274 inset->Write(buf, os);
276 os << "\n\\begin_inset ";
277 inset->Write(buf, os);
278 os << "\n\\end_inset \n\n";
284 os << "\n\\newline \n";
288 os << "\n\\hfill \n";
292 os << "\n\\backslash \n";
296 if (i + 1 < size() && GetChar(i + 1) == ' ') {
303 if ((column > 70 && c == ' ')
308 // this check is to amend a bug. LyX sometimes
309 // inserts '\0' this could cause problems.
313 lyxerr << "ERROR (LyXParagraph::writeFile):"
314 " NULL char in structure." << endl;
320 // now write the next paragraph
322 next->writeFile(buf, os, bparams, footflag, dth);
326 void LyXParagraph::validate(LaTeXFeatures & features) const
328 BufferParams const & bparams = features.bufferParams();
331 // this will be useful later
332 LyXLayout const & layout =
333 textclasslist.Style(bparams.textclass,
338 if (params.lineTop() || params.lineBottom())
339 features.lyxline = true;
340 if (!params.spacing().isDefault())
341 features.setspace = true;
344 features.layout[GetLayout()] = true;
347 Language const * doc_language = bparams.language;
349 for (FontList::const_iterator cit = fontlist.begin();
350 cit != fontlist.end(); ++cit) {
351 if ((*cit).font().noun() == LyXFont::ON) {
352 lyxerr[Debug::LATEX] << "font.noun: "
353 << (*cit).font().noun()
355 features.noun = true;
356 lyxerr[Debug::LATEX] << "Noun enabled. Font: "
357 << (*cit).font().stateText(0)
360 switch ((*cit).font().color()) {
362 case LColor::inherit:
366 features.color = true;
367 lyxerr[Debug::LATEX] << "Color enabled. Font: "
368 << (*cit).font().stateText(0)
372 Language const * language = (*cit).font().language();
373 if (language->babel() != doc_language->babel()) {
374 features.UsedLanguages.insert(language);
375 lyxerr[Debug::LATEX] << "Found language "
376 << language->babel() << endl;
381 for (InsetList::const_iterator cit = insetlist.begin();
382 cit != insetlist.end(); ++cit) {
384 (*cit).inset->Validate(features);
387 if (params.pextraType() == PEXTRA_INDENT)
388 features.LyXParagraphIndent = true;
389 if (params.pextraType() == PEXTRA_FLOATFLT)
390 features.floatflt = true;
392 if (layout.needprotect
393 && next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE)
394 features.NeedLyXFootnoteCode = true;
396 if (bparams.paragraph_separation == BufferParams::PARSEP_INDENT
397 && params.pextraType() == LyXParagraph::PEXTRA_MINIPAGE)
398 features.NeedLyXMinipageIndent = true;
400 if (footnoteflag != NO_FOOTNOTE && footnotekind == ALGORITHM)
401 features.algorithm = true;
406 // First few functions needed for cut and paste and paragraph breaking.
407 void LyXParagraph::CopyIntoMinibuffer(Buffer const & buffer,
408 LyXParagraph::size_type pos) const
410 BufferParams bparams = buffer.params;
412 minibuffer_char = GetChar(pos);
413 minibuffer_font = GetFontSettings(bparams, pos);
414 minibuffer_inset = 0;
415 if (minibuffer_char == LyXParagraph::META_INSET) {
417 minibuffer_inset = GetInset(pos)->Clone(buffer);
419 minibuffer_inset = 0;
420 minibuffer_char = ' ';
421 // This reflects what GetInset() does (ARRae)
427 void LyXParagraph::CutIntoMinibuffer(BufferParams const & bparams,
428 LyXParagraph::size_type pos)
430 minibuffer_char = GetChar(pos);
431 minibuffer_font = GetFontSettings(bparams, pos);
432 minibuffer_inset = 0;
433 if (minibuffer_char == LyXParagraph::META_INSET) {
435 minibuffer_inset = GetInset(pos);
436 // This is a little hack since I want exactly
437 // the inset, not just a clone. Otherwise
438 // the inset would be deleted when calling Erase(pos)
440 InsetTable search_elem(pos, 0);
441 InsetList::iterator it =
442 lower_bound(insetlist.begin(),
444 search_elem, matchIT());
445 if (it != insetlist.end() && (*it).pos == pos)
448 minibuffer_inset = 0;
449 minibuffer_char = ' ';
450 // This reflects what GetInset() does (ARRae)
455 // Erase(pos); now the caller is responsible for that.
459 bool LyXParagraph::InsertFromMinibuffer(LyXParagraph::size_type pos)
461 if ((minibuffer_char == LyXParagraph::META_INSET) &&
462 !InsertInsetAllowed(minibuffer_inset))
464 if (minibuffer_char == LyXParagraph::META_INSET)
465 InsertInset(pos, minibuffer_inset, minibuffer_font);
467 InsertChar(pos, minibuffer_char, minibuffer_font);
475 void LyXParagraph::Clear()
484 // the destructor removes the new paragraph from the list
485 LyXParagraph::~LyXParagraph()
488 previous->next = next;
490 next->previous = previous;
492 for (InsetList::iterator it = insetlist.begin();
493 it != insetlist.end(); ++it) {
500 //lyxerr << "LyXParagraph::paragraph_id = "
501 // << LyXParagraph::paragraph_id << endl;
505 void LyXParagraph::Erase(LyXParagraph::size_type pos)
508 // > because last is the next unused position, and you can
509 // use it if you want
511 if (next && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
512 NextAfterFootnote()->Erase(pos - text.size() - 1);
514 lyxerr.debug() << "ERROR (LyXParagraph::Erase): "
515 "position does not exist." << endl;
519 Assert(pos < size());
522 if (pos < size()) { // last is free for insertation, but should be empty
524 // if it is an inset, delete the inset entry
525 if (text[pos] == LyXParagraph::META_INSET) {
527 InsetTable search_inset(pos, 0);
528 InsetList::iterator it =
529 lower_bound(insetlist.begin(),
531 search_inset, matchIT());
532 if (it != insetlist.end() && (*it).pos == pos) {
538 text.erase(text.begin() + pos);
540 // Erase entries in the tables.
541 FontTable search_font(pos, LyXFont());
543 FontList::iterator it =
544 lower_bound(fontlist.begin(),
546 search_font, matchFT());
547 if (it != fontlist.end() && (*it).pos() == pos &&
549 (it != fontlist.begin() && (*(it - 1)).pos() == pos - 1))) {
550 // If it is a multi-character font
551 // entry, we just make it smaller
552 // (see update below), otherwise we
554 unsigned int const i = it - fontlist.begin();
555 fontlist.erase(fontlist.begin() + i);
556 it = fontlist.begin() + i;
557 if (i > 0 && i < fontlist.size() &&
558 fontlist[i - 1].font() == fontlist[i].font()) {
559 fontlist.erase(fontlist.begin() + i - 1);
560 it = fontlist.begin() + i - 1;
564 // Update all other entries.
565 FontList::iterator fend = fontlist.end();
566 for (; it != fend; ++it)
567 (*it).pos((*it).pos() - 1);
569 // Update the inset table.
570 InsetTable search_inset(pos, 0);
571 InsetList::iterator lend = insetlist.end();
572 for (InsetList::iterator it =
573 upper_bound(insetlist.begin(),
575 search_inset, matchIT());
580 lyxerr << "ERROR (LyXParagraph::Erase): "
581 "can't erase non-existant char." << endl;
587 void LyXParagraph::InsertChar(LyXParagraph::size_type pos,
588 LyXParagraph::value_type c)
590 LyXFont const f(LyXFont::ALL_INHERIT);
591 InsertChar(pos, c, f);
595 void LyXParagraph::InsertChar(LyXParagraph::size_type pos,
596 LyXParagraph::value_type c,
597 LyXFont const & font)
600 // > because last is the next unused position, and you can
601 // use it if you want
604 && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
605 NextAfterFootnote()->InsertChar(pos - text.size() - 1,
608 lyxerr.debug() << "ERROR (LyXParagraph::InsertChar): "
609 "position does not exist." << endl;
613 Assert(pos <= size());
615 text.insert(text.begin() + pos, c);
617 // Update the font table.
618 FontTable search_font(pos, LyXFont());
619 for (FontList::iterator it = lower_bound(fontlist.begin(),
621 search_font, matchFT());
622 it != fontlist.end(); ++it)
623 (*it).pos((*it).pos() + 1);
625 // Update the inset table.
626 InsetTable search_inset(pos, 0);
627 for (InsetList::iterator it = lower_bound(insetlist.begin(),
629 search_inset, matchIT());
630 it != insetlist.end(); ++it)
637 void LyXParagraph::InsertInset(LyXParagraph::size_type pos,
640 LyXFont const f(LyXFont::ALL_INHERIT);
641 InsertInset(pos, inset, f);
645 void LyXParagraph::InsertInset(LyXParagraph::size_type pos,
646 Inset * inset, LyXFont const & font)
651 // > because last is the next unused position, and you can
652 // use it if you want
655 && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
657 ->InsertInset(pos - text.size() - 1,
660 lyxerr << "ERROR (LyXParagraph::InsertInset): "
661 "position does not exist: " << pos << endl;
665 Assert(pos <= size());
668 InsertChar(pos, META_INSET, font);
669 Assert(text[pos] == META_INSET);
671 // Add a new entry in the inset table.
672 InsetTable search_inset(pos, 0);
673 InsetList::iterator it = lower_bound(insetlist.begin(),
675 search_inset, matchIT());
676 if (it != insetlist.end() && (*it).pos == pos)
677 lyxerr << "ERROR (LyXParagraph::InsertInset): "
678 "there is an inset in position: " << pos << endl;
680 insetlist.insert(it, InsetTable(pos, inset));
682 inset->setOwner(inset_owner);
686 bool LyXParagraph::InsertInsetAllowed(Inset * inset)
688 //lyxerr << "LyXParagraph::InsertInsetAllowed" << endl;
691 return inset_owner->InsertInsetAllowed(inset);
696 Inset * LyXParagraph::GetInset(LyXParagraph::size_type pos)
701 && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
702 return NextAfterFootnote()
703 ->GetInset(pos - text.size() - 1);
705 lyxerr << "ERROR (LyXParagraph::GetInset): "
706 "position does not exist: "
712 Assert(pos < size());
715 InsetTable search_inset(pos, 0);
716 InsetList::iterator it = lower_bound(insetlist.begin(),
718 search_inset, matchIT());
719 if (it != insetlist.end() && (*it).pos == pos)
722 lyxerr << "ERROR (LyXParagraph::GetInset): "
723 "Inset does not exist: " << pos << endl;
726 // text[pos] = ' '; // WHY!!! does this set the pos to ' '????
727 // Did this commenting out introduce a bug? So far I have not
728 // see any, please enlighten me. (Lgb)
729 // My guess is that since the inset does not exist, we might
730 // as well replace it with a space to prevent craches. (Asger)
735 Inset const * LyXParagraph::GetInset(LyXParagraph::size_type pos) const
740 && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
741 return NextAfterFootnote()
742 ->GetInset(pos - text.size() - 1);
744 lyxerr << "ERROR (LyXParagraph::GetInset): "
745 "position does not exist: "
751 Assert(pos < size());
754 InsetTable search_inset(pos, 0);
755 InsetList::const_iterator cit = lower_bound(insetlist.begin(),
757 search_inset, matchIT());
758 if (cit != insetlist.end() && (*cit).pos == pos)
761 lyxerr << "ERROR (LyXParagraph::GetInset): "
762 "Inset does not exist: " << pos << endl;
764 //text[pos] = ' '; // WHY!!! does this set the pos to ' '????
765 // Did this commenting out introduce a bug? So far I have not
766 // see any, please enlighten me. (Lgb)
767 // My guess is that since the inset does not exist, we might
768 // as well replace it with a space to prevent craches. (Asger)
773 // Gets uninstantiated font setting at position.
774 // Optimized after profiling. (Asger)
775 LyXFont const LyXParagraph::GetFontSettings(BufferParams const & bparams,
776 LyXParagraph::size_type pos) const
779 Assert(pos <= size());
784 FontTable search_font(pos, LyXFont());
785 FontList::const_iterator cit = lower_bound(fontlist.begin(),
787 search_font, matchFT());
788 if (cit != fontlist.end())
789 return (*cit).font();
794 // > because last is the next unused position, and you can
795 // use it if you want
796 else if (pos > size()) {
798 && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
799 return NextAfterFootnote()
800 ->GetFontSettings(bparams,
801 pos - text.size() - 1);
803 // Why is it an error to ask for the font of a
804 // position that does not exist? Would it be
805 // enough for this to be enabled on debug?
806 // We want strict error checking, but it's ok to only
807 // have it when debugging. (Asger)
808 lyxerr << "ERROR (LyXParagraph::GetFontSettings): "
809 "position does not exist. "
810 << pos << " (" << static_cast<int>(pos)
812 } else if (pos > 0) {
813 return GetFontSettings(bparams, pos - 1);
816 if (pos == size() && size())
817 return GetFontSettings(bparams, pos - 1);
821 return LyXFont(LyXFont::ALL_INHERIT, getParLanguage(bparams));
823 //return LyXFont(LyXFont::ALL_INHERIT);
827 // Gets uninstantiated font setting at position 0
828 LyXFont const LyXParagraph::GetFirstFontSettings() const
831 if (!fontlist.empty())
832 return fontlist[0].font();
836 else if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE)
837 return NextAfterFootnote()->GetFirstFontSettings();
839 return LyXFont(LyXFont::ALL_INHERIT);
843 // Gets the fully instantiated font at a given position in a paragraph
844 // This is basically the same function as LyXText::GetFont() in text2.C.
845 // The difference is that this one is used for generating the LaTeX file,
846 // and thus cosmetic "improvements" are disallowed: This has to deliver
847 // the true picture of the buffer. (Asger)
848 // If position is -1, we get the layout font of the paragraph.
849 // If position is -2, we get the font of the manual label of the paragraph.
850 LyXFont const LyXParagraph::getFont(BufferParams const & bparams,
851 LyXParagraph::size_type pos) const
854 LyXLayout const & layout =
855 textclasslist.Style(bparams.textclass,
857 LyXParagraph::size_type main_body = 0;
858 if (layout.labeltype == LABEL_MANUAL)
859 main_body = BeginningOfMainBody();
864 layoutfont = layout.labelfont;
866 layoutfont = layout.font;
867 tmpfont = GetFontSettings(bparams, pos);
868 tmpfont.realize(layoutfont);
870 // process layoutfont for pos == -1 and labelfont for pos < -1
872 tmpfont = layout.font;
874 tmpfont = layout.labelfont;
875 tmpfont.setLanguage(getParLanguage(bparams));
878 // check for environment font information
879 char par_depth = GetDepth();
880 LyXParagraph const * par = this;
881 while (par && par_depth && !tmpfont.resolved()) {
882 par = par->DepthHook(par_depth - 1);
884 tmpfont.realize(textclasslist.
885 Style(bparams.textclass,
886 par->GetLayout()).font);
887 par_depth = par->GetDepth();
891 tmpfont.realize(textclasslist
892 .TextClass(bparams.textclass)
898 /// Returns the height of the highest font in range
900 LyXParagraph::HighestFontInRange(LyXParagraph::size_type startpos,
901 LyXParagraph::size_type endpos) const
903 LyXFont::FONT_SIZE maxsize = LyXFont::SIZE_TINY;
904 if (fontlist.empty())
907 FontTable end_search(endpos, LyXFont());
908 FontList::const_iterator end_it = lower_bound(fontlist.begin(),
910 end_search, matchFT());
911 if (end_it != fontlist.end())
914 FontTable start_search(startpos, LyXFont());
915 for (FontList::const_iterator cit =
916 lower_bound(fontlist.begin(),
918 start_search, matchFT());
919 cit != end_it; ++cit) {
920 LyXFont::FONT_SIZE size = (*cit).font().size();
921 if (size > maxsize && size <= LyXFont::SIZE_HUGER)
928 LyXParagraph::value_type
929 LyXParagraph::GetChar(LyXParagraph::size_type pos) const
934 Assert(pos <= size());
935 if (!size() || pos == size()) return '\0';
946 // > because last is the next unused position, and you can
947 // use it if you want
948 else if (pos > size()) {
949 if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE)
950 return NextAfterFootnote()
951 ->GetChar(pos - text.size() - 1);
954 lyxerr << "ERROR (LyXParagraph::GetChar const): "
955 "position does not exist."
956 << pos << " (" << static_cast<int>(pos)
962 // We should have a footnote environment.
963 if (!next || next->footnoteflag == LyXParagraph::NO_FOOTNOTE) {
964 // Notice that LyX does request the
965 // last char from time to time. (Asger)
966 //lyxerr << "ERROR (LyXParagraph::GetChar): "
967 // "expected footnote." << endl;
970 switch (next->footnotekind) {
971 case LyXParagraph::FOOTNOTE:
972 return LyXParagraph::META_FOOTNOTE;
973 case LyXParagraph::MARGIN:
974 return LyXParagraph::META_MARGIN;
975 case LyXParagraph::FIG:
976 case LyXParagraph::WIDE_FIG:
977 return LyXParagraph::META_FIG;
978 case LyXParagraph::TAB:
979 case LyXParagraph::WIDE_TAB:
980 return LyXParagraph::META_TAB;
981 case LyXParagraph::ALGORITHM:
982 return LyXParagraph::META_ALGORITHM;
984 return '\0'; // to shut up gcc
990 LyXParagraph::value_type
991 LyXParagraph::GetUChar(BufferParams const & bparams,
992 LyXParagraph::size_type pos) const
994 value_type c = GetChar(pos);
995 if (!lyxrc.rtl_support)
1025 if (uc != c && GetFontSettings(bparams, pos).isRightToLeft())
1031 // return an string of the current word, and the end of the word in lastpos.
1032 string const LyXParagraph::GetWord(LyXParagraph::size_type & lastpos) const
1034 Assert(lastpos >= 0);
1036 // the current word is defined as starting at the first character
1037 // from the immediate left of lastpospos which meets the definition
1038 // of IsLetter(), continuing to the last character to the right
1039 // of this meeting IsLetter.
1045 // move back until we have a letter
1047 //there's no real reason to have firstpos & lastpos as
1048 //separate variables as this is written, but maybe someon
1049 // will want to return firstpos in the future.
1051 //since someone might have typed a punctuation first
1052 int firstpos = lastpos;
1054 while ((firstpos >= 0) && !IsLetter(firstpos))
1057 // now find the beginning by looking for a nonletter
1059 while ((firstpos>= 0) && IsLetter(firstpos))
1062 // the above is now pointing to the preceeding non-letter
1066 // so copy characters into theword until we get a nonletter
1067 // note that this can easily exceed lastpos, wich means
1068 // that if used in the middle of a word, the whole word
1071 while (IsLetter(lastpos)) theword += GetChar(lastpos++);
1079 #warning Remember to get rid of this one. (Lgb)
1081 LyXParagraph::size_type LyXParagraph::Last() const
1084 if (next && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1085 return text.size() + NextAfterFootnote()->Last() + 1;
1086 // the 1 is the symbol
1095 LyXParagraph * LyXParagraph::ParFromPos(LyXParagraph::size_type pos)
1097 // > because last is the next unused position, and you can
1098 // use it if you want
1101 && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1102 return NextAfterFootnote()
1103 ->ParFromPos(pos - text.size() - 1);
1105 lyxerr << "ERROR (LyXParagraph::ParFromPos): "
1106 "position does not exist." << endl;
1115 int LyXParagraph::PositionInParFromPos(LyXParagraph::size_type pos) const
1117 // > because last is the next unused position, and you can
1118 // use it if you want
1121 && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1122 return NextAfterFootnote()
1123 ->PositionInParFromPos(pos - text.size() - 1);
1126 "ERROR (LyXParagraph::PositionInParFromPos): "
1127 "position does not exist." << endl;
1136 void LyXParagraph::SetFont(LyXParagraph::size_type pos,
1137 LyXFont const & font)
1140 // > because last is the next unused position, and you can
1141 // use it if you want
1144 next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1145 NextAfterFootnote()->SetFont(pos - text.size() - 1,
1148 lyxerr << "ERROR (LyXParagraph::SetFont): "
1149 "position does not exist." << endl;
1154 Assert(pos <= size());
1157 // First, reduce font against layout/label font
1158 // Update: The SetCharFont() routine in text2.C already
1159 // reduces font, so we don't need to do that here. (Asger)
1160 // No need to simplify this because it will disappear
1161 // in a new kernel. (Asger)
1162 // Next search font table
1164 FontTable search_font(pos, LyXFont());
1165 FontList::iterator it = lower_bound(fontlist.begin(),
1167 search_font, matchFT());
1168 unsigned int i = it - fontlist.begin();
1169 bool notfound = it == fontlist.end();
1171 if (!notfound && fontlist[i].font() == font)
1174 bool begin = pos == 0 || notfound ||
1175 (i > 0 && fontlist[i-1].pos() == pos - 1);
1176 // Is position pos is a beginning of a font block?
1177 bool end = !notfound && fontlist[i].pos() == pos;
1178 // Is position pos is the end of a font block?
1179 if (begin && end) { // A single char block
1180 if (i + 1 < fontlist.size() &&
1181 fontlist[i + 1].font() == font) {
1182 // Merge the singleton block with the next block
1183 fontlist.erase(fontlist.begin() + i);
1184 if (i > 0 && fontlist[i - 1].font() == font)
1185 fontlist.erase(fontlist.begin() + i-1);
1186 } else if (i > 0 && fontlist[i - 1].font() == font) {
1187 // Merge the singleton block with the previous block
1188 fontlist[i - 1].pos(pos);
1189 fontlist.erase(fontlist.begin() + i);
1191 fontlist[i].font(font);
1193 if (i > 0 && fontlist[i - 1].font() == font)
1194 fontlist[i - 1].pos(pos);
1196 fontlist.insert(fontlist.begin() + i,
1197 FontTable(pos, font));
1199 fontlist[i].pos(pos - 1);
1200 if (!(i + 1 < fontlist.size() &&
1201 fontlist[i + 1].font() == font))
1202 fontlist.insert(fontlist.begin() + i + 1,
1203 FontTable(pos, font));
1204 } else { // The general case. The block is splitted into 3 blocks
1205 fontlist.insert(fontlist.begin() + i,
1206 FontTable(pos - 1, fontlist[i].font()));
1207 fontlist.insert(fontlist.begin() + i + 1,
1208 FontTable(pos, font));
1213 // This function is able to hide closed footnotes.
1214 LyXParagraph * LyXParagraph::Next()
1217 if (next && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1218 LyXParagraph * tmp = next;
1220 && tmp->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1222 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1223 return tmp->Next(); /* there can be more than one
1224 footnote in a logical
1227 return next; // This should never happen!
1235 LyXParagraph * LyXParagraph::NextAfterFootnote()
1237 if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1238 LyXParagraph * tmp = next;
1239 while (tmp && tmp->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1241 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1242 return tmp; /* there can be more than one footnote
1243 in a logical paragraph */
1245 return next; // This should never happen!
1253 LyXParagraph const * LyXParagraph::NextAfterFootnote() const
1255 if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1256 LyXParagraph * tmp = next;
1257 while (tmp && tmp->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1259 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1260 return tmp; /* there can be more than one footnote
1261 in a logical paragraph */
1263 return next; // This should never happen!
1271 LyXParagraph * LyXParagraph::PreviousBeforeFootnote()
1274 if (previous && previous->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1276 while (tmp && tmp->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1277 tmp = tmp->previous;
1278 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1279 return tmp; /* there can be more than one footnote
1280 in a logical paragraph */
1282 return previous; // This should never happen!
1290 LyXParagraph * LyXParagraph::LastPhysicalPar()
1292 if (footnoteflag != LyXParagraph::NO_FOOTNOTE)
1295 LyXParagraph * tmp = this;
1297 && tmp->next->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1298 tmp = tmp->NextAfterFootnote();
1306 LyXParagraph const * LyXParagraph::LastPhysicalPar() const
1308 if (footnoteflag != LyXParagraph::NO_FOOTNOTE)
1311 LyXParagraph const * tmp = this;
1313 && tmp->next->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1314 tmp = tmp->NextAfterFootnote();
1322 LyXParagraph * LyXParagraph::FirstPhysicalPar()
1326 LyXParagraph * tmppar = this;
1330 || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE))
1331 tmppar = tmppar->previous;
1342 LyXParagraph const * LyXParagraph::FirstPhysicalPar() const
1346 LyXParagraph const * tmppar = this;
1350 || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE))
1351 tmppar = tmppar->previous;
1361 // This function is able to hide closed footnotes.
1362 LyXParagraph * LyXParagraph::Previous()
1365 LyXParagraph * tmp = previous;
1370 && tmp->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1371 tmp = tmp->previous;
1373 && tmp->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1374 tmp = tmp->previous;
1375 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1376 return tmp->next->Previous();
1386 // This function is able to hide closed footnotes.
1387 LyXParagraph const * LyXParagraph::Previous() const
1390 LyXParagraph * tmp = previous;
1394 && tmp->previous->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1395 tmp = tmp->previous;
1397 && tmp->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1398 tmp = tmp->previous;
1399 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1400 return tmp->next->Previous();
1410 void LyXParagraph::BreakParagraph(BufferParams const & bparams,
1411 LyXParagraph::size_type pos,
1416 // create a new paragraph
1419 size_type pos_first;
1420 LyXParagraph * par = ParFromPos(pos);
1421 LyXParagraph * firstpar = FirstPhysicalPar();
1423 LyXParagraph * tmp = new LyXParagraph(par);
1425 //LyXParagraph * par = this;
1426 //LyXParagraph * firstpar = this;
1427 LyXParagraph * tmp = new LyXParagraph(this);
1431 tmp->footnoteflag = footnoteflag;
1432 tmp->footnotekind = footnotekind;
1434 // this is an idea for a more userfriendly layout handling, I will
1435 // see what the users say
1438 // layout stays the same with latex-environments
1440 tmp->SetOnlyLayout(bparams, firstpar->layout);
1441 tmp->SetLabelWidthString(firstpar->params.labelWidthString());
1444 // layout stays the same with latex-environments
1446 tmp->SetOnlyLayout(bparams, layout);
1447 tmp->SetLabelWidthString(params.labelWidthString());
1451 if (Last() > pos || !Last() || flag == 2) {
1452 tmp->SetOnlyLayout(bparams, firstpar->layout);
1453 tmp->params.align(firstpar->params.align());
1454 tmp->SetLabelWidthString(firstpar->params.labelWidthString());
1456 tmp->params.lineBottom(firstpar->params.lineBottom());
1457 firstpar->params.lineBottom(false);
1458 tmp->params.pagebreakBottom(firstpar->params.pagebreakBottom());
1459 firstpar->params.pagebreakBottom(false);
1460 tmp->params.spaceBottom(firstpar->params.spaceBottom());
1461 firstpar->params.spaceBottom(VSpace(VSpace::NONE));
1463 tmp->params.depth(firstpar->params.depth());
1464 tmp->params.noindent(firstpar->params.noindent());
1466 if (Last() > pos || !Last() || flag == 2) {
1467 tmp->SetOnlyLayout(bparams, layout);
1468 tmp->params.align(params.align());
1469 tmp->SetLabelWidthString(params.labelWidthString());
1471 tmp->params.lineBottom(params.lineBottom());
1472 params.lineBottom(false);
1473 tmp->params.pagebreakBottom(params.pagebreakBottom());
1474 params.pagebreakBottom(false);
1475 tmp->params.spaceBottom(params.spaceBottom());
1476 params.spaceBottom(VSpace(VSpace::NONE));
1478 tmp->params.depth(params.depth());
1479 tmp->params.noindent(params.noindent());
1481 // copy everything behind the break-position
1482 // to the new paragraph
1485 while (ParFromPos(pos_first) != par)
1487 pos_end = pos_first + par->text.size() - 1;
1490 for (i = j = pos; i <= pos_end; ++i) {
1491 par->CutIntoMinibuffer(bparams, i - pos_first);
1492 if (tmp->InsertFromMinibuffer(j - pos))
1498 for (i = pos_end; i >= pos; --i)
1499 par->Erase(i - pos_first);
1503 size_type pos_end = text.size() - 1;
1505 for (i = j = pos; i <= pos_end; ++i) {
1506 CutIntoMinibuffer(bparams, i);
1507 if (tmp->InsertFromMinibuffer(j - pos))
1511 for (i = pos_end; i >= pos; --i)
1519 // just an idea of me
1521 tmp->params.lineTop(firstpar->params.lineTop());
1522 tmp->params.pagebreakTop(firstpar->params.pagebreakTop());
1523 tmp->params.spaceTop(firstpar->params.spaceTop());
1524 tmp->bibkey = firstpar->bibkey;
1526 // layout stays the same with latex-environments
1528 firstpar->SetOnlyLayout(bparams, tmp->layout);
1529 firstpar->SetLabelWidthString(tmp->params.labelWidthString());
1530 firstpar->params.depth(tmp->params.depth());
1534 // just an idea of me
1536 tmp->params.lineTop(params.lineTop());
1537 tmp->params.pagebreakTop(params.pagebreakTop());
1538 tmp->params.spaceTop(params.spaceTop());
1539 tmp->bibkey = bibkey;
1541 // layout stays the same with latex-environments
1543 SetOnlyLayout(bparams, tmp->layout);
1544 SetLabelWidthString(tmp->params.labelWidthString());
1545 params.depth(tmp->params.depth());
1552 void LyXParagraph::MakeSameLayout(LyXParagraph const * par)
1555 par = par->FirstPhysicalPar();
1556 footnoteflag = par->footnoteflag;
1557 footnotekind = par->footnotekind;
1559 layout = par->layout;
1560 params.makeSame(par->params);
1562 // This can be changed after NEW_INSETS is in effect. (Lgb)
1563 SetLabelWidthString(par->params.labelWidthString());
1568 LyXParagraph * LyXParagraph::FirstSelfrowPar()
1570 LyXParagraph * tmppar = this;
1573 && tmppar->previous->footnoteflag ==
1574 LyXParagraph::CLOSED_FOOTNOTE)
1575 || tmppar->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))
1576 tmppar = tmppar->previous;
1579 return this; // This should never happen!
1586 int LyXParagraph::StripLeadingSpaces(LyXTextClassList::size_type tclass)
1588 if (textclasslist.Style(tclass, GetLayout()).free_spacing)
1596 && (IsNewline(0) || IsLineSeparator(0))){
1607 LyXParagraph * LyXParagraph::Clone() const
1609 // create a new paragraph
1610 LyXParagraph * result = new LyXParagraph;
1612 result->MakeSameLayout(this);
1614 // this is because of the dummy layout of the paragraphs that
1616 result->layout = layout;
1618 result->inset_owner = inset_owner;
1622 result->bibkey = static_cast<InsetBibKey *>
1623 (bibkey->Clone(*current_view->buffer()));
1627 // copy everything behind the break-position to the new paragraph
1629 result->text = text;
1630 result->fontlist = fontlist;
1631 result->insetlist = insetlist;
1632 for (InsetList::iterator it = result->insetlist.begin();
1633 it != result->insetlist.end(); ++it)
1634 (*it).inset = (*it).inset->Clone(*current_view->buffer());
1639 bool LyXParagraph::HasSameLayout(LyXParagraph const * par) const
1642 par = par->FirstPhysicalPar();
1647 par->footnoteflag == footnoteflag &&
1648 par->footnotekind == footnotekind &&
1650 par->layout == layout &&
1651 params.sameLayout(par->params);
1655 void LyXParagraph::BreakParagraphConservative(BufferParams const & bparams,
1656 LyXParagraph::size_type pos)
1659 // create a new paragraph
1660 LyXParagraph * par = ParFromPos(pos);
1662 LyXParagraph * tmp = new LyXParagraph(par);
1664 tmp->MakeSameLayout(par);
1666 // When can pos < Last()?
1667 // I guess pos == Last() is possible.
1669 // copy everything behind the break-position to the new
1671 size_type pos_first = 0;
1672 while (ParFromPos(pos_first) != par)
1674 size_type pos_end = pos_first + par->text.size() - 1;
1677 for (i = j = pos; i <= pos_end; ++i) {
1678 par->CutIntoMinibuffer(bparams, i - pos_first);
1679 if (tmp->InsertFromMinibuffer(j - pos))
1685 for (size_type i = pos_end; i >= pos; --i)
1686 par->Erase(i - pos_first);
1691 // create a new paragraph
1692 LyXParagraph * tmp = new LyXParagraph(this);
1693 tmp->MakeSameLayout(this);
1695 // When can pos > Last()?
1696 // I guess pos == Last() is possible.
1698 // copy everything behind the break-position to the new
1700 size_type pos_end = text.size() - 1;
1703 for (i = j = pos; i <= pos_end; ++i) {
1704 CutIntoMinibuffer(bparams, i);
1705 if (tmp->InsertFromMinibuffer(j - pos))
1711 for (size_type i = pos_end; i >= pos; --i)
1720 // Be carefull, this does not make any check at all.
1721 // This method has wrong name, it combined this par with the next par.
1722 // In that sense it is the reverse of break paragraph. (Lgb)
1723 void LyXParagraph::PasteParagraph(BufferParams const & bparams)
1725 // copy the next paragraph to this one
1726 LyXParagraph * the_next = Next();
1728 LyXParagraph * firstpar = FirstPhysicalPar();
1731 // first the DTP-stuff
1733 firstpar->params.lineBottom(the_next->params.lineBottom());
1734 firstpar->params.spaceBottom(the_next->params.spaceBottom());
1735 firstpar->params.pagebreakBottom(the_next->params.pagebreakBottom());
1737 params.lineBottom(the_next->params.lineBottom());
1738 params.spaceBottom(the_next->params.spaceBottom());
1739 params.pagebreakBottom(the_next->params.pagebreakBottom());
1742 size_type pos_end = the_next->text.size() - 1;
1743 size_type pos_insert = Last();
1745 // ok, now copy the paragraph
1747 for (i = j = 0; i <= pos_end; ++i) {
1748 the_next->CutIntoMinibuffer(bparams, i);
1749 if (InsertFromMinibuffer(pos_insert + j))
1753 // delete the next paragraph
1754 LyXParagraph * ppar = the_next->previous;
1755 LyXParagraph * npar = the_next->next;
1762 void LyXParagraph::OpenFootnote(LyXParagraph::size_type pos)
1764 LyXParagraph * par = ParFromPos(pos);
1766 while (par && par->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1767 par->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
1773 void LyXParagraph::CloseFootnote(LyXParagraph::size_type pos)
1775 LyXParagraph * par = ParFromPos(pos);
1777 while (par && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1778 par->footnoteflag = LyXParagraph::CLOSED_FOOTNOTE;
1785 int LyXParagraph::GetEndLabel(BufferParams const & bparams) const
1787 LyXParagraph const * par = this;
1788 int par_depth = GetDepth();
1790 LyXTextClass::LayoutList::size_type layout = par->GetLayout();
1791 int const endlabeltype =
1792 textclasslist.Style(bparams.textclass,
1793 layout).endlabeltype;
1794 if (endlabeltype != END_LABEL_NO_LABEL) {
1795 LyXParagraph const * last = this;
1797 if (footnoteflag == NO_FOOTNOTE)
1798 last = LastPhysicalPar();
1799 else if (next->footnoteflag == NO_FOOTNOTE)
1800 return endlabeltype;
1805 if (!last || !last->next)
1806 return endlabeltype;
1808 int next_depth = last->next->GetDepth();
1809 if (par_depth > next_depth ||
1810 (par_depth == next_depth && layout != last->next->GetLayout() ))
1811 return endlabeltype;
1816 par = par->DepthHook(par_depth - 1);
1818 par_depth = par->GetDepth();
1820 return END_LABEL_NO_LABEL;
1824 LyXTextClass::size_type LyXParagraph::GetLayout() const
1827 return FirstPhysicalPar()->layout;
1834 char LyXParagraph::GetDepth() const
1837 return FirstPhysicalPar()->params.depth();
1839 return params.depth();
1844 char LyXParagraph::GetAlign() const
1847 return FirstPhysicalPar()->params.align();
1849 return params.align();
1854 string const & LyXParagraph::GetLabelstring() const
1857 return FirstPhysicalPar()->params.labelString();
1859 return params.labelString();
1864 int LyXParagraph::GetFirstCounter(int i) const
1867 return FirstPhysicalPar()->counter_[i];
1874 // the next two functions are for the manual labels
1875 string const LyXParagraph::GetLabelWidthString() const
1878 if (!FirstPhysicalPar()->params.labelWidthString().empty())
1879 return FirstPhysicalPar()->params.labelWidthString();
1881 if (!params.labelWidthString().empty())
1882 return params.labelWidthString();
1885 return _("Senseless with this layout!");
1889 void LyXParagraph::SetLabelWidthString(string const & s)
1892 LyXParagraph * par = FirstPhysicalPar();
1894 par->params.labelWidthString(s);
1896 params.labelWidthString(s);
1901 void LyXParagraph::SetOnlyLayout(BufferParams const & bparams,
1902 LyXTextClass::size_type new_layout)
1905 LyXParagraph * par = FirstPhysicalPar();
1907 LyXParagraph * par = this;
1909 LyXParagraph * ppar = 0;
1910 LyXParagraph * npar = 0;
1912 par->layout = new_layout;
1914 if (par->params.pextraType() == PEXTRA_NONE) {
1915 if (par->Previous()) {
1917 ppar = par->Previous()->FirstPhysicalPar();
1919 ppar = par->Previous();
1923 && (ppar->params.depth() > par->params.depth()))
1925 ppar = ppar->Previous()->FirstPhysicalPar();
1927 ppar = ppar->Previous();
1932 npar = par->Next()->NextAfterFootnote();
1938 && (npar->params.depth() > par->params.depth()))
1940 npar = npar->Next()->NextAfterFootnote();
1942 npar = npar->Next();
1945 if (ppar && (ppar->params.pextraType() != PEXTRA_NONE)) {
1946 string p1 = ppar->params.pextraWidth();
1947 string p2 = ppar->params.pextraWidthp();
1948 ppar->SetPExtraType(bparams,
1949 ppar->params.pextraType(),
1952 if ((par->params.pextraType() == PEXTRA_NONE) &&
1953 npar && (npar->params.pextraType() != PEXTRA_NONE)) {
1954 string const p1 = npar->params.pextraWidth();
1955 string const p2 = npar->params.pextraWidthp();
1956 npar->SetPExtraType(bparams, npar->params.pextraType(),
1963 void LyXParagraph::SetLayout(BufferParams const & bparams,
1964 LyXTextClass::size_type new_layout)
1968 * par = FirstPhysicalPar(),
1975 par->layout = new_layout;
1976 par->params.labelWidthString(string());
1977 par->params.align(LYX_ALIGN_LAYOUT);
1978 par->params.spaceTop(VSpace(VSpace::NONE));
1979 par->params.spaceBottom(VSpace(VSpace::NONE));
1980 par->params.spacing(Spacing(Spacing::Default));
1982 if (par->params.pextraType() == PEXTRA_NONE) {
1983 if (par->Previous()) {
1985 ppar = par->Previous()->FirstPhysicalPar();
1987 ppar = par->Previous();
1991 && (ppar->params.depth() > par->params.depth()))
1993 ppar = ppar->Previous()->FirstPhysicalPar();
1995 ppar = ppar->Previous();
2000 npar = par->Next()->NextAfterFootnote();
2006 && (npar->params.depth() > par->params.depth()))
2008 npar = npar->Next()->NextAfterFootnote();
2010 npar = npar->Next();
2013 if (ppar && (ppar->params.pextraType() != PEXTRA_NONE)) {
2014 string const p1 = ppar->params.pextraWidth();
2015 string const p2 = ppar->params.pextraWidthp();
2016 ppar->SetPExtraType(bparams, ppar->params.pextraType(),
2019 if ((par->params.pextraType() == PEXTRA_NONE) &&
2020 npar && (npar->params.pextraType() != PEXTRA_NONE)) {
2021 string const p1 = npar->params.pextraWidth();
2022 string const p2 = npar->params.pextraWidthp();
2023 npar->SetPExtraType(bparams, npar->params.pextraType(),
2030 // if the layout of a paragraph contains a manual label, the beginning of the
2031 // main body is the beginning of the second word. This is what the par-
2032 // function returns. If the layout does not contain a label, the main
2033 // body always starts with position 0. This differentiation is necessary,
2034 // because there cannot be a newline or a blank <= the beginning of the
2035 // main body in TeX.
2037 int LyXParagraph::BeginningOfMainBody() const
2040 if (FirstPhysicalPar() != this)
2043 // Unroll the first two cycles of the loop
2044 // and remember the previous character to
2045 // remove unnecessary GetChar() calls
2048 && GetChar(i) != LyXParagraph::META_NEWLINE
2051 char previous_char = 0;
2054 && (previous_char = GetChar(i)) != LyXParagraph::META_NEWLINE) {
2055 // Yes, this ^ is supposed to be "= " not "=="
2058 && previous_char != ' '
2059 && (temp = GetChar(i)) != LyXParagraph::META_NEWLINE) {
2061 previous_char = temp;
2067 if (i == 0 && i == size() &&
2068 !(footnoteflag == LyXParagraph::NO_FOOTNOTE
2069 && next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE))
2070 ++i; /* the cursor should not jump
2071 * to the main body if there
2078 LyXParagraph * LyXParagraph::DepthHook(int deth)
2080 LyXParagraph * newpar = this;
2086 newpar = newpar->FirstPhysicalPar()->Previous();
2088 newpar = newpar->Previous();
2090 } while (newpar && newpar->GetDepth() > deth
2092 && newpar->footnoteflag == footnoteflag
2097 if (Previous() || GetDepth())
2098 lyxerr << "ERROR (LyXParagraph::DepthHook): "
2103 return newpar->FirstPhysicalPar();
2110 LyXParagraph const * LyXParagraph::DepthHook(int deth) const
2112 LyXParagraph const * newpar = this;
2118 newpar = newpar->FirstPhysicalPar()->Previous();
2120 newpar = newpar->Previous();
2122 } while (newpar && newpar->GetDepth() > deth
2124 && newpar->footnoteflag == footnoteflag
2129 if (Previous() || GetDepth())
2130 lyxerr << "ERROR (LyXParagraph::DepthHook): "
2135 return newpar->FirstPhysicalPar();
2142 int LyXParagraph::AutoDeleteInsets()
2145 InsetList::size_type index = 0;
2146 while (index < insetlist.size()) {
2147 if (insetlist[index].inset && insetlist[index].inset->AutoDelete()) {
2148 Erase(insetlist[index].pos);
2149 // Erase() calls to insetlist.erase(&insetlist[index])
2150 // so index shouldn't be increased.
2159 LyXParagraph::inset_iterator
2160 LyXParagraph::InsetIterator(LyXParagraph::size_type pos)
2162 InsetTable search_inset(pos, 0);
2163 InsetList::iterator it = lower_bound(insetlist.begin(),
2165 search_inset, matchIT());
2166 return inset_iterator(it);
2170 // returns -1 if inset not found
2171 int LyXParagraph::GetPositionOfInset(Inset * inset) const
2174 for (InsetList::const_iterator cit = insetlist.begin();
2175 cit != insetlist.end(); ++cit) {
2176 if ((*cit).inset == inset) {
2180 if (inset == bibkey)
2184 // Think about footnotes.
2185 if (footnoteflag == LyXParagraph::NO_FOOTNOTE
2186 && next && next->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2188 NextAfterFootnote()->GetPositionOfInset(inset);
2190 return text.size() + 1 + further;
2197 LyXParagraph * LyXParagraph::TeXOnePar(Buffer const * buf,
2198 BufferParams const & bparams,
2199 ostream & os, TexRow & texrow,
2204 TexRow & foot_texrow,
2209 lyxerr[Debug::LATEX] << "TeXOnePar... " << this << endl;
2210 LyXLayout const & style =
2211 textclasslist.Style(bparams.textclass,
2214 bool further_blank_line = false;
2217 lyxerr << "ERROR (LyXParagraph::TeXOnePar) is dummy." << endl;
2220 if (params.startOfAppendix()) {
2221 os << "\\appendix\n";
2225 if (!params.spacing().isDefault()
2226 && (!Previous() || !Previous()->HasSameLayout(this))) {
2227 os << params.spacing().writeEnvirBegin() << "\n";
2231 if (tex_code_break_column && style.isCommand()){
2236 if (params.pagebreakTop()) {
2238 further_blank_line = true;
2240 if (params.spaceTop().kind() != VSpace::NONE) {
2241 os << params.spaceTop().asLatexCommand(bparams);
2242 further_blank_line = true;
2245 if (params.lineTop()) {
2246 os << "\\lyxline{\\" << getFont(bparams, 0).latexSize() << '}'
2247 << "\\vspace{-1\\parskip}";
2248 further_blank_line = true;
2251 if (further_blank_line){
2256 Language const * language = getParLanguage(bparams);
2257 Language const * doc_language = bparams.language;
2258 Language const * previous_language = previous
2259 ? previous->getParLanguage(bparams) : doc_language;
2260 if (language->babel() != doc_language->babel() &&
2261 language->babel() != previous_language->babel()) {
2262 os << subst(lyxrc.language_command_begin, "$$lang",
2268 if (bparams.inputenc == "auto" &&
2269 language->encoding() != previous_language->encoding()) {
2270 os << "\\inputencoding{"
2271 << language->encoding()->LatexName()
2276 switch (style.latextype) {
2279 << style.latexname()
2280 << style.latexparam();
2282 case LATEX_ITEM_ENVIRONMENT:
2284 bibkey->Latex(buf, os, false, false);
2288 case LATEX_LIST_ENVIRONMENT:
2295 bool need_par = SimpleTeXOnePar(buf, bparams, os, texrow, moving_arg);
2297 LyXParagraph * par = next;
2299 // Spit out footnotes
2300 if (lyxrc.rtl_support) {
2301 if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE
2302 && next->footnoteflag != footnoteflag) {
2303 LyXParagraph * p = 0;
2304 bool is_rtl = (size() > 0)
2305 ? GetFontSettings(bparams,
2306 size()-1).isRightToLeft()
2307 : language->RightToLeft();
2308 if ((p = NextAfterFootnote()) != 0 &&
2310 p->GetFontSettings(bparams, 0).isRightToLeft() != is_rtl)
2311 is_rtl = getParLanguage(bparams)->RightToLeft();
2312 while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2313 && par->footnoteflag != footnoteflag) {
2314 par = par->TeXFootnote(buf, bparams,
2316 foot_texrow, foot_count,
2318 par->SimpleTeXOnePar(buf, bparams,
2319 os, texrow, moving_arg);
2320 is_rtl = (par->size() > 0)
2321 ? par->GetFontSettings(bparams,
2322 par->size()-1).isRightToLeft()
2323 : language->RightToLeft();
2325 par->next->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
2326 (p = par->NextAfterFootnote()) != 0 &&
2328 p->GetFontSettings(bparams, 0).isRightToLeft() != is_rtl)
2329 is_rtl = language->RightToLeft();
2334 while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2335 && par->footnoteflag != footnoteflag) {
2336 par = par->TeXFootnote(buf, bparams,
2338 foot, foot_texrow, foot_count,
2340 par->SimpleTeXOnePar(buf, bparams, os, texrow, moving_arg);
2346 // Make sure that \\par is done with the font of the last
2347 // character if this has another size as the default.
2348 // This is necessary because LaTeX (and LyX on the screen)
2349 // calculates the space between the baselines according
2350 // to this font. (Matthias)
2352 // Is this really needed ? (Dekel)
2353 // We do not need to use to change the font for the last paragraph
2354 // or for a command.
2355 LyXFont font = getFont(bparams, Last() - 1);
2356 bool is_command = textclasslist.Style(bparams.textclass,
2357 GetLayout()).isCommand();
2358 if (style.resfont.size() != font.size() && next && !is_command) {
2361 os << "\\" << font.latexSize() << " \\par}";
2362 } else if (need_par) {
2364 } else if (is_command)
2367 if (language->babel() != doc_language->babel() &&
2370 || (footnoteflag != NO_FOOTNOTE && par->footnoteflag != footnoteflag)
2372 || par->getParLanguage(bparams)->babel() != language->babel())) {
2374 << subst(lyxrc.language_command_end, "$$lang",
2375 doc_language->babel());
2378 switch (style.latextype) {
2379 case LATEX_ITEM_ENVIRONMENT:
2380 case LATEX_LIST_ENVIRONMENT:
2381 if (par && (params.depth() < par->params.depth())) {
2386 case LATEX_ENVIRONMENT:
2387 // if its the last paragraph of the current environment
2388 // skip it otherwise fall through
2390 && (par->layout != layout
2391 || par->params.depth() != params.depth()
2392 || par->params.pextraType() != params.pextraType()))
2395 // we don't need it for the last paragraph!!!
2396 // or for tables in floats
2397 // -- effectively creates a \par where there isn't one which
2398 // breaks a \subfigure or \subtable.
2400 // && footnoteflag == LyXParagraph::NO_FOOTNOTE) {
2406 further_blank_line = false;
2407 if (params.lineBottom()) {
2408 os << "\\lyxline{\\" << getFont(bparams, Last() - 1).latexSize() << '}';
2409 further_blank_line = true;
2412 if (params.spaceBottom().kind() != VSpace::NONE) {
2413 os << params.spaceBottom().asLatexCommand(bparams);
2414 further_blank_line = true;
2417 if (params.pagebreakBottom()) {
2419 further_blank_line = true;
2422 if (further_blank_line){
2427 if (!params.spacing().isDefault()
2428 && (!par || !par->HasSameLayout(this))) {
2429 os << params.spacing().writeEnvirEnd() << "\n";
2433 // we don't need it for the last paragraph!!!
2436 && !(footnoteflag != LyXParagraph::NO_FOOTNOTE && par &&
2437 par->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2444 lyxerr[Debug::LATEX] << "TeXOnePar...done " << par << endl;
2449 // This one spits out the text of the paragraph
2450 bool LyXParagraph::SimpleTeXOnePar(Buffer const * buf,
2451 BufferParams const & bparams,
2452 ostream & os, TexRow & texrow,
2455 lyxerr[Debug::LATEX] << "SimpleTeXOnePar... " << this << endl;
2457 bool return_value = false;
2459 LyXLayout const & style =
2460 textclasslist.Style(bparams.textclass,
2462 LyXFont basefont, last_font;
2464 // Maybe we have to create a optional argument.
2465 size_type main_body;
2466 if (style.labeltype != LABEL_MANUAL)
2469 main_body = BeginningOfMainBody();
2471 if (main_body > 0) {
2473 basefont = getFont(bparams, -2); // Get label font
2475 basefont = getFont(bparams, -1); // Get layout font
2486 if (style.isCommand()) {
2489 } else if (params.align() != LYX_ALIGN_LAYOUT) {
2492 return_value = true;
2496 moving_arg |= style.needprotect;
2498 // Which font is currently active?
2499 LyXFont running_font(basefont);
2500 // Do we have an open font change?
2501 bool open_font = false;
2503 texrow.start(this, 0);
2505 for (size_type i = 0; i < size(); ++i) {
2507 // First char in paragraph or after label?
2513 if (main_body > 0) {
2515 column += running_font.latexWriteEndChanges(os, basefont, basefont);
2518 basefont = getFont(bparams, -1); // Now use the layout font
2519 running_font = basefont;
2523 if (style.isCommand()) {
2526 } else if (params.align() != LYX_ALIGN_LAYOUT && next) {
2527 // We do not need \par here (Dekel)
2531 return_value = true;
2534 if (params.noindent()) {
2535 os << "\\noindent ";
2538 switch (params.align()) {
2539 case LYX_ALIGN_NONE:
2540 case LYX_ALIGN_BLOCK:
2541 case LYX_ALIGN_LAYOUT:
2542 case LYX_ALIGN_SPECIAL:
2544 case LYX_ALIGN_LEFT:
2547 if (getParLanguage(bparams)->babel() != "hebrew") {
2548 os << "\\raggedright ";
2551 os << "\\raggedleft ";
2555 case LYX_ALIGN_RIGHT:
2558 if (getParLanguage(bparams)->babel() != "hebrew") {
2559 os << "\\raggedleft ";
2562 os << "\\raggedright ";
2566 case LYX_ALIGN_CENTER:
2569 os << "\\centering ";
2575 value_type c = GetChar(i);
2577 // Fully instantiated font
2578 LyXFont font = getFont(bparams, i);
2580 LyXParagraph * p = 0;
2583 previous->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
2584 (p = PreviousBeforeFootnote()) != 0)
2585 last_font = p->getFont(bparams, p->size() - 1);
2588 last_font = running_font;
2590 // Spaces at end of font change are simulated to be
2591 // outside font change, i.e. we write "\textXX{text} "
2592 // rather than "\textXX{text }". (Asger)
2593 if (open_font && c == ' ' && i <= size() - 2
2594 && !getFont(bparams, i + 1).equalExceptLatex(running_font)
2595 && !getFont(bparams, i + 1).equalExceptLatex(font)) {
2596 font = getFont(bparams, i + 1);
2598 // We end font definition before blanks
2599 if (!font.equalExceptLatex(running_font) && open_font) {
2600 column += running_font.latexWriteEndChanges(os,
2602 (i == main_body-1) ? basefont : font);
2603 running_font = basefont;
2607 // Blanks are printed before start of fontswitch
2609 // Do not print the separation of the optional argument
2610 if (i != main_body - 1) {
2611 SimpleTeXBlanks(os, texrow, i,
2612 column, font, style);
2616 // Do we need to change font?
2617 if (!font.equalExceptLatex(running_font)
2618 && i != main_body-1) {
2619 column += font.latexWriteStartChanges(os, basefont,
2621 running_font = font;
2625 if (c == LyXParagraph::META_NEWLINE) {
2626 // newlines are handled differently here than
2627 // the default in SimpleTeXSpecialChars().
2628 if (!style.newline_allowed
2629 || font.latex() == LyXFont::ON) {
2633 column += running_font.latexWriteEndChanges(os, basefont, basefont);
2636 basefont = getFont(bparams, -1);
2637 running_font = basefont;
2638 if (font.family() ==
2639 LyXFont::TYPEWRITER_FAMILY) {
2647 texrow.start(this, i + 1);
2650 SimpleTeXSpecialChars(buf, bparams,
2651 os, texrow, moving_arg,
2652 font, running_font, basefont,
2653 open_font, style, i, column, c);
2657 // If we have an open font definition, we have to close it
2659 LyXParagraph * p = 0;
2662 && next->footnoteflag != LyXParagraph::NO_FOOTNOTE
2663 && (p = NextAfterFootnote()) != 0
2668 running_font.latexWriteEndChanges(os, basefont,
2669 p->getFont(bparams, 0));
2671 running_font.latexWriteEndChanges(os, basefont, basefont);
2674 // Needed if there is an optional argument but no contents.
2675 if (main_body > 0 && main_body == size()) {
2677 return_value = false;
2680 lyxerr[Debug::LATEX] << "SimpleTeXOnePar...done " << this << endl;
2681 return return_value;
2685 bool LyXParagraph::linuxDocConvertChar(char c, string & sgml_string)
2687 bool retval = false;
2689 case LyXParagraph::META_HFILL:
2690 sgml_string.erase();
2692 case LyXParagraph::META_NEWLINE:
2696 sgml_string = "&";
2699 sgml_string = "<";
2702 sgml_string = ">";
2705 sgml_string = "$";
2708 sgml_string = "#";
2711 sgml_string = "%";
2714 sgml_string = "[";
2717 sgml_string = "]";
2720 sgml_string = "{";
2723 sgml_string = "}";
2726 sgml_string = "˜";
2729 sgml_string = """;
2732 sgml_string = "\";
2738 case '\0': // Ignore :-)
2739 sgml_string.erase();
2749 void LyXParagraph::SimpleTeXBlanks(ostream & os, TexRow & texrow,
2750 LyXParagraph::size_type const i,
2751 int & column, LyXFont const & font,
2752 LyXLayout const & style)
2754 if (column > tex_code_break_column
2756 && GetChar(i - 1) != ' '
2758 // In LaTeX mode, we don't want to
2759 // break lines since some commands
2761 && ! (font.latex() == LyXFont::ON)
2762 // same in FreeSpacing mode
2763 && !style.free_spacing
2764 // In typewriter mode, we want to avoid
2765 // ! . ? : at the end of a line
2766 && !(font.family() == LyXFont::TYPEWRITER_FAMILY
2767 && (GetChar(i-1) == '.'
2768 || GetChar(i-1) == '?'
2769 || GetChar(i-1) == ':'
2770 || GetChar(i-1) == '!'))) {
2771 if (tex_code_break_column == 0) {
2772 // in batchmode we need LaTeX to still
2773 // see it as a space not as an extra '\n'
2779 texrow.start(this, i + 1);
2781 } else if (font.latex() == LyXFont::OFF) {
2782 if (style.free_spacing) {
2791 void LyXParagraph::SimpleTeXSpecialChars(Buffer const * buf,
2792 BufferParams const & bparams,
2793 ostream & os, TexRow & texrow,
2796 LyXFont & running_font,
2799 LyXLayout const & style,
2800 LyXParagraph::size_type & i,
2802 LyXParagraph::value_type const c)
2804 // Two major modes: LaTeX or plain
2805 // Handle here those cases common to both modes
2806 // and then split to handle the two modes separately.
2808 case LyXParagraph::META_INSET: {
2809 Inset * inset = GetInset(i);
2812 int const len = os.tellp();
2813 //ostream::pos_type const len = os.tellp();
2814 if ((inset->LyxCode() == Inset::GRAPHICS_CODE
2815 || inset->LyxCode() == Inset::MATH_CODE
2816 || inset->LyxCode() == Inset::URL_CODE)
2817 && running_font.isRightToLeft()) {
2822 int tmp = inset->Latex(buf, os, moving_arg,
2823 style.free_spacing);
2831 column += int(os.tellp()) - len;
2840 case LyXParagraph::META_NEWLINE:
2842 column += running_font.latexWriteEndChanges(os,
2847 basefont = getFont(bparams, -1);
2848 running_font = basefont;
2851 case LyXParagraph::META_HFILL:
2857 // And now for the special cases within each mode
2858 // Are we in LaTeX mode?
2859 if (font.latex() == LyXFont::ON) {
2860 // at present we only have one option
2861 // but I'll leave it as a switch statement
2862 // so its simpler to extend. (ARRae)
2865 // make sure that we will not print
2866 // error generating chars to the tex
2867 // file. This test would not be needed
2868 // if it were done in the buffer
2876 // Plain mode (i.e. not LaTeX)
2879 os << "\\textbackslash{}";
2883 case '°': case '±': case '²': case '³':
2884 case '×': case '÷': case '¹': case 'ª':
2885 case 'º': case '¬': case 'µ':
2886 if (bparams.inputenc == "latin1" ||
2887 (bparams.inputenc == "auto" &&
2888 font.language()->encoding()->LatexName()
2890 os << "\\ensuremath{"
2899 case '|': case '<': case '>':
2900 // In T1 encoding, these characters exist
2901 if (lyxrc.fontenc == "T1") {
2903 //... but we should avoid ligatures
2904 if ((c == '>' || c == '<')
2906 && GetChar(i + 1) == c) {
2907 //os << "\\textcompwordmark{}";
2908 // Jean-Marc, have a look at
2909 // this. IÂ think this works
2917 // Typewriter font also has them
2918 if (font.family() == LyXFont::TYPEWRITER_FAMILY) {
2922 // Otherwise, we use what LaTeX
2926 os << "\\textless{}";
2930 os << "\\textgreater{}";
2934 os << "\\textbar{}";
2940 case '-': // "--" in Typewriter mode -> "-{}-"
2942 && GetChar(i + 1) == '-'
2943 && font.family() == LyXFont::TYPEWRITER_FAMILY) {
2952 os << "\\char`\\\"{}";
2957 if (bparams.inputenc == "default") {
2966 case '%': case '#': case '{':
2973 os << "\\textasciitilde{}";
2978 os << "\\textasciicircum{}";
2982 case '*': case '[': case ']':
2983 // avoid being mistaken for optional arguments
2984 os << '{' << c << '}';
2989 // Blanks are printed before font switching.
2990 // Sure? I am not! (try nice-latex)
2991 // I am sure it's correct. LyX might be smarter
2992 // in the future, but for now, nothing wrong is
2997 /* idea for labels --- begin*/
3001 && font.family() != LyXFont::TYPEWRITER_FAMILY
3002 && GetChar(i + 1) == 'y'
3003 && GetChar(i + 2) == 'X') {
3011 && font.family() != LyXFont::TYPEWRITER_FAMILY
3012 && GetChar(i + 1) == 'e'
3013 && GetChar(i + 2) == 'X') {
3018 // Check for "LaTeX2e"
3021 && font.family() != LyXFont::TYPEWRITER_FAMILY
3022 && GetChar(i + 1) == 'a'
3023 && GetChar(i + 2) == 'T'
3024 && GetChar(i + 3) == 'e'
3025 && GetChar(i + 4) == 'X'
3026 && GetChar(i + 5) == '2'
3027 && GetChar(i + 6) == 'e') {
3032 // Check for "LaTeX"
3035 && font.family() != LyXFont::TYPEWRITER_FAMILY
3036 && GetChar(i + 1) == 'a'
3037 && GetChar(i + 2) == 'T'
3038 && GetChar(i + 3) == 'e'
3039 && GetChar(i + 4) == 'X') {
3043 /* idea for labels --- end*/
3044 } else if (c != '\0') {
3054 LyXParagraph * LyXParagraph::TeXDeeper(Buffer const * buf,
3055 BufferParams const & bparams,
3056 ostream & os, TexRow & texrow
3059 TexRow & foot_texrow,
3064 lyxerr[Debug::LATEX] << "TeXDeeper... " << this << endl;
3065 LyXParagraph * par = this;
3068 (par->params.depth() == params.depth())
3070 && (par->footnoteflag == footnoteflag)
3075 lyxerr << "ERROR (LyXParagraph::TeXDeeper)" << endl;
3077 if (textclasslist.Style(bparams.textclass,
3078 par->layout).isEnvironment()
3079 || par->params.pextraType() != PEXTRA_NONE) {
3080 par = par->TeXEnvironment(buf, bparams,
3088 par = par->TeXOnePar(buf, bparams,
3098 lyxerr[Debug::LATEX] << "TeXDeeper...done " << par << endl;
3104 LyXParagraph * LyXParagraph::TeXEnvironment(Buffer const * buf,
3105 BufferParams const & bparams,
3106 ostream & os, TexRow & texrow
3109 TexRow & foot_texrow,
3114 bool eindent_open = false;
3116 bool foot_this_level = false;
3118 // flags when footnotetext should be appended to file.
3119 static bool minipage_open = false;
3120 static int minipage_open_depth = 0;
3121 char par_sep = bparams.paragraph_separation;
3123 lyxerr[Debug::LATEX] << "TeXEnvironment... " << this << endl;
3126 lyxerr << "ERROR (LyXParagraph::TeXEnvironment)" << endl;
3129 LyXLayout const & style =
3130 textclasslist.Style(bparams.textclass,
3133 if (params.pextraType() == PEXTRA_INDENT) {
3134 if (!params.pextraWidth().empty()) {
3135 os << "\\begin{LyXParagraphIndent}{"
3136 << params.pextraWidth() << "}\n";
3138 //float ib = atof(pextra_widthp.c_str())/100;
3139 // string can't handle floats at present (971109)
3140 // so I'll do a conversion by hand knowing that
3141 // the limits are 0.0 to 1.0. ARRae.
3142 os << "\\begin{LyXParagraphIndent}{";
3143 switch (params.pextraWidthp().length()) {
3149 << params.pextraWidthp();
3153 << params.pextraWidthp();
3155 os << "\\columnwidth}\n";
3158 eindent_open = true;
3160 if ((params.pextraType() == PEXTRA_MINIPAGE) && !minipage_open) {
3161 if (params.pextraHfill() && Previous() &&
3162 (Previous()->params.pextraType() == PEXTRA_MINIPAGE)) {
3163 os << "\\hfill{}\n";
3166 if (par_sep == BufferParams::PARSEP_INDENT) {
3167 os << "{\\setlength\\parindent{0pt}\n";
3170 os << "\\begin{minipage}";
3171 switch (params.pextraAlignment()) {
3172 case MINIPAGE_ALIGN_TOP:
3175 case MINIPAGE_ALIGN_MIDDLE:
3178 case MINIPAGE_ALIGN_BOTTOM:
3182 if (!params.pextraWidth().empty()) {
3183 os << '{' << params.pextraWidth() << "}\n";
3185 //float ib = atof(par->pextra_width.c_str())/100;
3186 // string can't handle floats at present
3187 // so I'll do a conversion by hand knowing that
3188 // the limits are 0.0 to 1.0. ARRae.
3190 switch (params.pextraWidthp().length()) {
3196 << params.pextraWidthp();
3200 << params.pextraWidthp();
3202 os << "\\columnwidth}\n";
3205 if (par_sep == BufferParams::PARSEP_INDENT) {
3206 os << "\\setlength\\parindent{\\LyXMinipageIndent}\n";
3209 minipage_open = true;
3210 minipage_open_depth = params.depth();
3213 #ifdef WITH_WARNINGS
3214 #warning Define FANCY_FOOTNOTE_CODE to re-enable Allan footnote code
3215 //I disabled it because it breaks when lists span on several
3218 if (style.isEnvironment()){
3219 if (style.latextype == LATEX_LIST_ENVIRONMENT) {
3220 #ifdef FANCY_FOOTNOTE_CODE
3221 if (foot_count < 0) {
3222 // flag that footnote[mark][text] should be
3223 // used for any footnotes from now on
3225 foot_this_level = true;
3228 os << "\\begin{" << style.latexname() << "}{"
3229 << params.labelWidthString() << "}\n";
3230 } else if (style.labeltype == LABEL_BIBLIO) {
3232 os << "\\begin{" << style.latexname() << "}{"
3233 << bibitemWidest(buf)
3235 } else if (style.latextype == LATEX_ITEM_ENVIRONMENT) {
3236 #ifdef FANCY_FOOTNOTE_CODE
3237 if (foot_count < 0) {
3238 // flag that footnote[mark][text] should be
3239 // used for any footnotes from now on
3241 foot_this_level = true;
3244 os << "\\begin{" << style.latexname() << '}'
3245 << style.latexparam() << '\n';
3247 os << "\\begin{" << style.latexname() << '}'
3248 << style.latexparam() << '\n';
3251 LyXParagraph * par = this;
3253 par = par->TeXOnePar(buf, bparams,
3257 foot, foot_texrow, foot_count
3261 if (minipage_open && par && !style.isEnvironment() &&
3262 (par->params.pextraType() == PEXTRA_MINIPAGE) &&
3263 par->params.pextraStartMinipage()) {
3264 os << "\\end{minipage}\n";
3266 if (par_sep == BufferParams::PARSEP_INDENT) {
3270 minipage_open = false;
3272 if (par && par->params.depth() > params.depth()) {
3273 if (textclasslist.Style(bparams.textclass,
3274 par->layout).isParagraph()
3276 // How to handle this? (Lgb)
3277 //&& !suffixIs(os, "\n\n")
3279 // There should be at least one '\n' already
3280 // but we need there to be two for Standard
3281 // paragraphs that are depth-increment'ed to be
3282 // output correctly. However, tables can
3283 // also be paragraphs so don't adjust them.
3286 // Will it ever harm to have one '\n' too
3287 // many? i.e. that we sometimes will have
3288 // three in a row. (Lgb)
3292 par = par->TeXDeeper(buf, bparams, os, texrow
3294 ,foot, foot_texrow, foot_count
3298 if (par && par->layout == layout && par->params.depth() == params.depth() &&
3299 (par->params.pextraType() == PEXTRA_MINIPAGE) && !minipage_open) {
3300 if (par->params.pextraHfill() && par->Previous() &&
3301 (par->Previous()->params.pextraType() == PEXTRA_MINIPAGE)){
3302 os << "\\hfill{}\n";
3305 if (par_sep == BufferParams::PARSEP_INDENT) {
3306 os << "{\\setlength\\parindent{0pt}\n";
3309 os << "\\begin{minipage}";
3310 switch (par->params.pextraAlignment()) {
3311 case MINIPAGE_ALIGN_TOP:
3314 case MINIPAGE_ALIGN_MIDDLE:
3317 case MINIPAGE_ALIGN_BOTTOM:
3321 if (!par->params.pextraWidth().empty()) {
3322 os << '{' << par->params.pextraWidth() << "}\n";
3324 //float ib = atof(par->pextra_widthp.c_str())/100;
3325 // string can't handle floats at present
3326 // so I'll do a conversion by hand knowing that
3327 // the limits are 0.0 to 1.0. ARRae.
3329 switch (par->params.pextraWidthp().length()) {
3334 os << "0." << par->params.pextraWidthp();
3337 os << "0.0" << par->params.pextraWidthp();
3339 os << "\\columnwidth}\n";
3342 if (par_sep == BufferParams::PARSEP_INDENT) {
3343 os << "\\setlength\\parindent{\\LyXMinipageIndent}\n";
3346 minipage_open = true;
3347 minipage_open_depth = par->params.depth();
3350 && par->layout == layout
3351 && par->params.depth() == params.depth()
3352 && par->params.pextraType() == params.pextraType()
3354 && par->footnoteflag == footnoteflag
3358 if (style.isEnvironment()) {
3359 os << "\\end{" << style.latexname() << '}';
3361 // maybe this should go after the minipage closes?
3362 if (foot_this_level) {
3363 if (foot_count >= 1) {
3364 if (foot_count > 1) {
3365 os << "\\addtocounter{footnote}{-"
3370 texrow += foot_texrow;
3372 foot_texrow.reset();
3378 if (minipage_open && (minipage_open_depth == params.depth()) &&
3379 (!par || par->params.pextraStartMinipage() ||
3380 par->params.pextraType() != PEXTRA_MINIPAGE)) {
3381 os << "\\end{minipage}\n";
3383 if (par_sep == BufferParams::PARSEP_INDENT) {
3387 if (par && par->params.pextraType() != PEXTRA_MINIPAGE) {
3388 os << "\\medskip\n\n";
3392 minipage_open = false;
3395 os << "\\end{LyXParagraphIndent}\n";
3398 if (!(par && (par->params.pextraType() == PEXTRA_MINIPAGE)
3399 && par->params.pextraHfill())) {
3403 lyxerr[Debug::LATEX] << "TeXEnvironment...done " << par << endl;
3404 return par; // ale970302
3409 LyXParagraph * LyXParagraph::TeXFootnote(Buffer const * buf,
3410 BufferParams const & bparams,
3411 ostream & os, TexRow & texrow,
3412 ostream & foot, TexRow & foot_texrow,
3416 lyxerr[Debug::LATEX] << "TeXFootnote... " << this << endl;
3417 if (footnoteflag == LyXParagraph::NO_FOOTNOTE)
3418 lyxerr << "ERROR (LyXParagraph::TeXFootnote): "
3419 "No footnote!" << endl;
3421 LyXParagraph * par = this;
3422 LyXLayout const & style =
3423 textclasslist.Style(bparams.textclass,
3424 previous->GetLayout());
3426 if (style.needprotect && footnotekind != LyXParagraph::FOOTNOTE){
3427 lyxerr << "ERROR (LyXParagraph::TeXFootnote): "
3428 "Float other than footnote in command"
3429 " with moving argument is illegal" << endl;
3432 if (footnotekind != LyXParagraph::FOOTNOTE
3433 && footnotekind != LyXParagraph::MARGIN
3436 // How to solve this?
3437 //&& !suffixIs(file, '\n')
3439 // we need to ensure that real floats like tables and figures
3440 // have their \begin{} on a new line otherwise we can get
3441 // incorrect results when using the endfloat.sty package
3442 // especially if two floats follow one another. ARRae 981022
3443 // NOTE: if the file is length 0 it must have just been
3444 // written out so we assume it ended with a '\n'
3446 // As far as I can see there is never any harm in writing
3447 // a '\n' too much. Please tell me if I am wrong. (Lgb)
3452 bool moving_arg = false;
3453 bool need_closing = false;
3454 bool is_rtl = isRightToLeftPar(bparams);
3456 if (is_rtl != parent_is_rtl) {
3461 need_closing = true;
3464 bool footer_in_body = true;
3465 switch (footnotekind) {
3466 case LyXParagraph::FOOTNOTE:
3467 if (style.intitle) {
3468 os << "\\thanks{\n";
3469 footer_in_body = false;
3472 if (foot_count == -1) {
3473 // we're at depth 0 so we can use:
3474 os << "\\footnote{%\n";
3475 footer_in_body = false;
3477 os << "\\footnotemark{}%\n";
3479 // we only need this when there are
3480 // multiple footnotes
3481 os << "\\stepcounter{footnote}";
3483 os << "\\footnotetext{%\n";
3484 foot_texrow.start(this, 0);
3485 foot_texrow.newline();
3490 case LyXParagraph::MARGIN:
3491 os << "\\marginpar{\n";
3493 case LyXParagraph::FIG:
3494 if (params.pextraType() == PEXTRA_FLOATFLT
3495 && (!params.pextraWidth().empty()
3496 || !params.pextraWidthp().empty())) {
3497 if (!params.pextraWidth().empty())
3498 os << "\\begin{floatingfigure}{"
3499 << params.pextraWidth() << "}\n";
3501 os << "\\begin{floatingfigure}{"
3502 << lyx::atoi(params.pextraWidthp()) / 100.0
3503 << "\\textwidth}\n";
3505 os << "\\begin{figure}";
3506 if (!bparams.float_placement.empty()) {
3507 os << '[' << bparams.float_placement << "]\n";
3513 case LyXParagraph::TAB:
3514 os << "\\begin{table}";
3515 if (!bparams.float_placement.empty()) {
3516 os << '[' << bparams.float_placement << "]\n";
3521 case LyXParagraph::WIDE_FIG:
3522 os << "\\begin{figure*}";
3523 if (!bparams.float_placement.empty()) {
3524 os << '[' << bparams.float_placement << "]\n";
3529 case LyXParagraph::WIDE_TAB:
3530 os << "\\begin{table*}";
3531 if (!bparams.float_placement.empty()) {
3532 os << '[' << bparams.float_placement << "]\n";
3537 case LyXParagraph::ALGORITHM:
3538 os << "\\begin{algorithm}\n";
3543 if (footnotekind != LyXParagraph::FOOTNOTE
3544 || !footer_in_body) {
3545 // Process text for all floats except footnotes in body
3547 LyXLayout const & style =
3549 .Style(bparams.textclass, par->layout);
3551 lyxerr << "ERROR (LyXParagraph::TeXFootnote)"
3553 if (style.isEnvironment()
3554 || par->params.pextraType() == PEXTRA_MINIPAGE) { /* && !minipage_open ?? */
3555 // Allows the use of minipages within float
3556 // environments. Shouldn't be circular because
3557 // we don't support footnotes inside
3558 // floats (yet). ARRae
3559 par = par->TeXEnvironment(buf, bparams, os,
3564 par = par->TeXOnePar(buf, bparams,
3565 os, texrow, moving_arg,
3570 if (par && !par->IsDummy() && par->params.depth() > params.depth()) {
3571 par = par->TeXDeeper(buf, bparams, os, texrow,
3575 } while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE);
3577 // process footnotes > depth 0 or in environments separately
3578 // NOTE: Currently don't support footnotes within footnotes
3579 // even though that is possible using the \footnotemark
3580 std::ostringstream dummy;
3581 TexRow dummy_texrow;
3582 int dummy_count = 0;
3584 LyXLayout const & style =
3586 .Style(bparams.textclass, par->layout);
3588 lyxerr << "ERROR (LyXParagraph::TeXFootnote)"
3590 if (style.isEnvironment()
3591 || par->params.pextraType() == PEXTRA_MINIPAGE) { /* && !minipage_open ?? */
3592 // Allows the use of minipages within float
3593 // environments. Shouldn't be circular because
3594 // we don't support footnotes inside
3595 // floats (yet). ARRae
3596 par = par->TeXEnvironment(buf, bparams,
3598 dummy, dummy_texrow,
3601 par = par->TeXOnePar(buf, bparams,
3604 dummy, dummy_texrow,
3608 if (par && !par->IsDummy() && par->params.depth() > params.depth()) {
3609 par = par->TeXDeeper(buf, bparams,
3611 dummy, dummy_texrow,
3615 && par->footnoteflag != LyXParagraph::NO_FOOTNOTE);
3617 lyxerr << "ERROR (LyXParagraph::TeXFootnote): "
3618 "Footnote in a Footnote -- not supported"
3623 switch (footnotekind) {
3624 case LyXParagraph::FOOTNOTE:
3625 if (footer_in_body) {
3626 // This helps tell which of the multiple
3627 // footnotetexts an error was in.
3629 foot_texrow.newline();
3634 case LyXParagraph::MARGIN:
3637 case LyXParagraph::FIG:
3638 if (params.pextraType() == PEXTRA_FLOATFLT
3639 && (!params.pextraWidth().empty()
3640 || !params.pextraWidthp().empty()))
3641 os << "\\end{floatingfigure}";
3643 os << "\\end{figure}";
3645 case LyXParagraph::TAB:
3646 os << "\\end{table}";
3648 case LyXParagraph::WIDE_FIG:
3649 os << "\\end{figure*}";
3651 case LyXParagraph::WIDE_TAB:
3652 os << "\\end{table*}";
3654 case LyXParagraph::ALGORITHM:
3655 os << "\\end{algorithm}";
3662 if (footnotekind != LyXParagraph::FOOTNOTE
3663 && footnotekind != LyXParagraph::MARGIN) {
3664 // we need to ensure that real floats like tables and figures
3665 // have their \end{} on a line of their own otherwise we can
3666 // get incorrect results when using the endfloat.sty package.
3671 lyxerr[Debug::LATEX] << "TeXFootnote...done " << par->next << endl;
3676 bool LyXParagraph::IsDummy() const
3678 return (footnoteflag == LyXParagraph::NO_FOOTNOTE && previous
3679 && previous->footnoteflag != LyXParagraph::NO_FOOTNOTE);
3683 void LyXParagraph::SetPExtraType(BufferParams const & bparams,
3684 int type, string const & width,
3685 string const & widthp)
3687 params.pextraType(type);
3688 params.pextraWidth(width);
3689 params.pextraWidthp(widthp);
3691 if (textclasslist.Style(bparams.textclass,
3692 layout).isEnvironment()) {
3693 LyXParagraph * par = this;
3694 LyXParagraph * ppar = par;
3696 while (par && (par->layout == layout)
3697 && (par->params.depth() == params.depth())) {
3699 par = par->Previous();
3702 par = par->FirstPhysicalPar();
3704 while (par && par->params.depth() > params.depth()) {
3705 par = par->Previous();
3708 par = par->FirstPhysicalPar();
3713 while (par && (par->layout == layout)
3714 && (par->params.depth() == params.depth())) {
3715 par->params.pextraType(type);
3716 par->params.pextraWidth(width);
3717 par->params.pextraWidthp(widthp);
3719 par = par->NextAfterFootnote();
3723 if (par && (par->params.depth() > params.depth()))
3724 par->SetPExtraType(bparams,
3725 type, width, widthp);
3727 while (par && ((par->params.depth() > params.depth()) || par->IsDummy()))
3728 par = par->NextAfterFootnote();
3730 while (par && par->params.depth() > params.depth())
3738 void LyXParagraph::UnsetPExtraType(BufferParams const & bparams)
3740 if (params.pextraType() == PEXTRA_NONE)
3743 params.pextraType(PEXTRA_NONE);
3744 params.pextraWidth(string());
3745 params.pextraWidthp(string());
3747 if (textclasslist.Style(bparams.textclass,
3748 layout).isEnvironment()) {
3749 LyXParagraph * par = this;
3750 LyXParagraph * ppar = par;
3752 while (par && (par->layout == layout)
3753 && (par->params.depth() == params.depth())) {
3755 par = par->Previous();
3758 par = par->FirstPhysicalPar();
3760 while (par && par->params.depth() > params.depth()) {
3761 par = par->Previous();
3764 par = par->FirstPhysicalPar();
3769 while (par && (par->layout == layout)
3770 && (par->params.depth() == params.depth())) {
3771 par->params.pextraType(PEXTRA_NONE);
3772 par->params.pextraWidth(string());
3773 par->params.pextraWidthp(string());
3775 par = par->NextAfterFootnote();
3779 if (par && (par->params.depth() > params.depth()))
3780 par->UnsetPExtraType(bparams);
3782 while (par && ((par->params.depth() > params.depth()) || par->IsDummy()))
3783 par = par->NextAfterFootnote();
3785 while (par && par->params.depth() > params.depth())
3793 bool LyXParagraph::IsHfill(size_type pos) const
3795 return IsHfillChar(GetChar(pos));
3799 bool LyXParagraph::IsInset(size_type pos) const
3801 return IsInsetChar(GetChar(pos));
3806 bool LyXParagraph::IsFloat(size_type pos) const
3808 return IsFloatChar(GetChar(pos));
3813 bool LyXParagraph::IsNewline(size_type pos) const
3815 return pos >= 0 && IsNewlineChar(GetChar(pos));
3819 bool LyXParagraph::IsSeparator(size_type pos) const
3821 return IsSeparatorChar(GetChar(pos));
3825 bool LyXParagraph::IsLineSeparator(size_type pos) const
3827 return IsLineSeparatorChar(GetChar(pos));
3831 bool LyXParagraph::IsKomma(size_type pos) const
3833 return IsKommaChar(GetChar(pos));
3837 /// Used by the spellchecker
3838 bool LyXParagraph::IsLetter(LyXParagraph::size_type pos) const
3840 value_type const c = GetChar(pos);
3841 if (IsLetterChar(c))
3843 // '\0' is not a letter, allthough every string contains "" (below)
3846 // We want to pass the ' and escape chars to ispell
3847 string const extra = lyxrc.isp_esc_chars + '\'';
3848 char ch[2] = { c, 0 };
3849 return contains(extra, ch);
3853 bool LyXParagraph::IsWord(size_type pos ) const
3855 return IsWordChar(GetChar(pos)) ;
3860 LyXParagraph::getParLanguage(BufferParams const & bparams) const
3864 return FirstPhysicalPar()->getParLanguage(bparams);
3868 return GetFirstFontSettings().language();
3870 return previous->getParLanguage(bparams);
3872 return bparams.language;
3876 bool LyXParagraph::isRightToLeftPar(BufferParams const & bparams) const
3878 return lyxrc.rtl_support
3879 && getParLanguage(bparams)->RightToLeft();
3883 void LyXParagraph::ChangeLanguage(BufferParams const & bparams,
3884 Language const * from, Language const * to)
3886 for (size_type i = 0; i < size(); ++i) {
3887 LyXFont font = GetFontSettings(bparams, i);
3888 if (font.language() == from) {
3889 font.setLanguage(to);
3896 bool LyXParagraph::isMultiLingual(BufferParams const & bparams)
3898 Language const * doc_language = bparams.language;
3899 for (FontList::const_iterator cit = fontlist.begin();
3900 cit != fontlist.end(); ++cit)
3901 if ((*cit).font().language() != doc_language)
3907 // Convert the paragraph to a string.
3908 // Used for building the table of contents
3909 string const LyXParagraph::String(Buffer const * buffer, bool label)
3911 BufferParams const & bparams = buffer->params;
3914 if (label && !IsDummy() && !params.labelString().empty())
3916 if (label && !params.labelString().empty())
3918 s += params.labelString() + ' ';
3919 string::size_type const len = s.size();
3921 for (LyXParagraph::size_type i = 0; i < size(); ++i) {
3922 value_type c = GetChar(i);
3925 else if (c == META_INSET &&
3926 GetInset(i)->LyxCode() == Inset::MATH_CODE) {
3927 std::ostringstream ost;
3928 GetInset(i)->Ascii(buffer, ost);
3929 s += subst(ost.str().c_str(),'\n',' ');
3934 if (next && next->footnoteflag != LyXParagraph::NO_FOOTNOTE
3935 && footnoteflag == LyXParagraph::NO_FOOTNOTE)
3936 s += NextAfterFootnote()->String(buffer, false);
3940 if (isRightToLeftPar(bparams))
3941 reverse(s.begin() + len,s.end());
3949 string const LyXParagraph::String(Buffer const * buffer,
3950 LyXParagraph::size_type beg,
3951 LyXParagraph::size_type end)
3956 if (beg == 0 && !IsDummy() && !params.labelString().empty())
3958 if (beg == 0 && !params.labelString().empty())
3960 s += params.labelString() + ' ';
3962 for (LyXParagraph::size_type i = beg; i < end; ++i) {
3963 value_type c = GetUChar(buffer->params, i);
3966 else if (c == META_INSET) {
3967 std::ostringstream ost;
3968 GetInset(i)->Ascii(buffer, ost);
3969 s += ost.str().c_str();
3977 void LyXParagraph::SetInsetOwner(Inset * i)
3980 for (InsetList::const_iterator cit = insetlist.begin();
3981 cit != insetlist.end(); ++cit) {
3983 (*cit).inset->setOwner(i);
3988 void LyXParagraph::deleteInsetsLyXText(BufferView * bv)
3991 for (InsetList::const_iterator cit = insetlist.begin();
3992 cit != insetlist.end(); ++cit) {
3994 if ((*cit).inset->IsTextInset()) {
3995 static_cast<UpdatableInset *>
3996 ((*cit).inset)->deleteLyXText(bv);
4003 void LyXParagraph::resizeInsetsLyXText(BufferView * bv)
4006 for (InsetList::const_iterator cit = insetlist.begin();
4007 cit != insetlist.end(); ++cit) {
4009 if ((*cit).inset->IsTextInset()) {
4010 static_cast<UpdatableInset *>
4011 ((*cit).inset)->resizeLyXText(bv);
4018 void LyXParagraph::fitToSize()
4020 TextContainer tmp(text.begin(), text.end());
4025 void LyXParagraph::setContentsFromPar(LyXParagraph * par)