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
127 if (footnoteflag != LyXParagraph::NO_FOOTNOTE ||
129 || previous_->footnoteflag == LyXParagraph::NO_FOOTNOTE) {
130 // The beginning or the end of a footnote environment?
131 if (footflag != footnoteflag) {
132 footflag = footnoteflag;
134 os << "\n\\begin_float "
135 << string_footnotekinds[footnotekind]
138 os << "\n\\end_float ";
142 // The beginning or end of a deeper (i.e. nested) area?
143 if (dth != params.depth()) {
144 if (params.depth() > dth) {
145 while (params.depth() > dth) {
146 os << "\n\\begin_deeper ";
150 while (params.depth() < dth) {
151 os << "\n\\end_deeper ";
157 // First write the layout
159 << textclasslist.NameOfLayout(bparams.textclass, layout)
162 // Maybe some vertical spaces.
163 if (params.spaceTop().kind() != VSpace::NONE)
164 os << "\\added_space_top "
165 << params.spaceTop().asLyXCommand() << " ";
166 if (params.spaceBottom().kind() != VSpace::NONE)
167 os << "\\added_space_bottom "
168 << params.spaceBottom().asLyXCommand() << " ";
170 // Maybe the paragraph has special spacing
171 params.spacing().writeFile(os, true);
173 // The labelwidth string used in lists.
174 if (!params.labelWidthString().empty())
175 os << "\\labelwidthstring "
176 << params.labelWidthString() << '\n';
178 // Lines above or below?
179 if (params.lineTop())
181 if (params.lineBottom())
182 os << "\\line_bottom ";
184 // Pagebreaks above or below?
185 if (params.pagebreakTop())
186 os << "\\pagebreak_top ";
187 if (params.pagebreakBottom())
188 os << "\\pagebreak_bottom ";
190 // Start of appendix?
191 if (params.startOfAppendix())
192 os << "\\start_of_appendix ";
195 if (params.noindent())
199 if (params.align() != LYX_ALIGN_LAYOUT) {
201 switch (params.align()) {
202 case LYX_ALIGN_LEFT: h = 1; break;
203 case LYX_ALIGN_RIGHT: h = 2; break;
204 case LYX_ALIGN_CENTER: h = 3; break;
205 default: h = 0; break;
207 os << "\\align " << string_align[h] << " ";
210 if (params.pextraType() != PEXTRA_NONE) {
211 os << "\\pextra_type " << params.pextraType();
212 if (params.pextraType() == PEXTRA_MINIPAGE) {
213 os << " \\pextra_alignment "
214 << params.pextraAlignment();
215 if (params.pextraHfill())
216 os << " \\pextra_hfill "
217 << params.pextraHfill();
218 if (params.pextraStartMinipage())
219 os << " \\pextra_start_minipage "
220 << params.pextraStartMinipage();
222 if (!params.pextraWidth().empty()) {
223 os << " \\pextra_width "
224 << VSpace(params.pextraWidth()).asLyXCommand();
225 } else if (!params.pextraWidthp().empty()) {
226 os << " \\pextra_widthp "
227 << params.pextraWidthp();
234 // Dummy layout. This means that a footnote ended.
235 os << "\n\\end_float ";
236 footflag = LyXParagraph::NO_FOOTNOTE;
242 bibkey->Write(buf, os);
244 LyXFont font1(LyXFont::ALL_INHERIT, bparams.language);
247 for (size_type i = 0; i < size(); ++i) {
253 // Write font changes
254 LyXFont font2 = GetFontSettings(bparams, i);
255 if (font2 != font1) {
256 font2.lyxWriteChanges(font1, os);
261 value_type const c = GetChar(i);
265 Inset const * inset = GetInset(i);
267 if (inset->DirectWrite()) {
268 // international char, let it write
269 // code directly so it's shorter in
271 inset->Write(buf, os);
273 os << "\n\\begin_inset ";
274 inset->Write(buf, os);
275 os << "\n\\end_inset \n\n";
281 os << "\n\\newline \n";
285 os << "\n\\hfill \n";
289 os << "\n\\backslash \n";
293 if (i + 1 < size() && GetChar(i + 1) == ' ') {
300 if ((column > 70 && c == ' ')
305 // this check is to amend a bug. LyX sometimes
306 // inserts '\0' this could cause problems.
310 lyxerr << "ERROR (LyXParagraph::writeFile):"
311 " NULL char in structure." << endl;
317 // now write the next paragraph
319 next_->writeFile(buf, os, bparams, footflag, dth);
323 void LyXParagraph::validate(LaTeXFeatures & features) const
325 BufferParams const & bparams = features.bufferParams();
328 // this will be useful later
329 LyXLayout const & layout =
330 textclasslist.Style(bparams.textclass,
335 if (params.lineTop() || params.lineBottom())
336 features.lyxline = true;
337 if (!params.spacing().isDefault())
338 features.setspace = true;
341 features.layout[GetLayout()] = true;
344 Language const * doc_language = bparams.language;
346 for (FontList::const_iterator cit = fontlist.begin();
347 cit != fontlist.end(); ++cit) {
348 if ((*cit).font().noun() == LyXFont::ON) {
349 lyxerr[Debug::LATEX] << "font.noun: "
350 << (*cit).font().noun()
352 features.noun = true;
353 lyxerr[Debug::LATEX] << "Noun enabled. Font: "
354 << (*cit).font().stateText(0)
357 switch ((*cit).font().color()) {
359 case LColor::inherit:
363 features.color = true;
364 lyxerr[Debug::LATEX] << "Color enabled. Font: "
365 << (*cit).font().stateText(0)
369 Language const * language = (*cit).font().language();
370 if (language->babel() != doc_language->babel()) {
371 features.UsedLanguages.insert(language);
372 lyxerr[Debug::LATEX] << "Found language "
373 << language->babel() << endl;
378 for (InsetList::const_iterator cit = insetlist.begin();
379 cit != insetlist.end(); ++cit) {
381 (*cit).inset->Validate(features);
385 if (params.pextraType() == PEXTRA_INDENT)
386 features.LyXParagraphIndent = true;
387 if (params.pextraType() == PEXTRA_FLOATFLT)
388 features.floatflt = true;
391 if (layout.needprotect
392 && next_ && next_->footnoteflag != LyXParagraph::NO_FOOTNOTE)
393 features.NeedLyXFootnoteCode = true;
396 if (bparams.paragraph_separation == BufferParams::PARSEP_INDENT
397 && params.pextraType() == LyXParagraph::PEXTRA_MINIPAGE)
398 features.NeedLyXMinipageIndent = true;
401 if (footnoteflag != NO_FOOTNOTE && footnotekind == ALGORITHM)
402 features.algorithm = true;
407 // First few functions needed for cut and paste and paragraph breaking.
408 void LyXParagraph::CopyIntoMinibuffer(Buffer const & buffer,
409 LyXParagraph::size_type pos) const
411 BufferParams bparams = buffer.params;
413 minibuffer_char = GetChar(pos);
414 minibuffer_font = GetFontSettings(bparams, pos);
415 minibuffer_inset = 0;
416 if (minibuffer_char == LyXParagraph::META_INSET) {
418 minibuffer_inset = GetInset(pos)->Clone(buffer);
420 minibuffer_inset = 0;
421 minibuffer_char = ' ';
422 // This reflects what GetInset() does (ARRae)
428 void LyXParagraph::CutIntoMinibuffer(BufferParams const & bparams,
429 LyXParagraph::size_type pos)
431 minibuffer_char = GetChar(pos);
432 minibuffer_font = GetFontSettings(bparams, pos);
433 minibuffer_inset = 0;
434 if (minibuffer_char == LyXParagraph::META_INSET) {
436 minibuffer_inset = GetInset(pos);
437 // This is a little hack since I want exactly
438 // the inset, not just a clone. Otherwise
439 // the inset would be deleted when calling Erase(pos)
441 InsetTable search_elem(pos, 0);
442 InsetList::iterator it =
443 lower_bound(insetlist.begin(),
445 search_elem, matchIT());
446 if (it != insetlist.end() && (*it).pos == pos)
449 minibuffer_inset = 0;
450 minibuffer_char = ' ';
451 // This reflects what GetInset() does (ARRae)
456 // Erase(pos); now the caller is responsible for that.
460 bool LyXParagraph::InsertFromMinibuffer(LyXParagraph::size_type pos)
462 if ((minibuffer_char == LyXParagraph::META_INSET) &&
463 !InsertInsetAllowed(minibuffer_inset))
465 if (minibuffer_char == LyXParagraph::META_INSET)
466 InsertInset(pos, minibuffer_inset, minibuffer_font);
468 InsertChar(pos, minibuffer_char, minibuffer_font);
476 void LyXParagraph::Clear()
485 // the destructor removes the new paragraph from the list
486 LyXParagraph::~LyXParagraph()
489 previous_->next_ = next_;
491 next_->previous_ = previous_;
493 for (InsetList::iterator it = insetlist.begin();
494 it != insetlist.end(); ++it) {
501 //lyxerr << "LyXParagraph::paragraph_id = "
502 // << LyXParagraph::paragraph_id << endl;
506 void LyXParagraph::Erase(LyXParagraph::size_type pos)
509 // > because last is the next unused position, and you can
510 // use it if you want
512 if (next_ && next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
513 NextAfterFootnote()->Erase(pos - text.size() - 1);
515 lyxerr.debug() << "ERROR (LyXParagraph::Erase): "
516 "position does not exist." << endl;
520 Assert(pos < size());
523 if (pos < size()) { // last is free for insertation, but should be empty
525 // if it is an inset, delete the inset entry
526 if (text[pos] == LyXParagraph::META_INSET) {
528 InsetTable search_inset(pos, 0);
529 InsetList::iterator it =
530 lower_bound(insetlist.begin(),
532 search_inset, matchIT());
533 if (it != insetlist.end() && (*it).pos == pos) {
539 text.erase(text.begin() + pos);
541 // Erase entries in the tables.
542 FontTable search_font(pos, LyXFont());
544 FontList::iterator it =
545 lower_bound(fontlist.begin(),
547 search_font, matchFT());
548 if (it != fontlist.end() && (*it).pos() == pos &&
550 (it != fontlist.begin() && (*(it - 1)).pos() == pos - 1))) {
551 // If it is a multi-character font
552 // entry, we just make it smaller
553 // (see update below), otherwise we
555 unsigned int const i = it - fontlist.begin();
556 fontlist.erase(fontlist.begin() + i);
557 it = fontlist.begin() + i;
558 if (i > 0 && i < fontlist.size() &&
559 fontlist[i - 1].font() == fontlist[i].font()) {
560 fontlist.erase(fontlist.begin() + i - 1);
561 it = fontlist.begin() + i - 1;
565 // Update all other entries.
566 FontList::iterator fend = fontlist.end();
567 for (; it != fend; ++it)
568 (*it).pos((*it).pos() - 1);
570 // Update the inset table.
571 InsetTable search_inset(pos, 0);
572 InsetList::iterator lend = insetlist.end();
573 for (InsetList::iterator it =
574 upper_bound(insetlist.begin(),
576 search_inset, matchIT());
581 lyxerr << "ERROR (LyXParagraph::Erase): "
582 "can't erase non-existant char." << endl;
588 void LyXParagraph::InsertChar(LyXParagraph::size_type pos,
589 LyXParagraph::value_type c)
591 LyXFont const f(LyXFont::ALL_INHERIT);
592 InsertChar(pos, c, f);
596 void LyXParagraph::InsertChar(LyXParagraph::size_type pos,
597 LyXParagraph::value_type c,
598 LyXFont const & font)
601 // > because last is the next unused position, and you can
602 // use it if you want
605 && next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
606 NextAfterFootnote()->InsertChar(pos - text.size() - 1,
609 lyxerr.debug() << "ERROR (LyXParagraph::InsertChar): "
610 "position does not exist." << endl;
614 Assert(pos <= size());
616 text.insert(text.begin() + pos, c);
618 // Update the font table.
619 FontTable search_font(pos, LyXFont());
620 for (FontList::iterator it = lower_bound(fontlist.begin(),
622 search_font, matchFT());
623 it != fontlist.end(); ++it)
624 (*it).pos((*it).pos() + 1);
626 // Update the inset table.
627 InsetTable search_inset(pos, 0);
628 for (InsetList::iterator it = lower_bound(insetlist.begin(),
630 search_inset, matchIT());
631 it != insetlist.end(); ++it)
638 void LyXParagraph::InsertInset(LyXParagraph::size_type pos,
641 LyXFont const f(LyXFont::ALL_INHERIT);
642 InsertInset(pos, inset, f);
646 void LyXParagraph::InsertInset(LyXParagraph::size_type pos,
647 Inset * inset, LyXFont const & font)
652 // > because last is the next unused position, and you can
653 // use it if you want
656 && next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
658 ->InsertInset(pos - text.size() - 1,
661 lyxerr << "ERROR (LyXParagraph::InsertInset): "
662 "position does not exist: " << pos << endl;
666 Assert(pos <= size());
669 InsertChar(pos, META_INSET, font);
670 Assert(text[pos] == META_INSET);
672 // Add a new entry in the inset table.
673 InsetTable search_inset(pos, 0);
674 InsetList::iterator it = lower_bound(insetlist.begin(),
676 search_inset, matchIT());
677 if (it != insetlist.end() && (*it).pos == pos)
678 lyxerr << "ERROR (LyXParagraph::InsertInset): "
679 "there is an inset in position: " << pos << endl;
681 insetlist.insert(it, InsetTable(pos, inset));
683 inset->setOwner(inset_owner);
687 bool LyXParagraph::InsertInsetAllowed(Inset * inset)
689 //lyxerr << "LyXParagraph::InsertInsetAllowed" << endl;
692 return inset_owner->InsertInsetAllowed(inset);
697 Inset * LyXParagraph::GetInset(LyXParagraph::size_type pos)
702 && next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
703 return NextAfterFootnote()
704 ->GetInset(pos - text.size() - 1);
706 lyxerr << "ERROR (LyXParagraph::GetInset): "
707 "position does not exist: "
713 Assert(pos < size());
716 InsetTable search_inset(pos, 0);
717 InsetList::iterator it = lower_bound(insetlist.begin(),
719 search_inset, matchIT());
720 if (it != insetlist.end() && (*it).pos == pos)
723 lyxerr << "ERROR (LyXParagraph::GetInset): "
724 "Inset does not exist: " << pos << endl;
727 // text[pos] = ' '; // WHY!!! does this set the pos to ' '????
728 // Did this commenting out introduce a bug? So far I have not
729 // see any, please enlighten me. (Lgb)
730 // My guess is that since the inset does not exist, we might
731 // as well replace it with a space to prevent craches. (Asger)
736 Inset const * LyXParagraph::GetInset(LyXParagraph::size_type pos) const
741 && next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
742 return NextAfterFootnote()
743 ->GetInset(pos - text.size() - 1);
745 lyxerr << "ERROR (LyXParagraph::GetInset): "
746 "position does not exist: "
752 Assert(pos < size());
755 InsetTable search_inset(pos, 0);
756 InsetList::const_iterator cit = lower_bound(insetlist.begin(),
758 search_inset, matchIT());
759 if (cit != insetlist.end() && (*cit).pos == pos)
762 lyxerr << "ERROR (LyXParagraph::GetInset): "
763 "Inset does not exist: " << pos << endl;
765 //text[pos] = ' '; // WHY!!! does this set the pos to ' '????
766 // Did this commenting out introduce a bug? So far I have not
767 // see any, please enlighten me. (Lgb)
768 // My guess is that since the inset does not exist, we might
769 // as well replace it with a space to prevent craches. (Asger)
774 // Gets uninstantiated font setting at position.
775 // Optimized after profiling. (Asger)
776 LyXFont const LyXParagraph::GetFontSettings(BufferParams const & bparams,
777 LyXParagraph::size_type pos) const
780 Assert(pos <= size());
785 FontTable search_font(pos, LyXFont());
786 FontList::const_iterator cit = lower_bound(fontlist.begin(),
788 search_font, matchFT());
789 if (cit != fontlist.end())
790 return (*cit).font();
795 // > because last is the next unused position, and you can
796 // use it if you want
797 else if (pos > size()) {
799 && next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
800 return NextAfterFootnote()
801 ->GetFontSettings(bparams,
802 pos - text.size() - 1);
804 // Why is it an error to ask for the font of a
805 // position that does not exist? Would it be
806 // enough for this to be enabled on debug?
807 // We want strict error checking, but it's ok to only
808 // have it when debugging. (Asger)
809 lyxerr << "ERROR (LyXParagraph::GetFontSettings): "
810 "position does not exist. "
811 << pos << " (" << static_cast<int>(pos)
813 } else if (pos > 0) {
814 return GetFontSettings(bparams, pos - 1);
817 if (pos == size() && size())
818 return GetFontSettings(bparams, pos - 1);
822 return LyXFont(LyXFont::ALL_INHERIT, getParLanguage(bparams));
824 //return LyXFont(LyXFont::ALL_INHERIT);
828 // Gets uninstantiated font setting at position 0
829 LyXFont const LyXParagraph::GetFirstFontSettings() const
832 if (!fontlist.empty())
833 return fontlist[0].font();
837 else if (next_ && next_->footnoteflag != LyXParagraph::NO_FOOTNOTE)
838 return NextAfterFootnote()->GetFirstFontSettings();
840 return LyXFont(LyXFont::ALL_INHERIT);
844 // Gets the fully instantiated font at a given position in a paragraph
845 // This is basically the same function as LyXText::GetFont() in text2.C.
846 // The difference is that this one is used for generating the LaTeX file,
847 // and thus cosmetic "improvements" are disallowed: This has to deliver
848 // the true picture of the buffer. (Asger)
849 // If position is -1, we get the layout font of the paragraph.
850 // If position is -2, we get the font of the manual label of the paragraph.
851 LyXFont const LyXParagraph::getFont(BufferParams const & bparams,
852 LyXParagraph::size_type pos) const
855 LyXLayout const & layout =
856 textclasslist.Style(bparams.textclass,
858 LyXParagraph::size_type main_body = 0;
859 if (layout.labeltype == LABEL_MANUAL)
860 main_body = BeginningOfMainBody();
865 layoutfont = layout.labelfont;
867 layoutfont = layout.font;
868 tmpfont = GetFontSettings(bparams, pos);
869 tmpfont.realize(layoutfont);
871 // process layoutfont for pos == -1 and labelfont for pos < -1
873 tmpfont = layout.font;
875 tmpfont = layout.labelfont;
876 tmpfont.setLanguage(getParLanguage(bparams));
879 // check for environment font information
880 char par_depth = GetDepth();
881 LyXParagraph const * par = this;
882 while (par && par_depth && !tmpfont.resolved()) {
883 par = par->DepthHook(par_depth - 1);
885 tmpfont.realize(textclasslist.
886 Style(bparams.textclass,
887 par->GetLayout()).font);
888 par_depth = par->GetDepth();
892 tmpfont.realize(textclasslist
893 .TextClass(bparams.textclass)
899 /// Returns the height of the highest font in range
901 LyXParagraph::HighestFontInRange(LyXParagraph::size_type startpos,
902 LyXParagraph::size_type endpos) const
904 LyXFont::FONT_SIZE maxsize = LyXFont::SIZE_TINY;
905 if (fontlist.empty())
908 FontTable end_search(endpos, LyXFont());
909 FontList::const_iterator end_it = lower_bound(fontlist.begin(),
911 end_search, matchFT());
912 if (end_it != fontlist.end())
915 FontTable start_search(startpos, LyXFont());
916 for (FontList::const_iterator cit =
917 lower_bound(fontlist.begin(),
919 start_search, matchFT());
920 cit != end_it; ++cit) {
921 LyXFont::FONT_SIZE size = (*cit).font().size();
922 if (size > maxsize && size <= LyXFont::SIZE_HUGER)
929 LyXParagraph::value_type
930 LyXParagraph::GetChar(LyXParagraph::size_type pos) const
935 Assert(pos <= size());
936 if (!size() || pos == size()) return '\0';
947 // > because last is the next unused position, and you can
948 // use it if you want
949 else if (pos > size()) {
950 if (next_ && next_->footnoteflag != LyXParagraph::NO_FOOTNOTE)
951 return NextAfterFootnote()
952 ->GetChar(pos - text.size() - 1);
955 lyxerr << "ERROR (LyXParagraph::GetChar const): "
956 "position does not exist."
957 << pos << " (" << static_cast<int>(pos)
963 // We should have a footnote environment.
964 if (!next_ || next_->footnoteflag == LyXParagraph::NO_FOOTNOTE) {
965 // Notice that LyX does request the
966 // last char from time to time. (Asger)
967 //lyxerr << "ERROR (LyXParagraph::GetChar): "
968 // "expected footnote." << endl;
971 switch (next_->footnotekind) {
972 case LyXParagraph::FOOTNOTE:
973 return LyXParagraph::META_FOOTNOTE;
974 case LyXParagraph::MARGIN:
975 return LyXParagraph::META_MARGIN;
976 case LyXParagraph::FIG:
977 case LyXParagraph::WIDE_FIG:
978 return LyXParagraph::META_FIG;
979 case LyXParagraph::TAB:
980 case LyXParagraph::WIDE_TAB:
981 return LyXParagraph::META_TAB;
982 case LyXParagraph::ALGORITHM:
983 return LyXParagraph::META_ALGORITHM;
985 return '\0'; // to shut up gcc
991 LyXParagraph::value_type
992 LyXParagraph::GetUChar(BufferParams const & bparams,
993 LyXParagraph::size_type pos) const
995 value_type c = GetChar(pos);
996 if (!lyxrc.rtl_support)
1026 if (uc != c && GetFontSettings(bparams, pos).isRightToLeft())
1032 // return an string of the current word, and the end of the word in lastpos.
1033 string const LyXParagraph::GetWord(LyXParagraph::size_type & lastpos) const
1035 Assert(lastpos >= 0);
1037 // the current word is defined as starting at the first character
1038 // from the immediate left of lastpospos which meets the definition
1039 // of IsLetter(), continuing to the last character to the right
1040 // of this meeting IsLetter.
1046 // move back until we have a letter
1048 //there's no real reason to have firstpos & lastpos as
1049 //separate variables as this is written, but maybe someon
1050 // will want to return firstpos in the future.
1052 //since someone might have typed a punctuation first
1053 int firstpos = lastpos;
1055 while ((firstpos >= 0) && !IsLetter(firstpos))
1058 // now find the beginning by looking for a nonletter
1060 while ((firstpos>= 0) && IsLetter(firstpos))
1063 // the above is now pointing to the preceeding non-letter
1067 // so copy characters into theword until we get a nonletter
1068 // note that this can easily exceed lastpos, wich means
1069 // that if used in the middle of a word, the whole word
1072 while (IsLetter(lastpos)) theword += GetChar(lastpos++);
1080 LyXParagraph::size_type LyXParagraph::Last() const
1082 if (next_ && next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1083 return text.size() + NextAfterFootnote()->Last() + 1;
1084 // the 1 is the symbol
1093 LyXParagraph * LyXParagraph::ParFromPos(LyXParagraph::size_type pos)
1095 // > because last is the next unused position, and you can
1096 // use it if you want
1099 && next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1100 return NextAfterFootnote()
1101 ->ParFromPos(pos - text.size() - 1);
1103 lyxerr << "ERROR (LyXParagraph::ParFromPos): "
1104 "position does not exist." << endl;
1113 int LyXParagraph::PositionInParFromPos(LyXParagraph::size_type pos) const
1115 // > because last is the next unused position, and you can
1116 // use it if you want
1119 && next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1120 return NextAfterFootnote()
1121 ->PositionInParFromPos(pos - text.size() - 1);
1124 "ERROR (LyXParagraph::PositionInParFromPos): "
1125 "position does not exist." << endl;
1134 void LyXParagraph::SetFont(LyXParagraph::size_type pos,
1135 LyXFont const & font)
1138 // > because last is the next unused position, and you can
1139 // use it if you want
1142 next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1143 NextAfterFootnote()->SetFont(pos - text.size() - 1,
1146 lyxerr << "ERROR (LyXParagraph::SetFont): "
1147 "position does not exist." << endl;
1152 Assert(pos <= size());
1155 // First, reduce font against layout/label font
1156 // Update: The SetCharFont() routine in text2.C already
1157 // reduces font, so we don't need to do that here. (Asger)
1158 // No need to simplify this because it will disappear
1159 // in a new kernel. (Asger)
1160 // Next search font table
1162 FontTable search_font(pos, LyXFont());
1163 FontList::iterator it = lower_bound(fontlist.begin(),
1165 search_font, matchFT());
1166 unsigned int i = it - fontlist.begin();
1167 bool notfound = it == fontlist.end();
1169 if (!notfound && fontlist[i].font() == font)
1172 bool begin = pos == 0 || notfound ||
1173 (i > 0 && fontlist[i-1].pos() == pos - 1);
1174 // Is position pos is a beginning of a font block?
1175 bool end = !notfound && fontlist[i].pos() == pos;
1176 // Is position pos is the end of a font block?
1177 if (begin && end) { // A single char block
1178 if (i + 1 < fontlist.size() &&
1179 fontlist[i + 1].font() == font) {
1180 // Merge the singleton block with the next block
1181 fontlist.erase(fontlist.begin() + i);
1182 if (i > 0 && fontlist[i - 1].font() == font)
1183 fontlist.erase(fontlist.begin() + i-1);
1184 } else if (i > 0 && fontlist[i - 1].font() == font) {
1185 // Merge the singleton block with the previous block
1186 fontlist[i - 1].pos(pos);
1187 fontlist.erase(fontlist.begin() + i);
1189 fontlist[i].font(font);
1191 if (i > 0 && fontlist[i - 1].font() == font)
1192 fontlist[i - 1].pos(pos);
1194 fontlist.insert(fontlist.begin() + i,
1195 FontTable(pos, font));
1197 fontlist[i].pos(pos - 1);
1198 if (!(i + 1 < fontlist.size() &&
1199 fontlist[i + 1].font() == font))
1200 fontlist.insert(fontlist.begin() + i + 1,
1201 FontTable(pos, font));
1202 } else { // The general case. The block is splitted into 3 blocks
1203 fontlist.insert(fontlist.begin() + i,
1204 FontTable(pos - 1, fontlist[i].font()));
1205 fontlist.insert(fontlist.begin() + i + 1,
1206 FontTable(pos, font));
1212 void LyXParagraph::next(LyXParagraph * p)
1218 // This function is able to hide closed footnotes.
1219 LyXParagraph * LyXParagraph::next()
1222 if (next_ && next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1223 LyXParagraph * tmp = next_;
1225 && tmp->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1227 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1228 return tmp->next(); /* there can be more than one
1229 footnote in a logical
1232 return next_; // This should never happen!
1239 LyXParagraph const * LyXParagraph::next() const
1242 if (next_ && next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1243 LyXParagraph * tmp = next_;
1245 && tmp->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1247 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1248 return tmp->next(); /* there can be more than one
1249 footnote in a logical
1252 return next_; // This should never happen!
1260 LyXParagraph * LyXParagraph::NextAfterFootnote()
1262 if (next_ && next_->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1263 LyXParagraph * tmp = next_;
1264 while (tmp && tmp->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1266 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1267 return tmp; /* there can be more than one footnote
1268 in a logical paragraph */
1270 return next_; // This should never happen!
1278 LyXParagraph const * LyXParagraph::NextAfterFootnote() const
1280 if (next_ && next_->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1281 LyXParagraph * tmp = next_;
1282 while (tmp && tmp->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1284 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1285 return tmp; /* there can be more than one footnote
1286 in a logical paragraph */
1288 return next_; // This should never happen!
1296 LyXParagraph * LyXParagraph::PreviousBeforeFootnote()
1299 if (previous_ && previous_->footnoteflag != LyXParagraph::NO_FOOTNOTE) {
1301 while (tmp && tmp->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1302 tmp = tmp->previous_;
1303 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1304 return tmp; /* there can be more than one footnote
1305 in a logical paragraph */
1307 return previous_; // This should never happen!
1315 LyXParagraph * LyXParagraph::LastPhysicalPar()
1317 if (footnoteflag != LyXParagraph::NO_FOOTNOTE)
1320 LyXParagraph * tmp = this;
1322 && tmp->next_->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1323 tmp = tmp->NextAfterFootnote();
1331 LyXParagraph const * LyXParagraph::LastPhysicalPar() const
1333 if (footnoteflag != LyXParagraph::NO_FOOTNOTE)
1336 LyXParagraph const * tmp = this;
1338 && tmp->next_->footnoteflag != LyXParagraph::NO_FOOTNOTE)
1339 tmp = tmp->NextAfterFootnote();
1347 LyXParagraph * LyXParagraph::FirstPhysicalPar()
1351 LyXParagraph * tmppar = this;
1355 || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE))
1356 tmppar = tmppar->previous_;
1367 LyXParagraph const * LyXParagraph::FirstPhysicalPar() const
1371 LyXParagraph const * tmppar = this;
1375 || tmppar->footnoteflag != LyXParagraph::NO_FOOTNOTE))
1376 tmppar = tmppar->previous_;
1386 void LyXParagraph::previous(LyXParagraph * p)
1392 // This function is able to hide closed footnotes.
1393 LyXParagraph * LyXParagraph::previous()
1396 LyXParagraph * tmp = previous_;
1401 && tmp->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1402 tmp = tmp->previous_;
1404 && tmp->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1405 tmp = tmp->previous_;
1406 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1407 return tmp->next_->previous();
1417 // This function is able to hide closed footnotes.
1418 LyXParagraph const * LyXParagraph::previous() const
1421 LyXParagraph * tmp = previous_;
1425 && tmp->previous_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1426 tmp = tmp->previous_;
1428 && tmp->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE)
1429 tmp = tmp->previous_;
1430 if (tmp && tmp->footnoteflag != LyXParagraph::CLOSED_FOOTNOTE)
1431 return tmp->next_->previous();
1441 void LyXParagraph::BreakParagraph(BufferParams const & bparams,
1442 LyXParagraph::size_type pos,
1447 // create a new paragraph
1450 size_type pos_first;
1451 LyXParagraph * par = ParFromPos(pos);
1452 LyXParagraph * firstpar = FirstPhysicalPar();
1454 LyXParagraph * tmp = new LyXParagraph(par);
1456 //LyXParagraph * par = this;
1457 //LyXParagraph * firstpar = this;
1458 LyXParagraph * tmp = new LyXParagraph(this);
1462 tmp->footnoteflag = footnoteflag;
1463 tmp->footnotekind = footnotekind;
1465 // this is an idea for a more userfriendly layout handling, I will
1466 // see what the users say
1469 // layout stays the same with latex-environments
1471 tmp->SetOnlyLayout(bparams, firstpar->layout);
1472 tmp->SetLabelWidthString(firstpar->params.labelWidthString());
1475 // layout stays the same with latex-environments
1477 tmp->SetOnlyLayout(bparams, layout);
1478 tmp->SetLabelWidthString(params.labelWidthString());
1482 if (Last() > pos || !Last() || flag == 2) {
1483 tmp->SetOnlyLayout(bparams, firstpar->layout);
1484 tmp->params.align(firstpar->params.align());
1485 tmp->SetLabelWidthString(firstpar->params.labelWidthString());
1487 tmp->params.lineBottom(firstpar->params.lineBottom());
1488 firstpar->params.lineBottom(false);
1489 tmp->params.pagebreakBottom(firstpar->params.pagebreakBottom());
1490 firstpar->params.pagebreakBottom(false);
1491 tmp->params.spaceBottom(firstpar->params.spaceBottom());
1492 firstpar->params.spaceBottom(VSpace(VSpace::NONE));
1494 tmp->params.depth(firstpar->params.depth());
1495 tmp->params.noindent(firstpar->params.noindent());
1497 if (size() > pos || !size() || flag == 2) {
1498 tmp->SetOnlyLayout(bparams, layout);
1499 tmp->params.align(params.align());
1500 tmp->SetLabelWidthString(params.labelWidthString());
1502 tmp->params.lineBottom(params.lineBottom());
1503 params.lineBottom(false);
1504 tmp->params.pagebreakBottom(params.pagebreakBottom());
1505 params.pagebreakBottom(false);
1506 tmp->params.spaceBottom(params.spaceBottom());
1507 params.spaceBottom(VSpace(VSpace::NONE));
1509 tmp->params.depth(params.depth());
1510 tmp->params.noindent(params.noindent());
1512 // copy everything behind the break-position
1513 // to the new paragraph
1516 while (ParFromPos(pos_first) != par)
1518 pos_end = pos_first + par->text.size() - 1;
1521 for (i = j = pos; i <= pos_end; ++i) {
1522 par->CutIntoMinibuffer(bparams, i - pos_first);
1523 if (tmp->InsertFromMinibuffer(j - pos))
1529 for (i = pos_end; i >= pos; --i)
1530 par->Erase(i - pos_first);
1534 size_type pos_end = text.size() - 1;
1536 for (i = j = pos; i <= pos_end; ++i) {
1537 CutIntoMinibuffer(bparams, i);
1538 if (tmp->InsertFromMinibuffer(j - pos))
1542 for (i = pos_end; i >= pos; --i)
1550 // just an idea of me
1552 tmp->params.lineTop(firstpar->params.lineTop());
1553 tmp->params.pagebreakTop(firstpar->params.pagebreakTop());
1554 tmp->params.spaceTop(firstpar->params.spaceTop());
1555 tmp->bibkey = firstpar->bibkey;
1557 // layout stays the same with latex-environments
1559 firstpar->SetOnlyLayout(bparams, tmp->layout);
1560 firstpar->SetLabelWidthString(tmp->params.labelWidthString());
1561 firstpar->params.depth(tmp->params.depth());
1565 // just an idea of me
1567 tmp->params.lineTop(params.lineTop());
1568 tmp->params.pagebreakTop(params.pagebreakTop());
1569 tmp->params.spaceTop(params.spaceTop());
1570 tmp->bibkey = bibkey;
1572 // layout stays the same with latex-environments
1574 SetOnlyLayout(bparams, tmp->layout);
1575 SetLabelWidthString(tmp->params.labelWidthString());
1576 params.depth(tmp->params.depth());
1583 void LyXParagraph::MakeSameLayout(LyXParagraph const * par)
1586 par = par->FirstPhysicalPar();
1587 footnoteflag = par->footnoteflag;
1588 footnotekind = par->footnotekind;
1590 layout = par->layout;
1591 params.makeSame(par->params);
1593 // This can be changed after NEW_INSETS is in effect. (Lgb)
1594 SetLabelWidthString(par->params.labelWidthString());
1599 LyXParagraph * LyXParagraph::FirstSelfrowPar()
1601 LyXParagraph * tmppar = this;
1604 && tmppar->previous_->footnoteflag ==
1605 LyXParagraph::CLOSED_FOOTNOTE)
1606 || tmppar->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE))
1607 tmppar = tmppar->previous_;
1610 return this; // This should never happen!
1617 int LyXParagraph::StripLeadingSpaces(LyXTextClassList::size_type tclass)
1619 if (textclasslist.Style(tclass, GetLayout()).free_spacing)
1629 && (IsNewline(0) || IsLineSeparator(0))){
1640 LyXParagraph * LyXParagraph::Clone() const
1642 // create a new paragraph
1643 LyXParagraph * result = new LyXParagraph;
1645 result->MakeSameLayout(this);
1647 // this is because of the dummy layout of the paragraphs that
1649 result->layout = layout;
1651 result->inset_owner = inset_owner;
1655 result->bibkey = static_cast<InsetBibKey *>
1656 (bibkey->Clone(*current_view->buffer()));
1660 // copy everything behind the break-position to the new paragraph
1662 result->text = text;
1663 result->fontlist = fontlist;
1664 result->insetlist = insetlist;
1665 for (InsetList::iterator it = result->insetlist.begin();
1666 it != result->insetlist.end(); ++it)
1667 (*it).inset = (*it).inset->Clone(*current_view->buffer());
1672 bool LyXParagraph::HasSameLayout(LyXParagraph const * par) const
1675 par = par->FirstPhysicalPar();
1680 par->footnoteflag == footnoteflag &&
1681 par->footnotekind == footnotekind &&
1683 par->layout == layout &&
1684 params.sameLayout(par->params);
1688 void LyXParagraph::BreakParagraphConservative(BufferParams const & bparams,
1689 LyXParagraph::size_type pos)
1692 // create a new paragraph
1693 LyXParagraph * par = ParFromPos(pos);
1695 LyXParagraph * tmp = new LyXParagraph(par);
1697 tmp->MakeSameLayout(par);
1699 // When can pos < Last()?
1700 // I guess pos == Last() is possible.
1702 // copy everything behind the break-position to the new
1704 size_type pos_first = 0;
1705 while (ParFromPos(pos_first) != par)
1707 size_type pos_end = pos_first + par->text.size() - 1;
1710 for (i = j = pos; i <= pos_end; ++i) {
1711 par->CutIntoMinibuffer(bparams, i - pos_first);
1712 if (tmp->InsertFromMinibuffer(j - pos))
1718 for (size_type i = pos_end; i >= pos; --i)
1719 par->Erase(i - pos_first);
1724 // create a new paragraph
1725 LyXParagraph * tmp = new LyXParagraph(this);
1726 tmp->MakeSameLayout(this);
1728 // When can pos > Last()?
1729 // I guess pos == Last() is possible.
1731 // copy everything behind the break-position to the new
1733 size_type pos_end = text.size() - 1;
1736 for (i = j = pos; i <= pos_end; ++i) {
1737 CutIntoMinibuffer(bparams, i);
1738 if (tmp->InsertFromMinibuffer(j - pos))
1744 for (size_type i = pos_end; i >= pos; --i)
1753 // Be carefull, this does not make any check at all.
1754 // This method has wrong name, it combined this par with the next par.
1755 // In that sense it is the reverse of break paragraph. (Lgb)
1756 void LyXParagraph::PasteParagraph(BufferParams const & bparams)
1758 // copy the next paragraph to this one
1759 LyXParagraph * the_next = next();
1761 // first the DTP-stuff
1763 LyXParagraph * firstpar = FirstPhysicalPar();
1764 firstpar->params.lineBottom(the_next->params.lineBottom());
1765 firstpar->params.spaceBottom(the_next->params.spaceBottom());
1766 firstpar->params.pagebreakBottom(the_next->params.pagebreakBottom());
1768 size_type pos_end = the_next->text.size() - 1;
1769 size_type pos_insert = Last();
1771 params.lineBottom(the_next->params.lineBottom());
1772 params.spaceBottom(the_next->params.spaceBottom());
1773 params.pagebreakBottom(the_next->params.pagebreakBottom());
1775 size_type pos_end = the_next->text.size() - 1;
1776 size_type pos_insert = size();
1779 // ok, now copy the paragraph
1781 for (i = j = 0; i <= pos_end; ++i) {
1782 the_next->CutIntoMinibuffer(bparams, i);
1783 if (InsertFromMinibuffer(pos_insert + j))
1787 // delete the next paragraph
1788 LyXParagraph * ppar = the_next->previous_;
1789 LyXParagraph * npar = the_next->next_;
1796 void LyXParagraph::OpenFootnote(LyXParagraph::size_type pos)
1798 LyXParagraph * par = ParFromPos(pos);
1800 while (par && par->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
1801 par->footnoteflag = LyXParagraph::OPEN_FOOTNOTE;
1807 void LyXParagraph::CloseFootnote(LyXParagraph::size_type pos)
1809 LyXParagraph * par = ParFromPos(pos);
1811 while (par && par->footnoteflag == LyXParagraph::OPEN_FOOTNOTE) {
1812 par->footnoteflag = LyXParagraph::CLOSED_FOOTNOTE;
1819 int LyXParagraph::GetEndLabel(BufferParams const & bparams) const
1821 LyXParagraph const * par = this;
1822 int par_depth = GetDepth();
1824 LyXTextClass::LayoutList::size_type layout = par->GetLayout();
1825 int const endlabeltype =
1826 textclasslist.Style(bparams.textclass,
1827 layout).endlabeltype;
1828 if (endlabeltype != END_LABEL_NO_LABEL) {
1829 LyXParagraph const * last = this;
1831 if (footnoteflag == NO_FOOTNOTE)
1832 last = LastPhysicalPar();
1833 else if (next_->footnoteflag == NO_FOOTNOTE)
1834 return endlabeltype;
1839 if (!last || !last->next_)
1840 return endlabeltype;
1842 int next_depth = last->next_->GetDepth();
1843 if (par_depth > next_depth ||
1844 (par_depth == next_depth && layout != last->next_->GetLayout() ))
1845 return endlabeltype;
1850 par = par->DepthHook(par_depth - 1);
1852 par_depth = par->GetDepth();
1854 return END_LABEL_NO_LABEL;
1858 LyXTextClass::size_type LyXParagraph::GetLayout() const
1861 return FirstPhysicalPar()->layout;
1868 char LyXParagraph::GetDepth() const
1871 return FirstPhysicalPar()->params.depth();
1873 return params.depth();
1878 char LyXParagraph::GetAlign() const
1881 return FirstPhysicalPar()->params.align();
1883 return params.align();
1888 string const & LyXParagraph::GetLabelstring() const
1891 return FirstPhysicalPar()->params.labelString();
1893 return params.labelString();
1898 int LyXParagraph::GetFirstCounter(int i) const
1901 return FirstPhysicalPar()->counter_[i];
1908 // the next two functions are for the manual labels
1909 string const LyXParagraph::GetLabelWidthString() const
1912 if (!FirstPhysicalPar()->params.labelWidthString().empty())
1913 return FirstPhysicalPar()->params.labelWidthString();
1915 if (!params.labelWidthString().empty())
1916 return params.labelWidthString();
1919 return _("Senseless with this layout!");
1923 void LyXParagraph::SetLabelWidthString(string const & s)
1926 LyXParagraph * par = FirstPhysicalPar();
1928 par->params.labelWidthString(s);
1930 params.labelWidthString(s);
1935 void LyXParagraph::SetOnlyLayout(BufferParams const & bparams,
1936 LyXTextClass::size_type new_layout)
1939 LyXParagraph * par = FirstPhysicalPar();
1941 LyXParagraph * par = this;
1943 LyXParagraph * ppar = 0;
1944 LyXParagraph * npar = 0;
1946 par->layout = new_layout;
1949 if (par->params.pextraType() == PEXTRA_NONE) {
1951 if (par->previous()) {
1953 ppar = par->previous()->FirstPhysicalPar();
1955 ppar = par->previous();
1959 && (ppar->params.depth() > par->params.depth()))
1961 ppar = ppar->previous()->FirstPhysicalPar();
1963 ppar = ppar->previous();
1968 npar = par->next()->NextAfterFootnote();
1974 && (npar->params.depth() > par->params.depth()))
1976 npar = npar->next()->NextAfterFootnote();
1978 npar = npar->next();
1982 if (ppar && (ppar->params.pextraType() != PEXTRA_NONE)) {
1983 string p1 = ppar->params.pextraWidth();
1984 string p2 = ppar->params.pextraWidthp();
1985 ppar->SetPExtraType(bparams,
1986 ppar->params.pextraType(),
1989 if ((par->params.pextraType() == PEXTRA_NONE) &&
1990 npar && (npar->params.pextraType() != PEXTRA_NONE)) {
1991 string const p1 = npar->params.pextraWidth();
1992 string const p2 = npar->params.pextraWidthp();
1993 npar->SetPExtraType(bparams, npar->params.pextraType(),
2001 void LyXParagraph::SetLayout(BufferParams const & bparams,
2002 LyXTextClass::size_type new_layout)
2006 * par = FirstPhysicalPar(),
2013 par->layout = new_layout;
2014 par->params.labelWidthString(string());
2015 par->params.align(LYX_ALIGN_LAYOUT);
2016 par->params.spaceTop(VSpace(VSpace::NONE));
2017 par->params.spaceBottom(VSpace(VSpace::NONE));
2018 par->params.spacing(Spacing(Spacing::Default));
2021 if (par->params.pextraType() == PEXTRA_NONE) {
2023 if (par->previous()) {
2025 ppar = par->previous()->FirstPhysicalPar();
2027 ppar = par->previous();
2031 && (ppar->params.depth() > par->params.depth()))
2033 ppar = ppar->previous()->FirstPhysicalPar();
2035 ppar = ppar->previous();
2040 npar = par->next()->NextAfterFootnote();
2046 && (npar->params.depth() > par->params.depth()))
2048 npar = npar->next()->NextAfterFootnote();
2050 npar = npar->next();
2054 if (ppar && (ppar->params.pextraType() != PEXTRA_NONE)) {
2055 string const p1 = ppar->params.pextraWidth();
2056 string const p2 = ppar->params.pextraWidthp();
2057 ppar->SetPExtraType(bparams, ppar->params.pextraType(),
2060 if ((par->params.pextraType() == PEXTRA_NONE) &&
2061 npar && (npar->params.pextraType() != PEXTRA_NONE)) {
2062 string const p1 = npar->params.pextraWidth();
2063 string const p2 = npar->params.pextraWidthp();
2064 npar->SetPExtraType(bparams, npar->params.pextraType(),
2072 // if the layout of a paragraph contains a manual label, the beginning of the
2073 // main body is the beginning of the second word. This is what the par-
2074 // function returns. If the layout does not contain a label, the main
2075 // body always starts with position 0. This differentiation is necessary,
2076 // because there cannot be a newline or a blank <= the beginning of the
2077 // main body in TeX.
2079 int LyXParagraph::BeginningOfMainBody() const
2082 if (FirstPhysicalPar() != this)
2085 // Unroll the first two cycles of the loop
2086 // and remember the previous character to
2087 // remove unnecessary GetChar() calls
2090 && GetChar(i) != LyXParagraph::META_NEWLINE
2093 char previous_char = 0;
2096 && (previous_char = GetChar(i)) != LyXParagraph::META_NEWLINE) {
2097 // Yes, this ^ is supposed to be "= " not "=="
2100 && previous_char != ' '
2101 && (temp = GetChar(i)) != LyXParagraph::META_NEWLINE) {
2103 previous_char = temp;
2109 if (i == 0 && i == size() &&
2110 !(footnoteflag == LyXParagraph::NO_FOOTNOTE
2111 && next_ && next_->footnoteflag != LyXParagraph::NO_FOOTNOTE))
2112 ++i; /* the cursor should not jump
2113 * to the main body if there
2120 LyXParagraph * LyXParagraph::DepthHook(int deth)
2122 LyXParagraph * newpar = this;
2128 newpar = newpar->FirstPhysicalPar()->previous();
2130 newpar = newpar->previous();
2132 } while (newpar && newpar->GetDepth() > deth
2134 && newpar->footnoteflag == footnoteflag
2139 if (previous() || GetDepth())
2140 lyxerr << "ERROR (LyXParagraph::DepthHook): "
2145 return newpar->FirstPhysicalPar();
2152 LyXParagraph const * LyXParagraph::DepthHook(int deth) const
2154 LyXParagraph const * newpar = this;
2160 newpar = newpar->FirstPhysicalPar()->previous();
2162 newpar = newpar->previous();
2164 } while (newpar && newpar->GetDepth() > deth
2166 && newpar->footnoteflag == footnoteflag
2171 if (previous() || GetDepth())
2172 lyxerr << "ERROR (LyXParagraph::DepthHook): "
2177 return newpar->FirstPhysicalPar();
2184 int LyXParagraph::AutoDeleteInsets()
2187 InsetList::size_type index = 0;
2188 while (index < insetlist.size()) {
2189 if (insetlist[index].inset && insetlist[index].inset->AutoDelete()) {
2190 Erase(insetlist[index].pos);
2191 // Erase() calls to insetlist.erase(&insetlist[index])
2192 // so index shouldn't be increased.
2201 LyXParagraph::inset_iterator
2202 LyXParagraph::InsetIterator(LyXParagraph::size_type pos)
2204 InsetTable search_inset(pos, 0);
2205 InsetList::iterator it = lower_bound(insetlist.begin(),
2207 search_inset, matchIT());
2208 return inset_iterator(it);
2212 // returns -1 if inset not found
2213 int LyXParagraph::GetPositionOfInset(Inset * inset) const
2216 for (InsetList::const_iterator cit = insetlist.begin();
2217 cit != insetlist.end(); ++cit) {
2218 if ((*cit).inset == inset) {
2222 if (inset == bibkey)
2226 // Think about footnotes.
2227 if (footnoteflag == LyXParagraph::NO_FOOTNOTE
2228 && next_ && next_->footnoteflag == LyXParagraph::CLOSED_FOOTNOTE) {
2230 NextAfterFootnote()->GetPositionOfInset(inset);
2232 return text.size() + 1 + further;
2239 LyXParagraph * LyXParagraph::TeXOnePar(Buffer const * buf,
2240 BufferParams const & bparams,
2241 ostream & os, TexRow & texrow,
2246 TexRow & foot_texrow,
2251 lyxerr[Debug::LATEX] << "TeXOnePar... " << this << endl;
2252 LyXLayout const & style =
2253 textclasslist.Style(bparams.textclass,
2256 bool further_blank_line = false;
2259 lyxerr << "ERROR (LyXParagraph::TeXOnePar) is dummy." << endl;
2262 if (params.startOfAppendix()) {
2263 os << "\\appendix\n";
2267 if (!params.spacing().isDefault()
2268 && (!previous() || !previous()->HasSameLayout(this))) {
2269 os << params.spacing().writeEnvirBegin() << "\n";
2273 if (tex_code_break_column && style.isCommand()){
2278 if (params.pagebreakTop()) {
2280 further_blank_line = true;
2282 if (params.spaceTop().kind() != VSpace::NONE) {
2283 os << params.spaceTop().asLatexCommand(bparams);
2284 further_blank_line = true;
2287 if (params.lineTop()) {
2288 os << "\\lyxline{\\" << getFont(bparams, 0).latexSize() << '}'
2289 << "\\vspace{-1\\parskip}";
2290 further_blank_line = true;
2293 if (further_blank_line){
2298 Language const * language = getParLanguage(bparams);
2299 Language const * doc_language = bparams.language;
2300 Language const * previous_language = previous_
2301 ? previous_->getParLanguage(bparams) : doc_language;
2302 if (language->babel() != doc_language->babel() &&
2303 language->babel() != previous_language->babel()) {
2304 os << subst(lyxrc.language_command_begin, "$$lang",
2310 if (bparams.inputenc == "auto" &&
2311 language->encoding() != previous_language->encoding()) {
2312 os << "\\inputencoding{"
2313 << language->encoding()->LatexName()
2318 switch (style.latextype) {
2321 << style.latexname()
2322 << style.latexparam();
2324 case LATEX_ITEM_ENVIRONMENT:
2326 bibkey->Latex(buf, os, false, false);
2330 case LATEX_LIST_ENVIRONMENT:
2337 bool need_par = SimpleTeXOnePar(buf, bparams, os, texrow, moving_arg);
2339 LyXParagraph * par = next_;
2341 // Spit out footnotes
2342 if (lyxrc.rtl_support) {
2343 if (next_ && next_->footnoteflag != LyXParagraph::NO_FOOTNOTE
2344 && next_->footnoteflag != footnoteflag) {
2345 LyXParagraph * p = 0;
2346 bool is_rtl = (size() > 0)
2347 ? GetFontSettings(bparams,
2348 size()-1).isRightToLeft()
2349 : language->RightToLeft();
2350 if ((p = NextAfterFootnote()) != 0 &&
2352 p->GetFontSettings(bparams, 0).isRightToLeft() != is_rtl)
2353 is_rtl = getParLanguage(bparams)->RightToLeft();
2354 while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2355 && par->footnoteflag != footnoteflag) {
2356 par = par->TeXFootnote(buf, bparams,
2358 foot_texrow, foot_count,
2360 par->SimpleTeXOnePar(buf, bparams,
2361 os, texrow, moving_arg);
2362 is_rtl = (par->size() > 0)
2363 ? par->GetFontSettings(bparams,
2364 par->size()-1).isRightToLeft()
2365 : language->RightToLeft();
2367 par->next_->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
2368 (p = par->NextAfterFootnote()) != 0 &&
2370 p->GetFontSettings(bparams, 0).isRightToLeft() != is_rtl)
2371 is_rtl = language->RightToLeft();
2376 while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE
2377 && par->footnoteflag != footnoteflag) {
2378 par = par->TeXFootnote(buf, bparams,
2380 foot, foot_texrow, foot_count,
2382 par->SimpleTeXOnePar(buf, bparams, os, texrow, moving_arg);
2388 // Make sure that \\par is done with the font of the last
2389 // character if this has another size as the default.
2390 // This is necessary because LaTeX (and LyX on the screen)
2391 // calculates the space between the baselines according
2392 // to this font. (Matthias)
2394 // Is this really needed ? (Dekel)
2395 // We do not need to use to change the font for the last paragraph
2396 // or for a command.
2398 LyXFont font = getFont(bparams, Last() - 1);
2400 LyXFont font = getFont(bparams, size() - 1);
2402 bool is_command = textclasslist.Style(bparams.textclass,
2403 GetLayout()).isCommand();
2404 if (style.resfont.size() != font.size() && next_ && !is_command) {
2407 os << "\\" << font.latexSize() << " \\par}";
2408 } else if (need_par) {
2410 } else if (is_command)
2413 if (language->babel() != doc_language->babel() &&
2416 || (footnoteflag != NO_FOOTNOTE && par->footnoteflag != footnoteflag)
2418 || par->getParLanguage(bparams)->babel() != language->babel())) {
2420 << subst(lyxrc.language_command_end, "$$lang",
2421 doc_language->babel());
2424 switch (style.latextype) {
2425 case LATEX_ITEM_ENVIRONMENT:
2426 case LATEX_LIST_ENVIRONMENT:
2427 if (par && (params.depth() < par->params.depth())) {
2432 case LATEX_ENVIRONMENT:
2433 // if its the last paragraph of the current environment
2434 // skip it otherwise fall through
2436 && (par->layout != layout
2437 || par->params.depth() != params.depth()
2439 || par->params.pextraType() != params.pextraType()
2444 // we don't need it for the last paragraph!!!
2445 // or for tables in floats
2446 // -- effectively creates a \par where there isn't one which
2447 // breaks a \subfigure or \subtable.
2449 // && footnoteflag == LyXParagraph::NO_FOOTNOTE) {
2455 further_blank_line = false;
2456 if (params.lineBottom()) {
2458 os << "\\lyxline{\\" << getFont(bparams,
2459 Last() - 1).latexSize() << '}';
2461 os << "\\lyxline{\\" << getFont(bparams,
2462 size() - 1).latexSize() << '}';
2464 further_blank_line = true;
2467 if (params.spaceBottom().kind() != VSpace::NONE) {
2468 os << params.spaceBottom().asLatexCommand(bparams);
2469 further_blank_line = true;
2472 if (params.pagebreakBottom()) {
2474 further_blank_line = true;
2477 if (further_blank_line){
2482 if (!params.spacing().isDefault()
2483 && (!par || !par->HasSameLayout(this))) {
2484 os << params.spacing().writeEnvirEnd() << "\n";
2488 // we don't need it for the last paragraph!!!
2491 && !(footnoteflag != LyXParagraph::NO_FOOTNOTE && par &&
2492 par->footnoteflag == LyXParagraph::NO_FOOTNOTE)
2499 lyxerr[Debug::LATEX] << "TeXOnePar...done " << par << endl;
2504 // This one spits out the text of the paragraph
2505 bool LyXParagraph::SimpleTeXOnePar(Buffer const * buf,
2506 BufferParams const & bparams,
2507 ostream & os, TexRow & texrow,
2510 lyxerr[Debug::LATEX] << "SimpleTeXOnePar... " << this << endl;
2512 bool return_value = false;
2514 LyXLayout const & style =
2515 textclasslist.Style(bparams.textclass,
2517 LyXFont basefont, last_font;
2519 // Maybe we have to create a optional argument.
2520 size_type main_body;
2521 if (style.labeltype != LABEL_MANUAL)
2524 main_body = BeginningOfMainBody();
2526 if (main_body > 0) {
2528 basefont = getFont(bparams, -2); // Get label font
2530 basefont = getFont(bparams, -1); // Get layout font
2541 if (style.isCommand()) {
2544 } else if (params.align() != LYX_ALIGN_LAYOUT) {
2547 return_value = true;
2551 moving_arg |= style.needprotect;
2553 // Which font is currently active?
2554 LyXFont running_font(basefont);
2555 // Do we have an open font change?
2556 bool open_font = false;
2558 texrow.start(this, 0);
2560 for (size_type i = 0; i < size(); ++i) {
2562 // First char in paragraph or after label?
2568 if (main_body > 0) {
2570 column += running_font.latexWriteEndChanges(os, basefont, basefont);
2573 basefont = getFont(bparams, -1); // Now use the layout font
2574 running_font = basefont;
2578 if (style.isCommand()) {
2581 } else if (params.align() != LYX_ALIGN_LAYOUT && next_) {
2582 // We do not need \par here (Dekel)
2586 return_value = true;
2589 if (params.noindent()) {
2590 os << "\\noindent ";
2593 switch (params.align()) {
2594 case LYX_ALIGN_NONE:
2595 case LYX_ALIGN_BLOCK:
2596 case LYX_ALIGN_LAYOUT:
2597 case LYX_ALIGN_SPECIAL:
2599 case LYX_ALIGN_LEFT:
2602 if (getParLanguage(bparams)->babel() != "hebrew") {
2603 os << "\\raggedright ";
2606 os << "\\raggedleft ";
2610 case LYX_ALIGN_RIGHT:
2613 if (getParLanguage(bparams)->babel() != "hebrew") {
2614 os << "\\raggedleft ";
2617 os << "\\raggedright ";
2621 case LYX_ALIGN_CENTER:
2624 os << "\\centering ";
2630 value_type c = GetChar(i);
2632 // Fully instantiated font
2633 LyXFont font = getFont(bparams, i);
2635 LyXParagraph * p = 0;
2638 previous_->footnoteflag != LyXParagraph::NO_FOOTNOTE &&
2639 (p = PreviousBeforeFootnote()) != 0)
2640 last_font = p->getFont(bparams, p->size() - 1);
2643 last_font = running_font;
2645 // Spaces at end of font change are simulated to be
2646 // outside font change, i.e. we write "\textXX{text} "
2647 // rather than "\textXX{text }". (Asger)
2648 if (open_font && c == ' ' && i <= size() - 2
2649 && !getFont(bparams, i + 1).equalExceptLatex(running_font)
2650 && !getFont(bparams, i + 1).equalExceptLatex(font)) {
2651 font = getFont(bparams, i + 1);
2653 // We end font definition before blanks
2654 if (!font.equalExceptLatex(running_font) && open_font) {
2655 column += running_font.latexWriteEndChanges(os,
2657 (i == main_body-1) ? basefont : font);
2658 running_font = basefont;
2662 // Blanks are printed before start of fontswitch
2664 // Do not print the separation of the optional argument
2665 if (i != main_body - 1) {
2666 SimpleTeXBlanks(os, texrow, i,
2667 column, font, style);
2671 // Do we need to change font?
2672 if (!font.equalExceptLatex(running_font)
2673 && i != main_body-1) {
2674 column += font.latexWriteStartChanges(os, basefont,
2676 running_font = font;
2680 if (c == LyXParagraph::META_NEWLINE) {
2681 // newlines are handled differently here than
2682 // the default in SimpleTeXSpecialChars().
2683 if (!style.newline_allowed
2684 || font.latex() == LyXFont::ON) {
2688 column += running_font.latexWriteEndChanges(os, basefont, basefont);
2691 basefont = getFont(bparams, -1);
2692 running_font = basefont;
2693 if (font.family() ==
2694 LyXFont::TYPEWRITER_FAMILY) {
2702 texrow.start(this, i + 1);
2705 SimpleTeXSpecialChars(buf, bparams,
2706 os, texrow, moving_arg,
2707 font, running_font, basefont,
2708 open_font, style, i, column, c);
2712 // If we have an open font definition, we have to close it
2714 LyXParagraph * p = 0;
2717 && next_->footnoteflag != LyXParagraph::NO_FOOTNOTE
2718 && (p = NextAfterFootnote()) != 0
2723 running_font.latexWriteEndChanges(os, basefont,
2724 p->getFont(bparams, 0));
2726 running_font.latexWriteEndChanges(os, basefont, basefont);
2729 // Needed if there is an optional argument but no contents.
2730 if (main_body > 0 && main_body == size()) {
2732 return_value = false;
2735 lyxerr[Debug::LATEX] << "SimpleTeXOnePar...done " << this << endl;
2736 return return_value;
2740 bool LyXParagraph::linuxDocConvertChar(char c, string & sgml_string)
2742 bool retval = false;
2744 case LyXParagraph::META_HFILL:
2745 sgml_string.erase();
2747 case LyXParagraph::META_NEWLINE:
2751 sgml_string = "&";
2754 sgml_string = "<";
2757 sgml_string = ">";
2760 sgml_string = "$";
2763 sgml_string = "#";
2766 sgml_string = "%";
2769 sgml_string = "[";
2772 sgml_string = "]";
2775 sgml_string = "{";
2778 sgml_string = "}";
2781 sgml_string = "˜";
2784 sgml_string = """;
2787 sgml_string = "\";
2793 case '\0': // Ignore :-)
2794 sgml_string.erase();
2804 void LyXParagraph::SimpleTeXBlanks(ostream & os, TexRow & texrow,
2805 LyXParagraph::size_type const i,
2806 int & column, LyXFont const & font,
2807 LyXLayout const & style)
2809 if (column > tex_code_break_column
2811 && GetChar(i - 1) != ' '
2813 // In LaTeX mode, we don't want to
2814 // break lines since some commands
2816 && ! (font.latex() == LyXFont::ON)
2817 // same in FreeSpacing mode
2818 && !style.free_spacing
2819 // In typewriter mode, we want to avoid
2820 // ! . ? : at the end of a line
2821 && !(font.family() == LyXFont::TYPEWRITER_FAMILY
2822 && (GetChar(i-1) == '.'
2823 || GetChar(i-1) == '?'
2824 || GetChar(i-1) == ':'
2825 || GetChar(i-1) == '!'))) {
2826 if (tex_code_break_column == 0) {
2827 // in batchmode we need LaTeX to still
2828 // see it as a space not as an extra '\n'
2834 texrow.start(this, i + 1);
2836 } else if (font.latex() == LyXFont::OFF) {
2837 if (style.free_spacing) {
2846 void LyXParagraph::SimpleTeXSpecialChars(Buffer const * buf,
2847 BufferParams const & bparams,
2848 ostream & os, TexRow & texrow,
2851 LyXFont & running_font,
2854 LyXLayout const & style,
2855 LyXParagraph::size_type & i,
2857 LyXParagraph::value_type const c)
2859 // Two major modes: LaTeX or plain
2860 // Handle here those cases common to both modes
2861 // and then split to handle the two modes separately.
2863 case LyXParagraph::META_INSET: {
2864 Inset * inset = GetInset(i);
2867 int const len = os.tellp();
2868 //ostream::pos_type const len = os.tellp();
2869 if ((inset->LyxCode() == Inset::GRAPHICS_CODE
2870 || inset->LyxCode() == Inset::MATH_CODE
2871 || inset->LyxCode() == Inset::URL_CODE)
2872 && running_font.isRightToLeft()) {
2877 int tmp = inset->Latex(buf, os, moving_arg,
2878 style.free_spacing);
2886 column += int(os.tellp()) - len;
2895 case LyXParagraph::META_NEWLINE:
2897 column += running_font.latexWriteEndChanges(os,
2902 basefont = getFont(bparams, -1);
2903 running_font = basefont;
2906 case LyXParagraph::META_HFILL:
2912 // And now for the special cases within each mode
2913 // Are we in LaTeX mode?
2914 if (font.latex() == LyXFont::ON) {
2915 // at present we only have one option
2916 // but I'll leave it as a switch statement
2917 // so its simpler to extend. (ARRae)
2920 // make sure that we will not print
2921 // error generating chars to the tex
2922 // file. This test would not be needed
2923 // if it were done in the buffer
2931 // Plain mode (i.e. not LaTeX)
2934 os << "\\textbackslash{}";
2938 case '°': case '±': case '²': case '³':
2939 case '×': case '÷': case '¹': case 'ª':
2940 case 'º': case '¬': case 'µ':
2941 if (bparams.inputenc == "latin1" ||
2942 (bparams.inputenc == "auto" &&
2943 font.language()->encoding()->LatexName()
2945 os << "\\ensuremath{"
2954 case '|': case '<': case '>':
2955 // In T1 encoding, these characters exist
2956 if (lyxrc.fontenc == "T1") {
2958 //... but we should avoid ligatures
2959 if ((c == '>' || c == '<')
2961 && GetChar(i + 1) == c) {
2962 //os << "\\textcompwordmark{}";
2963 // Jean-Marc, have a look at
2964 // this. IÂ think this works
2972 // Typewriter font also has them
2973 if (font.family() == LyXFont::TYPEWRITER_FAMILY) {
2977 // Otherwise, we use what LaTeX
2981 os << "\\textless{}";
2985 os << "\\textgreater{}";
2989 os << "\\textbar{}";
2995 case '-': // "--" in Typewriter mode -> "-{}-"
2997 && GetChar(i + 1) == '-'
2998 && font.family() == LyXFont::TYPEWRITER_FAMILY) {
3007 os << "\\char`\\\"{}";
3012 if (bparams.inputenc == "default") {
3021 case '%': case '#': case '{':
3028 os << "\\textasciitilde{}";
3033 os << "\\textasciicircum{}";
3037 case '*': case '[': case ']':
3038 // avoid being mistaken for optional arguments
3039 os << '{' << c << '}';
3044 // Blanks are printed before font switching.
3045 // Sure? I am not! (try nice-latex)
3046 // I am sure it's correct. LyX might be smarter
3047 // in the future, but for now, nothing wrong is
3052 /* idea for labels --- begin*/
3056 && font.family() != LyXFont::TYPEWRITER_FAMILY
3057 && GetChar(i + 1) == 'y'
3058 && GetChar(i + 2) == 'X') {
3066 && font.family() != LyXFont::TYPEWRITER_FAMILY
3067 && GetChar(i + 1) == 'e'
3068 && GetChar(i + 2) == 'X') {
3073 // Check for "LaTeX2e"
3076 && font.family() != LyXFont::TYPEWRITER_FAMILY
3077 && GetChar(i + 1) == 'a'
3078 && GetChar(i + 2) == 'T'
3079 && GetChar(i + 3) == 'e'
3080 && GetChar(i + 4) == 'X'
3081 && GetChar(i + 5) == '2'
3082 && GetChar(i + 6) == 'e') {
3087 // Check for "LaTeX"
3090 && font.family() != LyXFont::TYPEWRITER_FAMILY
3091 && GetChar(i + 1) == 'a'
3092 && GetChar(i + 2) == 'T'
3093 && GetChar(i + 3) == 'e'
3094 && GetChar(i + 4) == 'X') {
3098 /* idea for labels --- end*/
3099 } else if (c != '\0') {
3109 LyXParagraph * LyXParagraph::TeXDeeper(Buffer const * buf,
3110 BufferParams const & bparams,
3111 ostream & os, TexRow & texrow
3114 TexRow & foot_texrow,
3119 lyxerr[Debug::LATEX] << "TeXDeeper... " << this << endl;
3120 LyXParagraph * par = this;
3123 (par->params.depth() == params.depth())
3125 && (par->footnoteflag == footnoteflag)
3130 lyxerr << "ERROR (LyXParagraph::TeXDeeper)" << endl;
3132 if (textclasslist.Style(bparams.textclass,
3133 par->layout).isEnvironment()
3135 || par->params.pextraType() != PEXTRA_NONE
3138 par = par->TeXEnvironment(buf, bparams,
3146 par = par->TeXOnePar(buf, bparams,
3156 lyxerr[Debug::LATEX] << "TeXDeeper...done " << par << endl;
3162 LyXParagraph * LyXParagraph::TeXEnvironment(Buffer const * buf,
3163 BufferParams const & bparams,
3164 ostream & os, TexRow & texrow
3167 TexRow & foot_texrow,
3173 bool eindent_open = false;
3176 bool foot_this_level = false;
3179 // flags when footnotetext should be appended to file.
3180 static bool minipage_open = false;
3181 static int minipage_open_depth = 0;
3182 char par_sep = bparams.paragraph_separation;
3185 lyxerr[Debug::LATEX] << "TeXEnvironment... " << this << endl;
3188 lyxerr << "ERROR (LyXParagraph::TeXEnvironment)" << endl;
3191 LyXLayout const & style =
3192 textclasslist.Style(bparams.textclass,
3196 if (params.pextraType() == PEXTRA_INDENT) {
3197 if (!params.pextraWidth().empty()) {
3198 os << "\\begin{LyXParagraphIndent}{"
3199 << params.pextraWidth() << "}\n";
3201 //float ib = atof(pextra_widthp.c_str())/100;
3202 // string can't handle floats at present (971109)
3203 // so I'll do a conversion by hand knowing that
3204 // the limits are 0.0 to 1.0. ARRae.
3205 os << "\\begin{LyXParagraphIndent}{";
3206 switch (params.pextraWidthp().length()) {
3212 << params.pextraWidthp();
3216 << params.pextraWidthp();
3218 os << "\\columnwidth}\n";
3221 eindent_open = true;
3223 if ((params.pextraType() == PEXTRA_MINIPAGE) && !minipage_open) {
3224 if (params.pextraHfill() && previous() &&
3225 (previous()->params.pextraType() == PEXTRA_MINIPAGE)) {
3226 os << "\\hfill{}\n";
3229 if (par_sep == BufferParams::PARSEP_INDENT) {
3230 os << "{\\setlength\\parindent{0pt}\n";
3233 os << "\\begin{minipage}";
3234 switch (params.pextraAlignment()) {
3235 case MINIPAGE_ALIGN_TOP:
3238 case MINIPAGE_ALIGN_MIDDLE:
3241 case MINIPAGE_ALIGN_BOTTOM:
3245 if (!params.pextraWidth().empty()) {
3246 os << '{' << params.pextraWidth() << "}\n";
3248 //float ib = atof(par->pextra_width.c_str())/100;
3249 // string can't handle floats at present
3250 // so I'll do a conversion by hand knowing that
3251 // the limits are 0.0 to 1.0. ARRae.
3253 switch (params.pextraWidthp().length()) {
3259 << params.pextraWidthp();
3263 << params.pextraWidthp();
3265 os << "\\columnwidth}\n";
3268 if (par_sep == BufferParams::PARSEP_INDENT) {
3269 os << "\\setlength\\parindent{\\LyXMinipageIndent}\n";
3272 minipage_open = true;
3273 minipage_open_depth = params.depth();
3276 #ifdef WITH_WARNINGS
3277 #warning Define FANCY_FOOTNOTE_CODE to re-enable Allan footnote code
3278 //I disabled it because it breaks when lists span on several
3281 if (style.isEnvironment()){
3282 if (style.latextype == LATEX_LIST_ENVIRONMENT) {
3283 #ifdef FANCY_FOOTNOTE_CODE
3284 if (foot_count < 0) {
3285 // flag that footnote[mark][text] should be
3286 // used for any footnotes from now on
3288 foot_this_level = true;
3291 os << "\\begin{" << style.latexname() << "}{"
3292 << params.labelWidthString() << "}\n";
3293 } else if (style.labeltype == LABEL_BIBLIO) {
3295 os << "\\begin{" << style.latexname() << "}{"
3296 << bibitemWidest(buf)
3298 } else if (style.latextype == LATEX_ITEM_ENVIRONMENT) {
3299 #ifdef FANCY_FOOTNOTE_CODE
3300 if (foot_count < 0) {
3301 // flag that footnote[mark][text] should be
3302 // used for any footnotes from now on
3304 foot_this_level = true;
3307 os << "\\begin{" << style.latexname() << '}'
3308 << style.latexparam() << '\n';
3310 os << "\\begin{" << style.latexname() << '}'
3311 << style.latexparam() << '\n';
3314 LyXParagraph * par = this;
3316 par = par->TeXOnePar(buf, bparams,
3320 foot, foot_texrow, foot_count
3324 if (minipage_open && par && !style.isEnvironment() &&
3325 (par->params.pextraType() == PEXTRA_MINIPAGE) &&
3326 par->params.pextraStartMinipage()) {
3327 os << "\\end{minipage}\n";
3329 if (par_sep == BufferParams::PARSEP_INDENT) {
3333 minipage_open = false;
3336 if (par && par->params.depth() > params.depth()) {
3337 if (textclasslist.Style(bparams.textclass,
3338 par->layout).isParagraph()
3340 // How to handle this? (Lgb)
3341 //&& !suffixIs(os, "\n\n")
3343 // There should be at least one '\n' already
3344 // but we need there to be two for Standard
3345 // paragraphs that are depth-increment'ed to be
3346 // output correctly. However, tables can
3347 // also be paragraphs so don't adjust them.
3350 // Will it ever harm to have one '\n' too
3351 // many? i.e. that we sometimes will have
3352 // three in a row. (Lgb)
3356 par = par->TeXDeeper(buf, bparams, os, texrow
3358 ,foot, foot_texrow, foot_count
3363 if (par && par->layout == layout && par->params.depth() == params.depth() &&
3364 (par->params.pextraType() == PEXTRA_MINIPAGE) && !minipage_open) {
3365 if (par->params.pextraHfill() && par->previous() &&
3366 (par->previous()->params.pextraType() == PEXTRA_MINIPAGE)){
3367 os << "\\hfill{}\n";
3370 if (par_sep == BufferParams::PARSEP_INDENT) {
3371 os << "{\\setlength\\parindent{0pt}\n";
3374 os << "\\begin{minipage}";
3375 switch (par->params.pextraAlignment()) {
3376 case MINIPAGE_ALIGN_TOP:
3379 case MINIPAGE_ALIGN_MIDDLE:
3382 case MINIPAGE_ALIGN_BOTTOM:
3386 if (!par->params.pextraWidth().empty()) {
3387 os << '{' << par->params.pextraWidth() << "}\n";
3389 //float ib = atof(par->pextra_widthp.c_str())/100;
3390 // string can't handle floats at present
3391 // so I'll do a conversion by hand knowing that
3392 // the limits are 0.0 to 1.0. ARRae.
3394 switch (par->params.pextraWidthp().length()) {
3399 os << "0." << par->params.pextraWidthp();
3402 os << "0.0" << par->params.pextraWidthp();
3404 os << "\\columnwidth}\n";
3407 if (par_sep == BufferParams::PARSEP_INDENT) {
3408 os << "\\setlength\\parindent{\\LyXMinipageIndent}\n";
3411 minipage_open = true;
3412 minipage_open_depth = par->params.depth();
3416 && par->layout == layout
3417 && par->params.depth() == params.depth()
3419 && par->params.pextraType() == params.pextraType()
3422 && par->footnoteflag == footnoteflag
3426 if (style.isEnvironment()) {
3427 os << "\\end{" << style.latexname() << '}';
3429 // maybe this should go after the minipage closes?
3430 if (foot_this_level) {
3431 if (foot_count >= 1) {
3432 if (foot_count > 1) {
3433 os << "\\addtocounter{footnote}{-"
3438 texrow += foot_texrow;
3440 foot_texrow.reset();
3447 if (minipage_open && (minipage_open_depth == params.depth()) &&
3448 (!par || par->params.pextraStartMinipage() ||
3449 par->params.pextraType() != PEXTRA_MINIPAGE)) {
3450 os << "\\end{minipage}\n";
3452 if (par_sep == BufferParams::PARSEP_INDENT) {
3456 if (par && par->params.pextraType() != PEXTRA_MINIPAGE) {
3457 os << "\\medskip\n\n";
3461 minipage_open = false;
3464 os << "\\end{LyXParagraphIndent}\n";
3467 if (!(par && (par->params.pextraType() == PEXTRA_MINIPAGE)
3468 && par->params.pextraHfill())) {
3473 lyxerr[Debug::LATEX] << "TeXEnvironment...done " << par << endl;
3474 return par; // ale970302
3479 LyXParagraph * LyXParagraph::TeXFootnote(Buffer const * buf,
3480 BufferParams const & bparams,
3481 ostream & os, TexRow & texrow,
3482 ostream & foot, TexRow & foot_texrow,
3486 lyxerr[Debug::LATEX] << "TeXFootnote... " << this << endl;
3487 if (footnoteflag == LyXParagraph::NO_FOOTNOTE)
3488 lyxerr << "ERROR (LyXParagraph::TeXFootnote): "
3489 "No footnote!" << endl;
3491 LyXParagraph * par = this;
3492 LyXLayout const & style =
3493 textclasslist.Style(bparams.textclass,
3494 previous_->GetLayout());
3496 if (style.needprotect && footnotekind != LyXParagraph::FOOTNOTE){
3497 lyxerr << "ERROR (LyXParagraph::TeXFootnote): "
3498 "Float other than footnote in command"
3499 " with moving argument is illegal" << endl;
3502 if (footnotekind != LyXParagraph::FOOTNOTE
3503 && footnotekind != LyXParagraph::MARGIN
3506 // How to solve this?
3507 //&& !suffixIs(file, '\n')
3509 // we need to ensure that real floats like tables and figures
3510 // have their \begin{} on a new line otherwise we can get
3511 // incorrect results when using the endfloat.sty package
3512 // especially if two floats follow one another. ARRae 981022
3513 // NOTE: if the file is length 0 it must have just been
3514 // written out so we assume it ended with a '\n'
3516 // As far as I can see there is never any harm in writing
3517 // a '\n' too much. Please tell me if I am wrong. (Lgb)
3522 bool moving_arg = false;
3523 bool need_closing = false;
3524 bool is_rtl = isRightToLeftPar(bparams);
3526 if (is_rtl != parent_is_rtl) {
3531 need_closing = true;
3534 bool footer_in_body = true;
3535 switch (footnotekind) {
3536 case LyXParagraph::FOOTNOTE:
3537 if (style.intitle) {
3538 os << "\\thanks{\n";
3539 footer_in_body = false;
3542 if (foot_count == -1) {
3543 // we're at depth 0 so we can use:
3544 os << "\\footnote{%\n";
3545 footer_in_body = false;
3547 os << "\\footnotemark{}%\n";
3549 // we only need this when there are
3550 // multiple footnotes
3551 os << "\\stepcounter{footnote}";
3553 os << "\\footnotetext{%\n";
3554 foot_texrow.start(this, 0);
3555 foot_texrow.newline();
3560 case LyXParagraph::MARGIN:
3561 os << "\\marginpar{\n";
3563 case LyXParagraph::FIG:
3564 if (params.pextraType() == PEXTRA_FLOATFLT
3565 && (!params.pextraWidth().empty()
3566 || !params.pextraWidthp().empty())) {
3567 if (!params.pextraWidth().empty())
3568 os << "\\begin{floatingfigure}{"
3569 << params.pextraWidth() << "}\n";
3571 os << "\\begin{floatingfigure}{"
3572 << lyx::atoi(params.pextraWidthp()) / 100.0
3573 << "\\textwidth}\n";
3575 os << "\\begin{figure}";
3576 if (!bparams.float_placement.empty()) {
3577 os << '[' << bparams.float_placement << "]\n";
3583 case LyXParagraph::TAB:
3584 os << "\\begin{table}";
3585 if (!bparams.float_placement.empty()) {
3586 os << '[' << bparams.float_placement << "]\n";
3591 case LyXParagraph::WIDE_FIG:
3592 os << "\\begin{figure*}";
3593 if (!bparams.float_placement.empty()) {
3594 os << '[' << bparams.float_placement << "]\n";
3599 case LyXParagraph::WIDE_TAB:
3600 os << "\\begin{table*}";
3601 if (!bparams.float_placement.empty()) {
3602 os << '[' << bparams.float_placement << "]\n";
3607 case LyXParagraph::ALGORITHM:
3608 os << "\\begin{algorithm}\n";
3613 if (footnotekind != LyXParagraph::FOOTNOTE
3614 || !footer_in_body) {
3615 // Process text for all floats except footnotes in body
3617 LyXLayout const & style =
3619 .Style(bparams.textclass, par->layout);
3621 lyxerr << "ERROR (LyXParagraph::TeXFootnote)"
3623 if (style.isEnvironment()
3624 || par->params.pextraType() == PEXTRA_MINIPAGE) { /* && !minipage_open ?? */
3625 // Allows the use of minipages within float
3626 // environments. Shouldn't be circular because
3627 // we don't support footnotes inside
3628 // floats (yet). ARRae
3629 par = par->TeXEnvironment(buf, bparams, os,
3634 par = par->TeXOnePar(buf, bparams,
3635 os, texrow, moving_arg,
3640 if (par && !par->IsDummy() && par->params.depth() > params.depth()) {
3641 par = par->TeXDeeper(buf, bparams, os, texrow,
3645 } while (par && par->footnoteflag != LyXParagraph::NO_FOOTNOTE);
3647 // process footnotes > depth 0 or in environments separately
3648 // NOTE: Currently don't support footnotes within footnotes
3649 // even though that is possible using the \footnotemark
3650 std::ostringstream dummy;
3651 TexRow dummy_texrow;
3652 int dummy_count = 0;
3654 LyXLayout const & style =
3656 .Style(bparams.textclass, par->layout);
3658 lyxerr << "ERROR (LyXParagraph::TeXFootnote)"
3660 if (style.isEnvironment()
3661 || par->params.pextraType() == PEXTRA_MINIPAGE) { /* && !minipage_open ?? */
3662 // Allows the use of minipages within float
3663 // environments. Shouldn't be circular because
3664 // we don't support footnotes inside
3665 // floats (yet). ARRae
3666 par = par->TeXEnvironment(buf, bparams,
3668 dummy, dummy_texrow,
3671 par = par->TeXOnePar(buf, bparams,
3674 dummy, dummy_texrow,
3678 if (par && !par->IsDummy() && par->params.depth() > params.depth()) {
3679 par = par->TeXDeeper(buf, bparams,
3681 dummy, dummy_texrow,
3685 && par->footnoteflag != LyXParagraph::NO_FOOTNOTE);
3687 lyxerr << "ERROR (LyXParagraph::TeXFootnote): "
3688 "Footnote in a Footnote -- not supported"
3693 switch (footnotekind) {
3694 case LyXParagraph::FOOTNOTE:
3695 if (footer_in_body) {
3696 // This helps tell which of the multiple
3697 // footnotetexts an error was in.
3699 foot_texrow.newline();
3704 case LyXParagraph::MARGIN:
3707 case LyXParagraph::FIG:
3708 if (params.pextraType() == PEXTRA_FLOATFLT
3709 && (!params.pextraWidth().empty()
3710 || !params.pextraWidthp().empty()))
3711 os << "\\end{floatingfigure}";
3713 os << "\\end{figure}";
3715 case LyXParagraph::TAB:
3716 os << "\\end{table}";
3718 case LyXParagraph::WIDE_FIG:
3719 os << "\\end{figure*}";
3721 case LyXParagraph::WIDE_TAB:
3722 os << "\\end{table*}";
3724 case LyXParagraph::ALGORITHM:
3725 os << "\\end{algorithm}";
3732 if (footnotekind != LyXParagraph::FOOTNOTE
3733 && footnotekind != LyXParagraph::MARGIN) {
3734 // we need to ensure that real floats like tables and figures
3735 // have their \end{} on a line of their own otherwise we can
3736 // get incorrect results when using the endfloat.sty package.
3741 lyxerr[Debug::LATEX] << "TeXFootnote...done " << par->next_ << endl;
3746 bool LyXParagraph::IsDummy() const
3748 return (footnoteflag == LyXParagraph::NO_FOOTNOTE && previous_
3749 && previous_->footnoteflag != LyXParagraph::NO_FOOTNOTE);
3754 void LyXParagraph::SetPExtraType(BufferParams const & bparams,
3755 int type, string const & width,
3756 string const & widthp)
3758 params.pextraType(type);
3759 params.pextraWidth(width);
3760 params.pextraWidthp(widthp);
3762 if (textclasslist.Style(bparams.textclass,
3763 layout).isEnvironment()) {
3764 LyXParagraph * par = this;
3765 LyXParagraph * ppar = par;
3767 while (par && (par->layout == layout)
3768 && (par->params.depth() == params.depth())) {
3770 par = par->previous();
3773 par = par->FirstPhysicalPar();
3775 while (par && par->params.depth() > params.depth()) {
3776 par = par->previous();
3779 par = par->FirstPhysicalPar();
3784 while (par && (par->layout == layout)
3785 && (par->params.depth() == params.depth())) {
3786 par->params.pextraType(type);
3787 par->params.pextraWidth(width);
3788 par->params.pextraWidthp(widthp);
3790 par = par->NextAfterFootnote();
3794 if (par && (par->params.depth() > params.depth()))
3795 par->SetPExtraType(bparams,
3796 type, width, widthp);
3798 while (par && ((par->params.depth() > params.depth()) || par->IsDummy()))
3799 par = par->NextAfterFootnote();
3801 while (par && par->params.depth() > params.depth())
3809 void LyXParagraph::UnsetPExtraType(BufferParams const & bparams)
3811 if (params.pextraType() == PEXTRA_NONE)
3814 params.pextraType(PEXTRA_NONE);
3815 params.pextraWidth(string());
3816 params.pextraWidthp(string());
3818 if (textclasslist.Style(bparams.textclass,
3819 layout).isEnvironment()) {
3820 LyXParagraph * par = this;
3821 LyXParagraph * ppar = par;
3823 while (par && (par->layout == layout)
3824 && (par->params.depth() == params.depth())) {
3826 par = par->previous();
3829 par = par->FirstPhysicalPar();
3831 while (par && par->params.depth() > params.depth()) {
3832 par = par->previous();
3835 par = par->FirstPhysicalPar();
3840 while (par && (par->layout == layout)
3841 && (par->params.depth() == params.depth())) {
3842 par->params.pextraType(PEXTRA_NONE);
3843 par->params.pextraWidth(string());
3844 par->params.pextraWidthp(string());
3846 par = par->NextAfterFootnote();
3850 if (par && (par->params.depth() > params.depth()))
3851 par->UnsetPExtraType(bparams);
3853 while (par && ((par->params.depth() > params.depth()) || par->IsDummy()))
3854 par = par->NextAfterFootnote();
3856 while (par && par->params.depth() > params.depth())
3865 bool LyXParagraph::IsHfill(size_type pos) const
3867 return IsHfillChar(GetChar(pos));
3871 bool LyXParagraph::IsInset(size_type pos) const
3873 return IsInsetChar(GetChar(pos));
3878 bool LyXParagraph::IsFloat(size_type pos) const
3880 return IsFloatChar(GetChar(pos));
3885 bool LyXParagraph::IsNewline(size_type pos) const
3887 return pos >= 0 && IsNewlineChar(GetChar(pos));
3891 bool LyXParagraph::IsSeparator(size_type pos) const
3893 return IsSeparatorChar(GetChar(pos));
3897 bool LyXParagraph::IsLineSeparator(size_type pos) const
3899 return IsLineSeparatorChar(GetChar(pos));
3903 bool LyXParagraph::IsKomma(size_type pos) const
3905 return IsKommaChar(GetChar(pos));
3909 /// Used by the spellchecker
3910 bool LyXParagraph::IsLetter(LyXParagraph::size_type pos) const
3912 value_type const c = GetChar(pos);
3913 if (IsLetterChar(c))
3915 // '\0' is not a letter, allthough every string contains "" (below)
3918 // We want to pass the ' and escape chars to ispell
3919 string const extra = lyxrc.isp_esc_chars + '\'';
3920 char ch[2] = { c, 0 };
3921 return contains(extra, ch);
3925 bool LyXParagraph::IsWord(size_type pos ) const
3927 return IsWordChar(GetChar(pos)) ;
3932 LyXParagraph::getParLanguage(BufferParams const & bparams) const
3936 return FirstPhysicalPar()->getParLanguage(bparams);
3940 return GetFirstFontSettings().language();
3942 return previous_->getParLanguage(bparams);
3944 return bparams.language;
3948 bool LyXParagraph::isRightToLeftPar(BufferParams const & bparams) const
3950 return lyxrc.rtl_support
3951 && getParLanguage(bparams)->RightToLeft();
3955 void LyXParagraph::ChangeLanguage(BufferParams const & bparams,
3956 Language const * from, Language const * to)
3958 for (size_type i = 0; i < size(); ++i) {
3959 LyXFont font = GetFontSettings(bparams, i);
3960 if (font.language() == from) {
3961 font.setLanguage(to);
3968 bool LyXParagraph::isMultiLingual(BufferParams const & bparams)
3970 Language const * doc_language = bparams.language;
3971 for (FontList::const_iterator cit = fontlist.begin();
3972 cit != fontlist.end(); ++cit)
3973 if ((*cit).font().language() != doc_language)
3979 // Convert the paragraph to a string.
3980 // Used for building the table of contents
3981 string const LyXParagraph::String(Buffer const * buffer, bool label)
3983 BufferParams const & bparams = buffer->params;
3986 if (label && !IsDummy() && !params.labelString().empty())
3988 if (label && !params.labelString().empty())
3990 s += params.labelString() + ' ';
3991 string::size_type const len = s.size();
3993 for (LyXParagraph::size_type i = 0; i < size(); ++i) {
3994 value_type c = GetChar(i);
3997 else if (c == META_INSET &&
3998 GetInset(i)->LyxCode() == Inset::MATH_CODE) {
3999 std::ostringstream ost;
4000 GetInset(i)->Ascii(buffer, ost);
4001 s += subst(ost.str().c_str(),'\n',' ');
4006 if (next_ && next_->footnoteflag != LyXParagraph::NO_FOOTNOTE
4007 && footnoteflag == LyXParagraph::NO_FOOTNOTE)
4008 s += NextAfterFootnote()->String(buffer, false);
4012 if (isRightToLeftPar(bparams))
4013 reverse(s.begin() + len,s.end());
4021 string const LyXParagraph::String(Buffer const * buffer,
4022 LyXParagraph::size_type beg,
4023 LyXParagraph::size_type end)
4028 if (beg == 0 && !IsDummy() && !params.labelString().empty())
4030 if (beg == 0 && !params.labelString().empty())
4032 s += params.labelString() + ' ';
4034 for (LyXParagraph::size_type i = beg; i < end; ++i) {
4035 value_type c = GetUChar(buffer->params, i);
4038 else if (c == META_INSET) {
4039 std::ostringstream ost;
4040 GetInset(i)->Ascii(buffer, ost);
4041 s += ost.str().c_str();
4049 void LyXParagraph::SetInsetOwner(Inset * i)
4052 for (InsetList::const_iterator cit = insetlist.begin();
4053 cit != insetlist.end(); ++cit) {
4055 (*cit).inset->setOwner(i);
4060 void LyXParagraph::deleteInsetsLyXText(BufferView * bv)
4063 for (InsetList::const_iterator cit = insetlist.begin();
4064 cit != insetlist.end(); ++cit) {
4066 if ((*cit).inset->IsTextInset()) {
4067 static_cast<UpdatableInset *>
4068 ((*cit).inset)->deleteLyXText(bv);
4075 void LyXParagraph::resizeInsetsLyXText(BufferView * bv)
4078 for (InsetList::const_iterator cit = insetlist.begin();
4079 cit != insetlist.end(); ++cit) {
4081 if ((*cit).inset->IsTextInset()) {
4082 static_cast<UpdatableInset *>
4083 ((*cit).inset)->resizeLyXText(bv);
4090 void LyXParagraph::fitToSize()
4092 TextContainer tmp(text.begin(), text.end());
4097 void LyXParagraph::setContentsFromPar(LyXParagraph * par)