3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Asger Alstrup
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
9 * \author Angus Leeming
11 * \author André Pönitz
13 * \author Jürgen Vigna
15 * Full author contact details are available in file CREDITS.
20 #include "paragraph.h"
21 #include "paragraph_pimpl.h"
24 #include "bufferparams.h"
29 #include "latexrunparams.h"
35 #include "insets/insetbibitem.h"
36 #include "insets/insetoptarg.h"
38 #include "support/lstrings.h"
39 #include "support/textutils.h"
40 #include "support/std_sstream.h"
44 using lyx::support::contains;
45 using lyx::support::subst;
50 using std::ostringstream;
53 Paragraph::Paragraph()
54 : y(0), pimpl_(new Paragraph::Pimpl(this))
62 Paragraph::Paragraph(Paragraph const & lp)
63 : y(0), text_(lp.text_), pimpl_(new Paragraph::Pimpl(*lp.pimpl_, this))
67 // this is because of the dummy layout of the paragraphs that
69 layout_ = lp.layout();
71 // copy everything behind the break-position to the new paragraph
72 insetlist = lp.insetlist;
73 InsetList::iterator it = insetlist.begin();
74 InsetList::iterator end = insetlist.end();
75 for (; it != end; ++it) {
76 // currently we hold Inset*, not InsetBase*
77 it->inset = static_cast<InsetOld*>(it->inset->clone().release());
82 void Paragraph::operator=(Paragraph const & lp)
84 // needed as we will destroy the pimpl_ before copying it
88 lyxerr << "Paragraph::operator=()" << endl;
93 pimpl_ = new Pimpl(*lp.pimpl_, this);
95 enumdepth = lp.enumdepth;
96 itemdepth = lp.itemdepth;
97 // this is because of the dummy layout of the paragraphs that
99 layout_ = lp.layout();
101 // copy everything behind the break-position to the new paragraph
102 insetlist = lp.insetlist;
103 InsetList::iterator it = insetlist.begin();
104 InsetList::iterator end = insetlist.end();
105 for (; it != end; ++it) {
106 it->inset = static_cast<InsetOld*>(it->inset->clone().release());
110 // the destructor removes the new paragraph from the list
111 Paragraph::~Paragraph()
115 //lyxerr << "Paragraph::paragraph_id = "
116 // << Paragraph::paragraph_id << endl;
120 void Paragraph::write(Buffer const & buf, ostream & os,
121 BufferParams const & bparams,
122 depth_type & dth) const
124 // The beginning or end of a deeper (i.e. nested) area?
125 if (dth != params().depth()) {
126 if (params().depth() > dth) {
127 while (params().depth() > dth) {
128 os << "\n\\begin_deeper ";
132 while (params().depth() < dth) {
133 os << "\n\\end_deeper ";
139 // First write the layout
140 os << "\n\\begin_layout " << layout()->name() << '\n';
144 LyXFont font1(LyXFont::ALL_INHERIT, bparams.language);
146 Change running_change = Change(Change::UNCHANGED);
147 lyx::time_type const curtime(lyx::current_time());
150 for (pos_type i = 0; i < size(); ++i) {
156 Change change = pimpl_->lookupChangeFull(i);
157 Changes::lyxMarkChange(os, column, curtime, running_change, change);
158 running_change = change;
160 // Write font changes
161 LyXFont font2 = getFontSettings(bparams, i);
162 if (font2 != font1) {
163 font2.lyxWriteChanges(font1, os);
168 value_type const c = getChar(i);
172 InsetOld const * inset = getInset(i);
174 if (inset->directWrite()) {
175 // international char, let it write
176 // code directly so it's shorter in
178 inset->write(buf, os);
180 os << "\n\\begin_inset ";
181 inset->write(buf, os);
182 os << "\n\\end_inset \n\n";
188 os << "\n\\backslash \n";
192 if (i + 1 < size() && getChar(i + 1) == ' ') {
199 if ((column > 70 && c == ' ')
204 // this check is to amend a bug. LyX sometimes
205 // inserts '\0' this could cause problems.
209 lyxerr << "ERROR (Paragraph::writeFile):"
210 " NULL char in structure." << endl;
216 // to make reading work properly
218 running_change = pimpl_->lookupChange(0);
219 Changes::lyxMarkChange(os, column, curtime,
220 Change(Change::UNCHANGED), running_change);
222 Changes::lyxMarkChange(os, column, curtime,
223 running_change, Change(Change::UNCHANGED));
225 os << "\n\\end_layout\n";
229 void Paragraph::validate(LaTeXFeatures & features) const
231 pimpl_->validate(features, *layout());
235 void Paragraph::eraseIntern(lyx::pos_type pos)
237 pimpl_->eraseIntern(pos);
241 bool Paragraph::erase(pos_type pos)
243 return pimpl_->erase(pos);
247 int Paragraph::erase(pos_type start, pos_type end)
249 return pimpl_->erase(start, end);
253 bool Paragraph::checkInsertChar(LyXFont & font)
255 if (pimpl_->inset_owner)
256 return pimpl_->inset_owner->checkInsertChar(font);
261 void Paragraph::insertChar(pos_type pos, Paragraph::value_type c)
263 insertChar(pos, c, LyXFont(LyXFont::ALL_INHERIT));
267 void Paragraph::insertChar(pos_type pos, Paragraph::value_type c,
268 LyXFont const & font, Change change)
270 pimpl_->insertChar(pos, c, font, change);
274 void Paragraph::insertInset(pos_type pos, InsetOld * inset)
276 insertInset(pos, inset, LyXFont(LyXFont::ALL_INHERIT));
280 void Paragraph::insertInset(pos_type pos, InsetOld * inset,
281 LyXFont const & font, Change change)
283 pimpl_->insertInset(pos, inset, font, change);
287 bool Paragraph::insetAllowed(InsetOld::Code code)
289 //lyxerr << "Paragraph::InsertInsetAllowed" << endl;
290 if (pimpl_->inset_owner)
291 return pimpl_->inset_owner->insetAllowed(code);
296 InsetOld * Paragraph::getInset(pos_type pos)
298 BOOST_ASSERT(pos < size());
299 return insetlist.get(pos);
303 InsetOld const * Paragraph::getInset(pos_type pos) const
305 BOOST_ASSERT(pos < size());
306 return insetlist.get(pos);
310 // Gets uninstantiated font setting at position.
311 LyXFont const Paragraph::getFontSettings(BufferParams const & bparams,
314 BOOST_ASSERT(pos <= size());
316 Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin();
317 Pimpl::FontList::const_iterator end = pimpl_->fontlist.end();
318 for (; cit != end; ++cit)
319 if (cit->pos() >= pos)
325 if (pos == size() && !empty())
326 return getFontSettings(bparams, pos - 1);
328 return LyXFont(LyXFont::ALL_INHERIT, getParLanguage(bparams));
332 lyx::pos_type Paragraph::getEndPosOfFontSpan(lyx::pos_type pos) const
334 BOOST_ASSERT(pos <= size());
336 Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin();
337 Pimpl::FontList::const_iterator end = pimpl_->fontlist.end();
338 for (; cit != end; ++cit)
339 if (cit->pos() >= pos)
342 // This should not happen, but if so, we take no chances.
343 //lyxerr << "Paragraph::getEndPosOfFontSpan: This should not happen!"
349 // Gets uninstantiated font setting at position 0
350 LyXFont const Paragraph::getFirstFontSettings() const
352 if (!empty() && !pimpl_->fontlist.empty())
353 return pimpl_->fontlist[0].font();
355 return LyXFont(LyXFont::ALL_INHERIT);
359 // Gets the fully instantiated font at a given position in a paragraph
360 // This is basically the same function as LyXText::GetFont() in text2.C.
361 // The difference is that this one is used for generating the LaTeX file,
362 // and thus cosmetic "improvements" are disallowed: This has to deliver
363 // the true picture of the buffer. (Asger)
364 LyXFont const Paragraph::getFont(BufferParams const & bparams, pos_type pos,
365 LyXFont const & outerfont) const
367 BOOST_ASSERT(pos >= 0);
369 LyXLayout_ptr const & lout = layout();
371 pos_type const body_pos = beginningOfBody();
375 layoutfont = lout->labelfont;
377 layoutfont = lout->font;
379 LyXFont tmpfont = getFontSettings(bparams, pos);
380 tmpfont.realize(layoutfont);
381 tmpfont.realize(outerfont);
382 tmpfont.realize(bparams.getLyXTextClass().defaultfont());
388 LyXFont const Paragraph::getLabelFont(BufferParams const & bparams,
389 LyXFont const & outerfont) const
391 LyXFont tmpfont = layout()->labelfont;
392 tmpfont.setLanguage(getParLanguage(bparams));
393 tmpfont.realize(outerfont);
394 tmpfont.realize(bparams.getLyXTextClass().defaultfont());
399 LyXFont const Paragraph::getLayoutFont(BufferParams const & bparams,
400 LyXFont const & outerfont) const
402 LyXFont tmpfont = layout()->font;
403 tmpfont.setLanguage(getParLanguage(bparams));
404 tmpfont.realize(outerfont);
405 tmpfont.realize(bparams.getLyXTextClass().defaultfont());
410 /// Returns the height of the highest font in range
412 Paragraph::highestFontInRange(pos_type startpos, pos_type endpos,
413 LyXFont_size def_size) const
415 if (pimpl_->fontlist.empty())
418 Pimpl::FontList::const_iterator end_it = pimpl_->fontlist.begin();
419 Pimpl::FontList::const_iterator end = pimpl_->fontlist.end();
420 for (; end_it != end; ++end_it) {
421 if (end_it->pos() >= endpos)
428 Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin();
429 for (; cit != end; ++cit) {
430 if (cit->pos() >= startpos)
434 LyXFont::FONT_SIZE maxsize = LyXFont::SIZE_TINY;
435 for (; cit != end_it; ++cit) {
436 LyXFont::FONT_SIZE size = cit->font().size();
437 if (size == LyXFont::INHERIT_SIZE)
439 if (size > maxsize && size <= LyXFont::SIZE_HUGER)
446 Paragraph::value_type
447 Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const
449 value_type c = getChar(pos);
450 if (!lyxrc.rtl_support)
480 if (uc != c && getFontSettings(bparams, pos).isRightToLeft())
487 void Paragraph::setFont(pos_type pos, LyXFont const & font)
489 BOOST_ASSERT(pos <= size());
491 // First, reduce font against layout/label font
492 // Update: The SetCharFont() routine in text2.C already
493 // reduces font, so we don't need to do that here. (Asger)
494 // No need to simplify this because it will disappear
495 // in a new kernel. (Asger)
496 // Next search font table
498 Pimpl::FontList::iterator beg = pimpl_->fontlist.begin();
499 Pimpl::FontList::iterator it = beg;
500 Pimpl::FontList::iterator endit = pimpl_->fontlist.end();
501 for (; it != endit; ++it) {
502 if (it->pos() >= pos)
505 unsigned int i = std::distance(beg, it);
506 bool notfound = (it == endit);
508 if (!notfound && pimpl_->fontlist[i].font() == font)
511 bool begin = pos == 0 || notfound ||
512 (i > 0 && pimpl_->fontlist[i - 1].pos() == pos - 1);
513 // Is position pos is a beginning of a font block?
514 bool end = !notfound && pimpl_->fontlist[i].pos() == pos;
515 // Is position pos is the end of a font block?
516 if (begin && end) { // A single char block
517 if (i + 1 < pimpl_->fontlist.size() &&
518 pimpl_->fontlist[i + 1].font() == font) {
519 // Merge the singleton block with the next block
520 pimpl_->fontlist.erase(pimpl_->fontlist.begin() + i);
521 if (i > 0 && pimpl_->fontlist[i - 1].font() == font)
522 pimpl_->fontlist.erase(pimpl_->fontlist.begin() + i - 1);
523 } else if (i > 0 && pimpl_->fontlist[i - 1].font() == font) {
524 // Merge the singleton block with the previous block
525 pimpl_->fontlist[i - 1].pos(pos);
526 pimpl_->fontlist.erase(pimpl_->fontlist.begin() + i);
528 pimpl_->fontlist[i].font(font);
530 if (i > 0 && pimpl_->fontlist[i - 1].font() == font)
531 pimpl_->fontlist[i - 1].pos(pos);
533 pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i,
534 Pimpl::FontTable(pos, font));
536 pimpl_->fontlist[i].pos(pos - 1);
537 if (!(i + 1 < pimpl_->fontlist.size() &&
538 pimpl_->fontlist[i + 1].font() == font))
539 pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i + 1,
540 Pimpl::FontTable(pos, font));
541 } else { // The general case. The block is splitted into 3 blocks
542 pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i,
543 Pimpl::FontTable(pos - 1, pimpl_->fontlist[i].font()));
544 pimpl_->fontlist.insert(pimpl_->fontlist.begin() + i + 1,
545 Pimpl::FontTable(pos, font));
550 void Paragraph::makeSameLayout(Paragraph const & par)
552 layout(par.layout());
554 params() = par.params();
558 int Paragraph::stripLeadingSpaces()
564 while (!empty() && (isNewline(0) || isLineSeparator(0))) {
565 pimpl_->eraseIntern(0);
573 bool Paragraph::hasSameLayout(Paragraph const & par) const
576 par.layout() == layout() &&
577 params().sameLayout(par.params());
581 Paragraph::depth_type Paragraph::getDepth() const
583 return params().depth();
587 Paragraph::depth_type Paragraph::getMaxDepthAfter() const
589 if (layout()->isEnvironment())
590 return params().depth() + 1;
592 return params().depth();
596 char Paragraph::getAlign() const
598 return params().align();
602 string const & Paragraph::getLabelstring() const
604 return params().labelString();
608 // the next two functions are for the manual labels
609 string const Paragraph::getLabelWidthString() const
611 if (!params().labelWidthString().empty())
612 return params().labelWidthString();
614 return _("Senseless with this layout!");
618 void Paragraph::setLabelWidthString(string const & s)
620 params().labelWidthString(s);
624 void Paragraph::applyLayout(LyXLayout_ptr const & new_layout)
627 params().labelWidthString(string());
628 params().align(LYX_ALIGN_LAYOUT);
629 params().spaceTop(VSpace(VSpace::NONE));
630 params().spaceBottom(VSpace(VSpace::NONE));
631 params().spacing(Spacing(Spacing::Default));
635 int Paragraph::beginningOfBody() const
637 if (layout()->labeltype != LABEL_MANUAL)
640 // Unroll the first two cycles of the loop
641 // and remember the previous character to
642 // remove unnecessary GetChar() calls
644 if (i < size() && !isNewline(i)) {
646 char previous_char = 0;
649 previous_char = getChar(i);
652 while (i < size() && previous_char != ' ') {
658 previous_char = temp;
668 // returns -1 if inset not found
669 int Paragraph::getPositionOfInset(InsetOld const * inset) const
672 InsetList::const_iterator it = insetlist.begin();
673 InsetList::const_iterator end = insetlist.end();
674 for (; it != end; ++it)
675 if (it->inset == inset)
681 InsetBibitem * Paragraph::bibitem() const
683 InsetList::const_iterator it = insetlist.begin();
684 if (it != insetlist.end() && it->inset->lyxCode() == InsetOld::BIBTEX_CODE)
685 return static_cast<InsetBibitem *>(it->inset);
691 // This could go to ParagraphParameters if we want to
692 int Paragraph::startTeXParParams(BufferParams const & bparams,
693 ostream & os, bool moving_arg) const
697 if (params().noindent()) {
702 switch (params().align()) {
704 case LYX_ALIGN_BLOCK:
705 case LYX_ALIGN_LAYOUT:
706 case LYX_ALIGN_SPECIAL:
709 case LYX_ALIGN_RIGHT:
710 case LYX_ALIGN_CENTER:
718 switch (params().align()) {
720 case LYX_ALIGN_BLOCK:
721 case LYX_ALIGN_LAYOUT:
722 case LYX_ALIGN_SPECIAL:
725 if (getParLanguage(bparams)->babel() != "hebrew") {
726 os << "\\begin{flushleft}";
729 os << "\\begin{flushright}";
733 case LYX_ALIGN_RIGHT:
734 if (getParLanguage(bparams)->babel() != "hebrew") {
735 os << "\\begin{flushright}";
738 os << "\\begin{flushleft}";
742 case LYX_ALIGN_CENTER:
743 os << "\\begin{center}";
752 // This could go to ParagraphParameters if we want to
753 int Paragraph::endTeXParParams(BufferParams const & bparams,
754 ostream & os, bool moving_arg) const
758 switch (params().align()) {
760 case LYX_ALIGN_BLOCK:
761 case LYX_ALIGN_LAYOUT:
762 case LYX_ALIGN_SPECIAL:
765 case LYX_ALIGN_RIGHT:
766 case LYX_ALIGN_CENTER:
774 switch (params().align()) {
776 case LYX_ALIGN_BLOCK:
777 case LYX_ALIGN_LAYOUT:
778 case LYX_ALIGN_SPECIAL:
781 if (getParLanguage(bparams)->babel() != "hebrew") {
782 os << "\\end{flushleft}";
785 os << "\\end{flushright}";
789 case LYX_ALIGN_RIGHT:
790 if (getParLanguage(bparams)->babel() != "hebrew") {
791 os << "\\end{flushright}";
794 os << "\\end{flushleft}";
798 case LYX_ALIGN_CENTER:
799 os << "\\end{center}";
807 // This one spits out the text of the paragraph
808 bool Paragraph::simpleTeXOnePar(Buffer const & buf,
809 BufferParams const & bparams,
810 LyXFont const & outerfont,
811 ostream & os, TexRow & texrow,
812 LatexRunParams const & runparams)
814 lyxerr[Debug::LATEX] << "SimpleTeXOnePar... " << this << endl;
816 bool return_value = false;
820 // well we have to check if we are in an inset with unlimited
821 // lenght (all in one row) if that is true then we don't allow
822 // any special options in the paragraph and also we don't allow
823 // any environment other then "Standard" to be valid!
825 (inInset() && inInset()->forceDefaultParagraphs(inInset()));
828 style = bparams.getLyXTextClass().defaultLayout();
835 // Maybe we have to create a optional argument.
838 // FIXME: can we actually skip this check and just call
839 // beginningOfBody() ??
840 if (style->labeltype != LABEL_MANUAL) {
843 body_pos = beginningOfBody();
846 unsigned int column = 0;
851 basefont = getLabelFont(bparams, outerfont);
853 basefont = getLayoutFont(bparams, outerfont);
856 bool moving_arg = runparams.moving_arg;
857 moving_arg |= style->needprotect;
859 // Which font is currently active?
860 LyXFont running_font(basefont);
861 // Do we have an open font change?
862 bool open_font = false;
864 Change::Type running_change = Change::UNCHANGED;
866 texrow.start(id(), 0);
868 // if the paragraph is empty, the loop will not be entered at all
870 if (style->isCommand()) {
875 column += startTeXParParams(bparams, os, moving_arg);
879 for (pos_type i = 0; i < size(); ++i) {
881 // First char in paragraph or after label?
885 column += running_font.latexWriteEndChanges(os, basefont, basefont);
888 basefont = getLayoutFont(bparams, outerfont);
889 running_font = basefont;
893 if (style->isCommand()) {
899 column += startTeXParParams(bparams, os,
903 value_type c = getChar(i);
905 // Fully instantiated font
906 LyXFont font = getFont(bparams, i, outerfont);
908 LyXFont const last_font = running_font;
910 // Spaces at end of font change are simulated to be
911 // outside font change, i.e. we write "\textXX{text} "
912 // rather than "\textXX{text }". (Asger)
913 if (open_font && c == ' ' && i <= size() - 2) {
914 LyXFont const & next_font = getFont(bparams, i + 1, outerfont);
915 if (next_font != running_font
916 && next_font != font) {
921 // We end font definition before blanks
923 (font != running_font ||
924 font.language() != running_font.language()))
926 column += running_font.latexWriteEndChanges(os,
928 (i == body_pos-1) ? basefont : font);
929 running_font = basefont;
933 // Blanks are printed before start of fontswitch
935 // Do not print the separation of the optional argument
936 if (i != body_pos - 1) {
937 pimpl_->simpleTeXBlanks(os, texrow, i,
938 column, font, *style);
942 // Do we need to change font?
943 if ((font != running_font ||
944 font.language() != running_font.language()) &&
947 column += font.latexWriteStartChanges(os, basefont,
953 Change::Type change = pimpl_->lookupChange(i);
955 column += Changes::latexMarkChange(os, running_change, change);
956 running_change = change;
958 LatexRunParams rp = runparams;
959 rp.moving_arg = moving_arg;
960 rp.free_spacing = style->free_spacing;
961 pimpl_->simpleTeXSpecialChars(buf, bparams,
962 os, texrow, runparams,
964 basefont, outerfont, open_font,
966 *style, i, column, c);
969 column += Changes::latexMarkChange(os,
970 running_change, Change::UNCHANGED);
972 // If we have an open font definition, we have to close it
974 #ifdef FIXED_LANGUAGE_END_DETECTION
977 .latexWriteEndChanges(os, basefont,
978 next_->getFont(bparams,
981 running_font.latexWriteEndChanges(os, basefont,
986 //#warning For now we ALWAYS have to close the foreign font settings if they are
987 //#warning there as we start another \selectlanguage with the next paragraph if
988 //#warning we are in need of this. This should be fixed sometime (Jug)
990 running_font.latexWriteEndChanges(os, basefont, basefont);
994 // Needed if there is an optional argument but no contents.
995 if (body_pos > 0 && body_pos == size()) {
997 return_value = false;
1001 column += endTeXParParams(bparams, os, moving_arg);
1004 lyxerr[Debug::LATEX] << "SimpleTeXOnePar...done " << this << endl;
1005 return return_value;
1011 /// return true if the char is a meta-character for an inset
1013 bool IsInsetChar(char c)
1015 return (c == Paragraph::META_INSET);
1022 bool Paragraph::isHfill(pos_type pos) const
1024 return IsInsetChar(getChar(pos))
1025 && getInset(pos)->lyxCode() == InsetOld::HFILL_CODE;
1029 bool Paragraph::isInset(pos_type pos) const
1031 return IsInsetChar(getChar(pos));
1035 bool Paragraph::isNewline(pos_type pos) const
1037 return IsInsetChar(getChar(pos))
1038 && getInset(pos)->lyxCode() == InsetOld::NEWLINE_CODE;
1042 bool Paragraph::isSeparator(pos_type pos) const
1044 return IsSeparatorChar(getChar(pos));
1048 bool Paragraph::isLineSeparator(pos_type pos) const
1050 value_type const c = getChar(pos);
1051 return IsLineSeparatorChar(c)
1052 || (IsInsetChar(c) && getInset(pos) &&
1053 getInset(pos)->isLineSeparator());
1057 bool Paragraph::isKomma(pos_type pos) const
1059 return IsKommaChar(getChar(pos));
1063 /// Used by the spellchecker
1064 bool Paragraph::isLetter(pos_type pos) const
1066 value_type const c = getChar(pos);
1067 if (IsLetterChar(c))
1070 return getInset(pos)->isLetter();
1071 // We want to pass the ' and escape chars to ispell
1072 string const extra = lyxrc.isp_esc_chars + '\'';
1073 return contains(extra, c);
1077 bool Paragraph::isWord(pos_type pos) const
1079 unsigned char const c = getChar(pos);
1080 return !(IsSeparatorChar(c)
1087 Paragraph::getParLanguage(BufferParams const & bparams) const
1090 return getFirstFontSettings().language();
1091 #warning FIXME we should check the prev par as well (Lgb)
1092 return bparams.language;
1096 bool Paragraph::isRightToLeftPar(BufferParams const & bparams) const
1098 return lyxrc.rtl_support
1099 && getParLanguage(bparams)->RightToLeft()
1100 && !(inInset() && inInset()->owner() &&
1101 inInset()->owner()->lyxCode() == InsetOld::ERT_CODE);
1105 void Paragraph::changeLanguage(BufferParams const & bparams,
1106 Language const * from, Language const * to)
1108 for (pos_type i = 0; i < size(); ++i) {
1109 LyXFont font = getFontSettings(bparams, i);
1110 if (font.language() == from) {
1111 font.setLanguage(to);
1118 bool Paragraph::isMultiLingual(BufferParams const & bparams)
1120 Language const * doc_language = bparams.language;
1121 Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin();
1122 Pimpl::FontList::const_iterator end = pimpl_->fontlist.end();
1124 for (; cit != end; ++cit)
1125 if (cit->font().language() != ignore_language &&
1126 cit->font().language() != latex_language &&
1127 cit->font().language() != doc_language)
1133 // Convert the paragraph to a string.
1134 // Used for building the table of contents
1135 string const Paragraph::asString(Buffer const & buffer, bool label) const
1139 if (label && !params().labelString().empty())
1140 s += params().labelString() + ' ';
1142 for (pos_type i = 0; i < size(); ++i) {
1143 value_type c = getChar(i);
1146 else if (c == META_INSET &&
1147 getInset(i)->lyxCode() == InsetOld::MATH_CODE) {
1149 getInset(i)->ascii(buffer, ost);
1150 s += subst(STRCONV(ost.str()),'\n',' ');
1156 // This should really be done by the caller and not here.
1157 string ret(asString(buffer, 0, size(), label));
1158 return subst(ret, '\n', ' ');
1163 string const Paragraph::asString(Buffer const & buffer,
1164 pos_type beg, pos_type end, bool label) const
1168 if (beg == 0 && label && !params().labelString().empty())
1169 os << params().labelString() << ' ';
1171 for (pos_type i = beg; i < end; ++i) {
1172 value_type const c = getUChar(buffer.params(), i);
1175 else if (c == META_INSET)
1176 getInset(i)->ascii(buffer, os);
1183 void Paragraph::setInsetOwner(UpdatableInset * inset)
1185 pimpl_->inset_owner = inset;
1186 InsetList::iterator it = insetlist.begin();
1187 InsetList::iterator end = insetlist.end();
1188 for (; it != end; ++it)
1190 it->inset->setOwner(inset);
1194 void Paragraph::deleteInsetsLyXText(BufferView * bv)
1196 insetlist.deleteInsetsLyXText(bv);
1200 void Paragraph::setContentsFromPar(Paragraph const & par)
1202 pimpl_->setContentsFromPar(par);
1206 void Paragraph::trackChanges(Change::Type type)
1208 pimpl_->trackChanges(type);
1212 void Paragraph::untrackChanges()
1214 pimpl_->untrackChanges();
1218 void Paragraph::cleanChanges()
1220 pimpl_->cleanChanges();
1224 Change::Type Paragraph::lookupChange(lyx::pos_type pos) const
1226 BOOST_ASSERT(!size() || pos < size());
1227 return pimpl_->lookupChange(pos);
1231 Change const Paragraph::lookupChangeFull(lyx::pos_type pos) const
1233 BOOST_ASSERT(!size() || pos < size());
1234 return pimpl_->lookupChangeFull(pos);
1238 bool Paragraph::isChanged(pos_type start, pos_type end) const
1240 return pimpl_->isChanged(start, end);
1244 bool Paragraph::isChangeEdited(pos_type start, pos_type end) const
1246 return pimpl_->isChangeEdited(start, end);
1250 void Paragraph::setChange(lyx::pos_type pos, Change::Type type)
1252 pimpl_->setChange(pos, type);
1257 void Paragraph::markErased()
1259 pimpl_->markErased();
1263 void Paragraph::acceptChange(pos_type start, pos_type end)
1265 return pimpl_->acceptChange(start, end);
1269 void Paragraph::rejectChange(pos_type start, pos_type end)
1271 return pimpl_->rejectChange(start, end);
1275 Paragraph::value_type Paragraph::getChar(pos_type pos) const
1277 // This is in the critical path!
1278 pos_type const siz = text_.size();
1280 BOOST_ASSERT(pos <= siz);
1283 lyxerr << "getChar() on pos " << pos << " in par id "
1284 << id() << " of size " << siz
1285 << " is a bit silly !" << endl;
1293 int Paragraph::id() const
1299 void Paragraph::id(int i)
1305 LyXLayout_ptr const & Paragraph::layout() const
1308 InsetOld * inset = inInset();
1309 if (inset && inset->lyxCode() == InsetOld::ENVIRONMENT_CODE)
1310 return static_cast<InsetEnvironment*>(inset)->layout();
1316 void Paragraph::layout(LyXLayout_ptr const & new_layout)
1318 layout_ = new_layout;
1322 UpdatableInset * Paragraph::inInset() const
1324 return pimpl_->inset_owner;
1328 void Paragraph::clearContents()
1334 void Paragraph::setChar(pos_type pos, value_type c)
1340 ParagraphParameters & Paragraph::params()
1342 return pimpl_->params;
1346 ParagraphParameters const & Paragraph::params() const
1348 return pimpl_->params;
1352 bool Paragraph::isFreeSpacing() const
1354 if (layout()->free_spacing)
1357 // for now we just need this, later should we need this in some
1358 // other way we can always add a function to InsetOld too.
1359 if (pimpl_->inset_owner && pimpl_->inset_owner->owner())
1360 return pimpl_->inset_owner->owner()->lyxCode() == InsetOld::ERT_CODE;
1365 bool Paragraph::allowEmpty() const
1367 if (layout()->keepempty)
1369 if (pimpl_->inset_owner && pimpl_->inset_owner->owner())
1370 return pimpl_->inset_owner->owner()->lyxCode() == InsetOld::ERT_CODE;