X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fparagraph.C;h=1a6cdfc35a5a61713500709dde8b7fd92b9414e3;hb=b1be8f3cb0486b659ff7e35601d2ed74d3ce29e0;hp=0d12383a6cbc92ce68d0db116602fde1203ebfea;hpb=40df68631241c4bda3b45a27f333eda5d4e10a1a;p=lyx.git diff --git a/src/paragraph.C b/src/paragraph.C index 0d12383a6c..1a6cdfc35a 100644 --- a/src/paragraph.C +++ b/src/paragraph.C @@ -1,12 +1,19 @@ -/* This file is part of - * ====================================================== +/** + * \file paragraph.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. * - * LyX, The Document Processor + * \author Asger Alstrup + * \author Lars Gullik Bjønnes + * \author Jean-Marc Lasgouttes + * \author Angus Leeming + * \author John Levon + * \author André Pönitz + * \author Dekel Tsur + * \author Jürgen Vigna * - * Copyright 1995 Matthias Ettrich - * Copyright 1995-2001 The LyX Team. - * - * ====================================================== */ + * Full author contact details are available in file CREDITS. + */ #include @@ -15,98 +22,105 @@ #include "buffer.h" #include "bufferparams.h" -#include "BufferView.h" -#include "changes.h" +#include "counters.h" #include "encoding.h" #include "debug.h" #include "gettext.h" #include "language.h" -#include "latexrunparams.h" -#include "layout.h" +#include "lyxfont.h" #include "lyxrc.h" +#include "lyxrow.h" +#include "outputparams.h" #include "paragraph_funcs.h" -#include "ParameterStruct.h" +#include "ParagraphList_fwd.h" +#include "sgml.h" #include "texrow.h" - -#include "Lsstream.h" +#include "vspace.h" #include "insets/insetbibitem.h" #include "insets/insetoptarg.h" -#include "insets/insetenv.h" -#include "support/filetools.h" #include "support/lstrings.h" -#include "support/lyxmanip.h" -#include "support/FileInfo.h" -#include "support/LAssert.h" #include "support/textutils.h" +#include "support/tostr.h" -#include -#include -#include -#include +#include +#include -using std::ostream; -using std::endl; -using std::fstream; -using std::ios; -using std::lower_bound; -using std::upper_bound; +#include +#include +#include using lyx::pos_type; +using lyx::support::contains; +using lyx::support::subst; -// this is a minibuffer - -namespace { +using std::distance; +using std::endl; +using std::list; +using std::stack; +using std::string; +using std::ostream; +using std::ostringstream; -char minibuffer_char; -LyXFont minibuffer_font; -Inset * minibuffer_inset; -} // namespace anon +ParagraphList::ParagraphList() +{} Paragraph::Paragraph() - : pimpl_(new Paragraph::Pimpl(this)) + : y(0), height(0), begin_of_body_(0), + pimpl_(new Paragraph::Pimpl(this)) { -#ifdef NO_STD_LIST - next_par_ = 0; - prev_par_ = 0; -#endif - enumdepth = 0; + //lyxerr << "sizeof Paragraph::Pimpl: " << sizeof(Paragraph::Pimpl) << endl; itemdepth = 0; params().clear(); } -Paragraph::Paragraph(Paragraph const & lp, bool same_ids) - : pimpl_(new Paragraph::Pimpl(*lp.pimpl_, this, same_ids)) +Paragraph::Paragraph(Paragraph const & par) + : itemdepth(par.itemdepth), insetlist(par.insetlist), + rows(par.rows), y(par.y), height(par.height), + width(par.width), layout_(par.layout_), + text_(par.text_), begin_of_body_(par.begin_of_body_), + pimpl_(new Paragraph::Pimpl(*par.pimpl_, this)) { - enumdepth = 0; - itemdepth = 0; -#ifdef NO_STD_LIST - next_par_ = 0; - prev_par_ = 0; -#endif - // this is because of the dummy layout of the paragraphs that - // follow footnotes - layout_ = lp.layout(); - buffer_ = lp.buffer_; - - // copy everything behind the break-position to the new paragraph - insetlist = lp.insetlist; + //lyxerr << "Paragraph::Paragraph(Paragraph const&)" << endl; InsetList::iterator it = insetlist.begin(); InsetList::iterator end = insetlist.end(); - for (; it != end; ++it) { - it.setInset(it.getInset()->clone(**buffer_, same_ids)); - // tell the new inset who is the boss now - it.getInset()->parOwner(this); + for (; it != end; ++it) + it->inset = it->inset->clone().release(); +} + + +Paragraph & Paragraph::operator=(Paragraph const & par) +{ + // needed as we will destroy the pimpl_ before copying it + if (&par != this) { + itemdepth = par.itemdepth; + + insetlist = par.insetlist; + InsetList::iterator it = insetlist.begin(); + InsetList::iterator end = insetlist.end(); + for (; it != end; ++it) + it->inset = it->inset->clone().release(); + + rows = par.rows; + y = par.y; + height = par.height; + width = par.width; + layout_ = par.layout(); + text_ = par.text_; + begin_of_body_ = par.begin_of_body_; + + delete pimpl_; + pimpl_ = new Pimpl(*par.pimpl_, this); } + return *this; } -// the destructor removes the new paragraph from the list Paragraph::~Paragraph() { delete pimpl_; @@ -116,7 +130,7 @@ Paragraph::~Paragraph() } -void Paragraph::write(Buffer const * buf, ostream & os, +void Paragraph::write(Buffer const & buf, ostream & os, BufferParams const & bparams, depth_type & dth) const { @@ -136,7 +150,7 @@ void Paragraph::write(Buffer const * buf, ostream & os, } // First write the layout - os << "\n\\layout " << layout()->name() << '\n'; + os << "\n\\begin_layout " << layout()->name() << '\n'; params().write(os); @@ -168,7 +182,7 @@ void Paragraph::write(Buffer const * buf, ostream & os, switch (c) { case META_INSET: { - Inset const * inset = getInset(i); + InsetBase const * inset = getInset(i); if (inset) if (inset->directWrite()) { // international char, let it write @@ -220,6 +234,8 @@ void Paragraph::write(Buffer const * buf, ostream & os, } Changes::lyxMarkChange(os, column, curtime, running_change, Change(Change::UNCHANGED)); + + os << "\n\\end_layout\n"; } @@ -229,68 +245,6 @@ void Paragraph::validate(LaTeXFeatures & features) const } -// First few functions needed for cut and paste and paragraph breaking. -void Paragraph::copyIntoMinibuffer(Buffer const & buffer, pos_type pos) const -{ - BufferParams bparams = buffer.params; - - minibuffer_char = getChar(pos); - minibuffer_font = getFontSettings(bparams, pos); - minibuffer_inset = 0; - if (minibuffer_char == Paragraph::META_INSET) { - if (getInset(pos)) { - minibuffer_inset = getInset(pos)->clone(buffer); - } else { - minibuffer_inset = 0; - minibuffer_char = ' '; - // This reflects what GetInset() does (ARRae) - } - } -} - - -void Paragraph::cutIntoMinibuffer(BufferParams const & bparams, pos_type pos) -{ - minibuffer_char = getChar(pos); - minibuffer_font = getFontSettings(bparams, pos); - minibuffer_inset = 0; - if (minibuffer_char == Paragraph::META_INSET) { - if (getInset(pos)) { - // the inset is not in a paragraph anymore - minibuffer_inset = insetlist.release(pos); - minibuffer_inset->parOwner(0); - } else { - minibuffer_inset = 0; - minibuffer_char = ' '; - // This reflects what GetInset() does (ARRae) - } - - } - - // Erase(pos); now the caller is responsible for that. -} - - -bool Paragraph::insertFromMinibuffer(pos_type pos) -{ - if (minibuffer_char == Paragraph::META_INSET) { - if (!insetAllowed(minibuffer_inset->lyxCode())) { - return false; - } - insertInset(pos, minibuffer_inset, minibuffer_font); - } else { - LyXFont f = minibuffer_font; - if (!checkInsertChar(f)) { - return false; - } - insertChar(pos, minibuffer_char, f); - } - return true; -} - -// end of minibuffer - - void Paragraph::eraseIntern(lyx::pos_type pos) { pimpl_->eraseIntern(pos); @@ -309,18 +263,24 @@ int Paragraph::erase(pos_type start, pos_type end) } -bool Paragraph::checkInsertChar(LyXFont & font) +void Paragraph::insert(pos_type start, string const & str, + LyXFont const & font) +{ + int size = str.size(); + for (int i = 0 ; i < size ; ++i) + insertChar(start + i, str[i], font); +} + + +bool Paragraph::checkInsertChar(LyXFont &) { - if (pimpl_->inset_owner) - return pimpl_->inset_owner->checkInsertChar(font); return true; } void Paragraph::insertChar(pos_type pos, Paragraph::value_type c) { - LyXFont const f(LyXFont::ALL_INHERIT); - insertChar(pos, c, f); + insertChar(pos, c, LyXFont(LyXFont::ALL_INHERIT)); } @@ -331,38 +291,35 @@ void Paragraph::insertChar(pos_type pos, Paragraph::value_type c, } -void Paragraph::insertInset(pos_type pos, Inset * inset) +void Paragraph::insertInset(pos_type pos, InsetBase * inset) { - LyXFont const f(LyXFont::ALL_INHERIT); - insertInset(pos, inset, f); + insertInset(pos, inset, LyXFont(LyXFont::ALL_INHERIT)); } -void Paragraph::insertInset(pos_type pos, Inset * inset, LyXFont const & font, Change change) +void Paragraph::insertInset(pos_type pos, InsetBase * inset, + LyXFont const & font, Change change) { pimpl_->insertInset(pos, inset, font, change); } -bool Paragraph::insetAllowed(Inset::Code code) +bool Paragraph::insetAllowed(InsetOld_code code) { - //lyxerr << "Paragraph::InsertInsetAllowed" << endl; - if (pimpl_->inset_owner) - return pimpl_->inset_owner->insetAllowed(code); - return true; + return !pimpl_->inset_owner || pimpl_->inset_owner->insetAllowed(code); } -Inset * Paragraph::getInset(pos_type pos) +InsetBase * Paragraph::getInset(pos_type pos) { - lyx::Assert(pos < size()); + BOOST_ASSERT(pos < size()); return insetlist.get(pos); } -Inset const * Paragraph::getInset(pos_type pos) const +InsetBase const * Paragraph::getInset(pos_type pos) const { - lyx::Assert(pos < size()); + BOOST_ASSERT(pos < size()); return insetlist.get(pos); } @@ -371,24 +328,41 @@ Inset const * Paragraph::getInset(pos_type pos) const LyXFont const Paragraph::getFontSettings(BufferParams const & bparams, pos_type pos) const { - lyx::Assert(pos <= size()); + if (pos > size()) { + lyxerr << " pos: " << pos << " size: " << size() << endl; + BOOST_ASSERT(pos <= size()); + } Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin(); Pimpl::FontList::const_iterator end = pimpl_->fontlist.end(); - for (; cit != end; ++cit) { + for (; cit != end; ++cit) if (cit->pos() >= pos) break; - } - LyXFont retfont; if (cit != end) - retfont = cit->font(); - else if (pos == size() && !empty()) - retfont = getFontSettings(bparams, pos - 1); - else - retfont = LyXFont(LyXFont::ALL_INHERIT, getParLanguage(bparams)); + return cit->font(); - return retfont; + if (pos == size() && !empty()) + return getFontSettings(bparams, pos - 1); + + return LyXFont(LyXFont::ALL_INHERIT, getParLanguage(bparams)); +} + + +lyx::pos_type Paragraph::getEndPosOfFontSpan(lyx::pos_type pos) const +{ + BOOST_ASSERT(pos <= size()); + + Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin(); + Pimpl::FontList::const_iterator end = pimpl_->fontlist.end(); + for (; cit != end; ++cit) + if (cit->pos() >= pos) + return cit->pos(); + + // This should not happen, but if so, we take no chances. + //lyxerr << "Paragraph::getEndPosOfFontSpan: This should not happen!" + // << endl; + return pos; } @@ -410,11 +384,11 @@ LyXFont const Paragraph::getFirstFontSettings() const LyXFont const Paragraph::getFont(BufferParams const & bparams, pos_type pos, LyXFont const & outerfont) const { - lyx::Assert(pos >= 0); + BOOST_ASSERT(pos >= 0); LyXLayout_ptr const & lout = layout(); - pos_type const body_pos = beginningOfBody(); + pos_type const body_pos = beginOfBody(); LyXFont layoutfont; if (pos < body_pos) @@ -422,50 +396,47 @@ LyXFont const Paragraph::getFont(BufferParams const & bparams, pos_type pos, else layoutfont = lout->font; - LyXFont tmpfont = getFontSettings(bparams, pos); - tmpfont.realize(layoutfont); - tmpfont.realize(outerfont); + LyXFont font = getFontSettings(bparams, pos); + font.realize(layoutfont); + font.realize(outerfont); + font.realize(bparams.getLyXTextClass().defaultfont()); - return realizeFont(tmpfont, bparams); + return font; } LyXFont const Paragraph::getLabelFont(BufferParams const & bparams, LyXFont const & outerfont) const { - LyXLayout_ptr const & lout = layout(); - - LyXFont tmpfont = lout->labelfont; + LyXFont tmpfont = layout()->labelfont; tmpfont.setLanguage(getParLanguage(bparams)); tmpfont.realize(outerfont); - - return realizeFont(tmpfont, bparams); + tmpfont.realize(bparams.getLyXTextClass().defaultfont()); + return tmpfont; } LyXFont const Paragraph::getLayoutFont(BufferParams const & bparams, LyXFont const & outerfont) const { - LyXLayout_ptr const & lout = layout(); - - LyXFont tmpfont = lout->font; + LyXFont tmpfont = layout()->font; tmpfont.setLanguage(getParLanguage(bparams)); tmpfont.realize(outerfont); - - return realizeFont(tmpfont, bparams); + tmpfont.realize(bparams.getLyXTextClass().defaultfont()); + return tmpfont; } /// Returns the height of the highest font in range -LyXFont::FONT_SIZE +LyXFont_size Paragraph::highestFontInRange(pos_type startpos, pos_type endpos, - LyXFont::FONT_SIZE const def_size) const + LyXFont_size def_size) const { if (pimpl_->fontlist.empty()) return def_size; Pimpl::FontList::const_iterator end_it = pimpl_->fontlist.begin(); - Pimpl::FontList::const_iterator end = pimpl_->fontlist.end(); + Pimpl::FontList::const_iterator const end = pimpl_->fontlist.end(); for (; end_it != end; ++end_it) { if (end_it->pos() >= endpos) break; @@ -535,10 +506,10 @@ Paragraph::getUChar(BufferParams const & bparams, pos_type pos) const void Paragraph::setFont(pos_type pos, LyXFont const & font) { - lyx::Assert(pos <= size()); + BOOST_ASSERT(pos <= size()); // First, reduce font against layout/label font - // Update: The SetCharFont() routine in text2.C already + // Update: The setCharFont() routine in text2.C already // reduces font, so we don't need to do that here. (Asger) // No need to simplify this because it will disappear // in a new kernel. (Asger) @@ -551,7 +522,7 @@ void Paragraph::setFont(pos_type pos, LyXFont const & font) if (it->pos() >= pos) break; } - unsigned int i = std::distance(beg, it); + unsigned int i = distance(beg, it); bool notfound = (it == endit); if (!notfound && pimpl_->fontlist[i].font() == font) @@ -606,7 +577,7 @@ void Paragraph::makeSameLayout(Paragraph const & par) int Paragraph::stripLeadingSpaces() { - if (layout()->free_spacing || isFreeSpacing()) + if (isFreeSpacing()) return 0; int i = 0; @@ -621,9 +592,7 @@ int Paragraph::stripLeadingSpaces() bool Paragraph::hasSameLayout(Paragraph const & par) const { - return - par.layout() == layout() && - params().sameLayout(par.params()); + return par.layout() == layout() && params().sameLayout(par.params()); } @@ -675,34 +644,40 @@ void Paragraph::applyLayout(LyXLayout_ptr const & new_layout) layout(new_layout); params().labelWidthString(string()); params().align(LYX_ALIGN_LAYOUT); - params().spaceTop(VSpace(VSpace::NONE)); - params().spaceBottom(VSpace(VSpace::NONE)); params().spacing(Spacing(Spacing::Default)); } -int Paragraph::beginningOfBody() const +pos_type Paragraph::beginOfBody() const { - if (layout()->labeltype != LABEL_MANUAL) - return 0; + return begin_of_body_; +} + + +void Paragraph::setBeginOfBody() +{ + if (layout()->labeltype != LABEL_MANUAL) { + begin_of_body_ = 0; + return; + } // Unroll the first two cycles of the loop // and remember the previous character to - // remove unnecessary GetChar() calls + // remove unnecessary getChar() calls pos_type i = 0; - if (i < size() && !isNewline(i)) { + pos_type end = size(); + if (i < end && !isNewline(i)) { ++i; char previous_char = 0; char temp = 0; - if (i < size()) { - previous_char = getChar(i); + if (i < end) { + previous_char = text_[i]; if (!isNewline(i)) { ++i; - while (i < size() && previous_char != ' ') { - temp = getChar(i); + while (i < end && previous_char != ' ') { + temp = text_[i]; if (isNewline(i)) break; - ++i; previous_char = temp; } @@ -710,32 +685,82 @@ int Paragraph::beginningOfBody() const } } - return i; + begin_of_body_ = i; } // returns -1 if inset not found -int Paragraph::getPositionOfInset(Inset const * inset) const +int Paragraph::getPositionOfInset(InsetBase const * inset) const { // Find the entry. - InsetList::iterator it = insetlist.begin(); - InsetList::iterator end = insetlist.end(); + InsetList::const_iterator it = insetlist.begin(); + InsetList::const_iterator end = insetlist.end(); for (; it != end; ++it) - if (it.getInset() == inset) - return it.getPos(); + if (it->inset == inset) + return it->pos; return -1; } -InsetBibitem * Paragraph::bibitem() +InsetBibitem * Paragraph::bibitem() const { - InsetList::iterator it = insetlist.begin(); - if (it != insetlist.end() && it.getInset()->lyxCode() == Inset::BIBTEX_CODE) - return static_cast(it.getInset()); + if (!insetlist.empty()) { + InsetBase * inset = insetlist.begin()->inset; + if (inset->lyxCode() == InsetBase::BIBTEX_CODE) + return static_cast(inset); + } return 0; } +bool Paragraph::forceDefaultParagraphs() const +{ + return inInset() && inInset()->forceDefaultParagraphs(inInset()); +} + + +bool Paragraph::autoBreakRows() const +{ + return inInset() && static_cast(inInset())->getAutoBreakRows(); +} + + +namespace { + +// paragraphs inside floats need different alignment tags to avoid +// unwanted space + +bool noTrivlistCentering(InsetBase::Code code) +{ + return code == InsetBase::FLOAT_CODE || code == InsetBase::WRAP_CODE; +} + + +string correction(string const & orig) +{ + if (orig == "flushleft") + return "raggedright"; + if (orig == "flushright") + return "raggedleft"; + if (orig == "center") + return "centering"; + return orig; +} + + +string const corrected_env(string const & suffix, string const & env, + InsetBase::Code code) +{ + string output = suffix + "{"; + if (noTrivlistCentering(code)) + output += correction(env); + else + output += env; + return output + "}"; +} + +} // namespace anon + // This could go to ParagraphParameters if we want to int Paragraph::startTeXParParams(BufferParams const & bparams, @@ -759,7 +784,7 @@ int Paragraph::startTeXParParams(BufferParams const & bparams, case LYX_ALIGN_CENTER: if (moving_arg) { os << "\\protect"; - column = 8; + column += 8; } break; } @@ -770,29 +795,32 @@ int Paragraph::startTeXParParams(BufferParams const & bparams, case LYX_ALIGN_LAYOUT: case LYX_ALIGN_SPECIAL: break; - case LYX_ALIGN_LEFT: - if (getParLanguage(bparams)->babel() != "hebrew") { - os << "\\begin{flushleft}"; - column += 17; - } else { - os << "\\begin{flushright}"; - column += 18; - } + case LYX_ALIGN_LEFT: { + string output; + if (getParLanguage(bparams)->babel() != "hebrew") + output = corrected_env("\\begin", "flushleft", ownerCode()); + else + output = corrected_env("\\begin", "flushright", ownerCode()); + os << output; + column += output.size(); break; - case LYX_ALIGN_RIGHT: - if (getParLanguage(bparams)->babel() != "hebrew") { - os << "\\begin{flushright}"; - column += 18; - } else { - os << "\\begin{flushleft}"; - column += 17; - } + } case LYX_ALIGN_RIGHT: { + string output; + if (getParLanguage(bparams)->babel() != "hebrew") + output = corrected_env("\\begin", "flushright", ownerCode()); + else + output = corrected_env("\\begin", "flushleft", ownerCode()); + os << output; + column += output.size(); break; - case LYX_ALIGN_CENTER: - os << "\\begin{center}"; - column += 14; + } case LYX_ALIGN_CENTER: { + string output; + output = corrected_env("\\begin", "center", ownerCode()); + os << output; + column += output.size(); break; } + } return column; } @@ -826,39 +854,43 @@ int Paragraph::endTeXParParams(BufferParams const & bparams, case LYX_ALIGN_LAYOUT: case LYX_ALIGN_SPECIAL: break; - case LYX_ALIGN_LEFT: - if (getParLanguage(bparams)->babel() != "hebrew") { - os << "\\end{flushleft}"; - column = 15; - } else { - os << "\\end{flushright}"; - column = 16; - } + case LYX_ALIGN_LEFT: { + string output; + if (getParLanguage(bparams)->babel() != "hebrew") + output = corrected_env("\\par\\end", "flushleft", ownerCode()); + else + output = corrected_env("\\par\\end", "flushright", ownerCode()); + os << output; + column += output.size(); break; - case LYX_ALIGN_RIGHT: - if (getParLanguage(bparams)->babel() != "hebrew") { - os << "\\end{flushright}"; - column+= 16; - } else { - os << "\\end{flushleft}"; - column = 15; - } + } case LYX_ALIGN_RIGHT: { + string output; + if (getParLanguage(bparams)->babel() != "hebrew") + output = corrected_env("\\par\\end", "flushright", ownerCode()); + else + output = corrected_env("\\par\\end", "flushleft", ownerCode()); + os << output; + column += output.size(); break; - case LYX_ALIGN_CENTER: - os << "\\end{center}"; - column = 12; + } case LYX_ALIGN_CENTER: { + string output; + output = corrected_env("\\par\\end", "center", ownerCode()); + os << output; + column += output.size(); break; } + } + return column; } // This one spits out the text of the paragraph -bool Paragraph::simpleTeXOnePar(Buffer const * buf, +bool Paragraph::simpleTeXOnePar(Buffer const & buf, BufferParams const & bparams, LyXFont const & outerfont, ostream & os, TexRow & texrow, - LatexRunParams const & runparams) + OutputParams const & runparams) const { lyxerr[Debug::LATEX] << "SimpleTeXOnePar... " << this << endl; @@ -867,11 +899,10 @@ bool Paragraph::simpleTeXOnePar(Buffer const * buf, LyXLayout_ptr style; // well we have to check if we are in an inset with unlimited - // lenght (all in one row) if that is true then we don't allow + // length (all in one row) if that is true then we don't allow // any special options in the paragraph and also we don't allow // any environment other then "Standard" to be valid! - bool asdefault = - (inInset() && inInset()->forceDefaultParagraphs(inInset())); + bool asdefault = forceDefaultParagraphs(); if (asdefault) { style = bparams.getLyXTextClass().defaultLayout(); @@ -882,16 +913,7 @@ bool Paragraph::simpleTeXOnePar(Buffer const * buf, LyXFont basefont; // Maybe we have to create a optional argument. - pos_type body_pos; - - // FIXME: can we actually skip this check and just call - // beginningOfBody() ?? - if (style->labeltype != LABEL_MANUAL) { - body_pos = 0; - } else { - body_pos = beginningOfBody(); - } - + pos_type body_pos = beginOfBody(); unsigned int column = 0; if (body_pos > 0) { @@ -902,8 +924,7 @@ bool Paragraph::simpleTeXOnePar(Buffer const * buf, basefont = getLayoutFont(bparams, outerfont); } - bool moving_arg = runparams.moving_arg; - moving_arg |= style->needprotect; + bool const moving_arg = runparams.moving_arg | style->needprotect; // Which font is currently active? LyXFont running_font(basefont); @@ -922,7 +943,6 @@ bool Paragraph::simpleTeXOnePar(Buffer const * buf, } if (!asdefault) column += startTeXParParams(bparams, os, moving_arg); - } for (pos_type i = 0; i < size(); ++i) { @@ -961,8 +981,7 @@ bool Paragraph::simpleTeXOnePar(Buffer const * buf, // rather than "\textXX{text }". (Asger) if (open_font && c == ' ' && i <= size() - 2) { LyXFont const & next_font = getFont(bparams, i + 1, outerfont); - if (next_font != running_font - && next_font != font) { + if (next_font != running_font && next_font != font) { font = next_font; } } @@ -1004,11 +1023,13 @@ bool Paragraph::simpleTeXOnePar(Buffer const * buf, column += Changes::latexMarkChange(os, running_change, change); running_change = change; - LatexRunParams rp = runparams; + OutputParams rp = runparams; rp.moving_arg = moving_arg; rp.free_spacing = style->free_spacing; + rp.lang = font.language()->babel(); + rp.intitle = style->intitle; pimpl_->simpleTeXSpecialChars(buf, bparams, - os, texrow, runparams, + os, texrow, rp, font, running_font, basefont, outerfont, open_font, running_change, @@ -1055,25 +1076,415 @@ bool Paragraph::simpleTeXOnePar(Buffer const * buf, } +namespace { +// checks, if newcol chars should be put into this line +// writes newline, if necessary. +void sgmlLineBreak(ostream & os, string::size_type & colcount, + string::size_type newcol) +{ + colcount += newcol; + if (colcount > lyxrc.ascii_linelen) { + os << "\n"; + colcount = newcol; // assume write after this call + } +} -bool Paragraph::isHfill(pos_type pos) const +enum PAR_TAG { + PAR_NONE=0, + TT = 1, + SF = 2, + BF = 4, + IT = 8, + SL = 16, + EM = 32 +}; + + +string tag_name(PAR_TAG const & pt) { + switch (pt) { + case PAR_NONE: return "!-- --"; + case TT: return "tt"; + case SF: return "sf"; + case BF: return "bf"; + case IT: return "it"; + case SL: return "sl"; + case EM: return "em"; + } + return ""; +} + + +inline +void operator|=(PAR_TAG & p1, PAR_TAG const & p2) +{ + p1 = static_cast(p1 | p2); +} + + +inline +void reset(PAR_TAG & p1, PAR_TAG const & p2) +{ + p1 = static_cast(p1 & ~p2); +} + +} // anon + + +// Handle internal paragraph parsing -- layout already processed. +void Paragraph::simpleLinuxDocOnePar(Buffer const & buf, + ostream & os, + LyXFont const & outerfont, + OutputParams const & runparams, + lyx::depth_type /*depth*/) const +{ + LyXLayout_ptr const & style = layout(); + + string::size_type char_line_count = 5; // Heuristic choice ;-) + + // gets paragraph main font + LyXFont font_old; + bool desc_on; + if (style->labeltype == LABEL_MANUAL) { + font_old = style->labelfont; + desc_on = true; + } else { + font_old = style->font; + desc_on = false; + } + + LyXFont::FONT_FAMILY family_type = LyXFont::ROMAN_FAMILY; + LyXFont::FONT_SERIES series_type = LyXFont::MEDIUM_SERIES; + LyXFont::FONT_SHAPE shape_type = LyXFont::UP_SHAPE; + bool is_em = false; + + stack tag_state; + // parsing main loop + for (pos_type i = 0; i < size(); ++i) { + + PAR_TAG tag_close = PAR_NONE; + list < PAR_TAG > tag_open; + + LyXFont const font = getFont(buf.params(), i, outerfont); + + if (font_old.family() != font.family()) { + switch (family_type) { + case LyXFont::SANS_FAMILY: + tag_close |= SF; + break; + case LyXFont::TYPEWRITER_FAMILY: + tag_close |= TT; + break; + default: + break; + } + + family_type = font.family(); + + switch (family_type) { + case LyXFont::SANS_FAMILY: + tag_open.push_back(SF); + break; + case LyXFont::TYPEWRITER_FAMILY: + tag_open.push_back(TT); + break; + default: + break; + } + } + + if (font_old.series() != font.series()) { + switch (series_type) { + case LyXFont::BOLD_SERIES: + tag_close |= BF; + break; + default: + break; + } + + series_type = font.series(); + + switch (series_type) { + case LyXFont::BOLD_SERIES: + tag_open.push_back(BF); + break; + default: + break; + } + + } + + if (font_old.shape() != font.shape()) { + switch (shape_type) { + case LyXFont::ITALIC_SHAPE: + tag_close |= IT; + break; + case LyXFont::SLANTED_SHAPE: + tag_close |= SL; + break; + default: + break; + } + + shape_type = font.shape(); + + switch (shape_type) { + case LyXFont::ITALIC_SHAPE: + tag_open.push_back(IT); + break; + case LyXFont::SLANTED_SHAPE: + tag_open.push_back(SL); + break; + default: + break; + } + } + // handle tag + if (font_old.emph() != font.emph()) { + if (font.emph() == LyXFont::ON) { + tag_open.push_back(EM); + is_em = true; + } + else if (is_em) { + tag_close |= EM; + is_em = false; + } + } + + list < PAR_TAG > temp; + while (!tag_state.empty() && tag_close) { + PAR_TAG k = tag_state.top(); + tag_state.pop(); + os << "'; + if (tag_close & k) + reset(tag_close,k); + else + temp.push_back(k); + } + + for(list< PAR_TAG >::const_iterator j = temp.begin(); + j != temp.end(); ++j) { + tag_state.push(*j); + os << '<' << tag_name(*j) << '>'; + } + + for(list< PAR_TAG >::const_iterator j = tag_open.begin(); + j != tag_open.end(); ++j) { + tag_state.push(*j); + os << '<' << tag_name(*j) << '>'; + } + + char c = getChar(i); + + + if (c == Paragraph::META_INSET) { + getInset(i)->linuxdoc(buf, os, runparams); + font_old = font; + continue; + } + + if (style->latexparam() == "CDATA") { + // "TeX"-Mode on == > SGML-Mode on. + if (c != '\0') + os << c; + ++char_line_count; + } else { + bool ws; + string str; + boost::tie(ws, str) = sgml::escapeChar(c); + if (ws && !isFreeSpacing()) { + // in freespacing mode, spaces are + // non-breaking characters + if (desc_on) { // if char is ' ' then... + ++char_line_count; + sgmlLineBreak(os, char_line_count, 6); + os << ""; + desc_on = false; + } else { + sgmlLineBreak(os, char_line_count, 1); + os << c; + } + } else { + os << str; + char_line_count += str.length(); + } + } + font_old = font; + } + + while (!tag_state.empty()) { + os << "'; + tag_state.pop(); + } + + // resets description flag correctly + if (desc_on) { + // not closed... + sgmlLineBreak(os, char_line_count, 6); + os << ""; + } +} + + +string Paragraph::getDocbookId() const { - return IsInsetChar(getChar(pos)) - && getInset(pos)->lyxCode() == Inset::HFILL_CODE; + for (pos_type i = 0; i < size(); ++i) { + if (isInset(i)) { + InsetBase const * inset = getInset(i); + InsetBase::Code lyx_code = inset->lyxCode(); + if (lyx_code == InsetBase::LABEL_CODE) { + return static_cast(inset)->getContents(); + } + } + + } + return string(); } -bool Paragraph::isInset(pos_type pos) const +void Paragraph::simpleDocBookOnePar(Buffer const & buf, + ostream & os, + LyXFont const & outerfont, + OutputParams const & runparams, + lyx::depth_type depth) const { - return IsInsetChar(getChar(pos)); + bool emph_flag = false; + + LyXLayout_ptr const & style = layout(); + LyXLayout_ptr const & defaultstyle = + buf.params().getLyXTextClass().defaultLayout(); + + LyXFont font_old = + style->labeltype == LABEL_MANUAL ? style->labelfont : style->font; + + int char_line_count = depth; + bool label_closed = true; + bool para_closed = true; + + if (style->latextype == LATEX_ITEM_ENVIRONMENT) { + string ls = ""; + Counters & counters = buf.params().getLyXTextClass().counters(); + if (!style->free_spacing) + os << string(depth,' '); + if (!style->labeltag().empty()) { + os << "<" << style->labeltag() << ">\n"; + label_closed = false; + } else { + if (!defaultstyle->latexparam().empty()) { + counters.step("para"); + ls = tostr(counters.value("para")); + ls = " id=\"" + + subst(defaultstyle->latexparam(), "#", ls) + '"'; + } + os << "<" << style->itemtag() << ">\n" + << string(depth, ' ') << "<" + << defaultstyle->latexname() << ls << ">\n"; + para_closed = false; + } + } + + // parsing main loop + for (pos_type i = 0; i < size(); ++i) { + LyXFont font = getFont(buf.params(), i, outerfont); + + // handle tag + if (font_old.emph() != font.emph()) { + if (font.emph() == LyXFont::ON) { + if (style->latexparam() == "CDATA") + os << "]]>"; + os << ""; + if (style->latexparam() == "CDATA") + os << "latexparam() == "CDATA") + os << "]]>"; + os << ""; + if (style->latexparam() == "CDATA") + os << "latexparam() == "CDATA") + os << "]]>"; + inset->docbook(buf, os, runparams); + if (style->latexparam() == "CDATA") + os << "pass_thru) { + os << c; + } else if (isFreeSpacing() || c != ' ') { + os << str; + } else if (!style->labeltag().empty() && !label_closed) { + ++char_line_count; + os << "\nlabeltag() << "><" + << style->itemtag() << "><" + << defaultstyle->latexname() << ">"; + label_closed = true; + para_closed = false; + } else { + os << ' '; + } + } + font_old = font; + } + + if (emph_flag) { + if (style->latexparam() == "CDATA") + os << "]]>"; + os << ""; + if (style->latexparam() == "CDATA") + os << " not closed... + os << "labeltag() << ">\n<" + << style->itemtag() << "><" + << defaultstyle->latexname() << "> "; + } + if (!para_closed) { + os << "\n" << string(depth, ' ') << "latexname() << ">\n"; + } + if (style->free_spacing) + os << '\n'; +} + + +namespace { + +/// return true if the char is a meta-character for an inset +inline +bool IsInsetChar(char c) +{ + return (c == Paragraph::META_INSET); +} + +} // namespace anon + + + +bool Paragraph::isHfill(pos_type pos) const +{ + return + isInset(pos) && getInset(pos)->lyxCode() == InsetBase::HFILL_CODE; } bool Paragraph::isNewline(pos_type pos) const { - return IsInsetChar(getChar(pos)) - && getInset(pos)->lyxCode() == Inset::NEWLINE_CODE; + return + isInset(pos) && getInset(pos)->lyxCode() == InsetBase::NEWLINE_CODE; } @@ -1114,22 +1525,24 @@ bool Paragraph::isLetter(pos_type pos) const bool Paragraph::isWord(pos_type pos) const { - return IsWordChar(getChar(pos)) ; + if (isInset(pos)) + return getInset(pos)->isLetter(); + value_type const c = getChar(pos); + return !(IsSeparatorChar(c) + || IsKommaChar(c) + || IsInsetChar(c)); } Language const * Paragraph::getParLanguage(BufferParams const & bparams) const { - if (!empty()) { + if (!empty()) return getFirstFontSettings().language(); +#ifdef WITH_WARNINGS #warning FIXME we should check the prev par as well (Lgb) -#if 0 - } else if (previous_) { - return previous_->getParLanguage(bparams); #endif - }else - return bparams.language; + return bparams.language; } @@ -1137,8 +1550,7 @@ bool Paragraph::isRightToLeftPar(BufferParams const & bparams) const { return lyxrc.rtl_support && getParLanguage(bparams)->RightToLeft() - && !(inInset() && inInset()->owner() && - inInset()->owner()->lyxCode() == Inset::ERT_CODE); + && ownerCode() != InsetBase::ERT_CODE; } @@ -1155,7 +1567,7 @@ void Paragraph::changeLanguage(BufferParams const & bparams, } -bool Paragraph::isMultiLingual(BufferParams const & bparams) +bool Paragraph::isMultiLingual(BufferParams const & bparams) const { Language const * doc_language = bparams.language; Pimpl::FontList::const_iterator cit = pimpl_->fontlist.begin(); @@ -1164,7 +1576,7 @@ bool Paragraph::isMultiLingual(BufferParams const & bparams) for (; cit != end; ++cit) if (cit->font().language() != ignore_language && cit->font().language() != latex_language && - cit->font().language() != doc_language) + cit->font().language() != doc_language) return true; return false; } @@ -1172,8 +1584,18 @@ bool Paragraph::isMultiLingual(BufferParams const & bparams) // Convert the paragraph to a string. // Used for building the table of contents -string const Paragraph::asString(Buffer const * buffer, bool label) const +string const Paragraph::asString(Buffer const & buffer, bool label) const { + OutputParams runparams; + return asString(buffer, runparams, label); +} + + +string const Paragraph::asString(Buffer const & buffer, + OutputParams const & runparams, + bool label) const +{ +#if 0 string s; if (label && !params().labelString().empty()) s += params().labelString() + ' '; @@ -1183,18 +1605,33 @@ string const Paragraph::asString(Buffer const * buffer, bool label) const if (IsPrintable(c)) s += c; else if (c == META_INSET && - getInset(i)->lyxCode() == Inset::MATH_CODE) { - ostringstream ost; - getInset(i)->ascii(buffer, ost); - s += subst(STRCONV(ost.str()),'\n',' '); + getInset(i)->lyxCode() == InsetBase::MATH_CODE) { + ostringstream os; + getInset(i)->plaintext(buffer, os, runparams); + s += subst(STRCONV(os.str()),'\n',' '); } } return s; +#else + // This should really be done by the caller and not here. + string ret = asString(buffer, runparams, 0, size(), label); + return subst(ret, '\n', ' '); +#endif } -string const Paragraph::asString(Buffer const * buffer, +string const Paragraph::asString(Buffer const & buffer, + pos_type beg, pos_type end, bool label) const +{ + + OutputParams const runparams; + return asString(buffer, runparams, beg, end, label); +} + + +string const Paragraph::asString(Buffer const & buffer, + OutputParams const & runparams, pos_type beg, pos_type end, bool label) const { ostringstream os; @@ -1203,39 +1640,20 @@ string const Paragraph::asString(Buffer const * buffer, os << params().labelString() << ' '; for (pos_type i = beg; i < end; ++i) { - value_type const c = getUChar(buffer->params, i); + value_type const c = getUChar(buffer.params(), i); if (IsPrintable(c)) os << c; else if (c == META_INSET) - getInset(i)->ascii(buffer, os); + getInset(i)->plaintext(buffer, os, runparams); } - return STRCONV(os.str()); -} - - -void Paragraph::setInsetOwner(Inset * i) -{ - pimpl_->inset_owner = i; - InsetList::iterator it = insetlist.begin(); - InsetList::iterator end = insetlist.end(); - for (; it != end; ++it) - if (it.getInset()) - it.getInset()->setOwner(i); -} - - -void Paragraph::deleteInsetsLyXText(BufferView * bv) -{ - // then the insets - insetlist.deleteInsetsLyXText(bv); + return os.str(); } -void Paragraph::resizeInsetsLyXText(BufferView * bv) +void Paragraph::setInsetOwner(UpdatableInset * inset) { - // then the insets - insetlist.resizeInsetsLyXText(bv); + pimpl_->inset_owner = inset; } @@ -1265,14 +1683,14 @@ void Paragraph::cleanChanges() Change::Type Paragraph::lookupChange(lyx::pos_type pos) const { - lyx::Assert(!size() || pos < size()); + BOOST_ASSERT(empty() || pos < size()); return pimpl_->lookupChange(pos); } Change const Paragraph::lookupChangeFull(lyx::pos_type pos) const { - lyx::Assert(!size() || pos < size()); + BOOST_ASSERT(empty() || pos < size()); return pimpl_->lookupChangeFull(pos); } @@ -1292,7 +1710,6 @@ bool Paragraph::isChangeEdited(pos_type start, pos_type end) const void Paragraph::setChange(lyx::pos_type pos, Change::Type type) { pimpl_->setChange(pos, type); - } @@ -1314,21 +1731,22 @@ void Paragraph::rejectChange(pos_type start, pos_type end) } -lyx::pos_type Paragraph::size() const +Paragraph::value_type Paragraph::getChar(pos_type pos) const { - return pimpl_->size(); -} + // This is in the critical path! + pos_type const siz = text_.size(); + BOOST_ASSERT(0 <= pos); + BOOST_ASSERT(pos <= siz); -bool Paragraph::empty() const -{ - return pimpl_->empty(); -} - + if (pos == siz) { + lyxerr << "getChar() on pos " << pos << " in par id " + << id() << " of size " << siz + << " is a bit silly !" << endl; + BOOST_ASSERT(false); + } -Paragraph::value_type Paragraph::getChar(pos_type pos) const -{ - return pimpl_->getChar(pos); + return text_[pos]; } @@ -1338,17 +1756,8 @@ int Paragraph::id() const } -void Paragraph::id(int i) -{ - pimpl_->id_ = i; -} - - LyXLayout_ptr const & Paragraph::layout() const { - Inset * inset = inInset(); - if (inset && inset->lyxCode() == Inset::ENVIRONMENT_CODE) - return static_cast(inset)->layout(); return layout_; } @@ -1359,20 +1768,28 @@ void Paragraph::layout(LyXLayout_ptr const & new_layout) } -Inset * Paragraph::inInset() const +UpdatableInset * Paragraph::inInset() const { return pimpl_->inset_owner; } +InsetBase::Code Paragraph::ownerCode() const +{ + return pimpl_->inset_owner + ? pimpl_->inset_owner->lyxCode() : InsetBase::NO_CODE; +} + + void Paragraph::clearContents() { - pimpl_->clear(); + text_.clear(); } + void Paragraph::setChar(pos_type pos, value_type c) { - pimpl_->setChar(pos, c); + text_[pos] = c; } @@ -1390,9 +1807,89 @@ ParagraphParameters const & Paragraph::params() const bool Paragraph::isFreeSpacing() const { + if (layout()->free_spacing) + return true; + // for now we just need this, later should we need this in some - // other way we can always add a function to Inset::() too. - if (pimpl_->inset_owner && pimpl_->inset_owner->owner()) - return (pimpl_->inset_owner->owner()->lyxCode() == Inset::ERT_CODE); - return false; + // other way we can always add a function to InsetBase too. + return ownerCode() == InsetBase::ERT_CODE; +} + + +bool Paragraph::allowEmpty() const +{ + if (layout()->keepempty) + return true; + return ownerCode() == InsetBase::ERT_CODE; +} + + +RowList::iterator Paragraph::getRow(pos_type pos) +{ + RowList::iterator rit = rows.end(); + RowList::iterator const begin = rows.begin(); + + for (--rit; rit != begin && rit->pos() > pos; --rit) + ; + + return rit; +} + + +RowList::const_iterator Paragraph::getRow(pos_type pos) const +{ + RowList::const_iterator rit = rows.end(); + RowList::const_iterator const begin = rows.begin(); + + for (--rit; rit != begin && rit->pos() > pos; --rit) + ; + + return rit; +} + + +size_t Paragraph::row(pos_type pos) const +{ + RowList::const_iterator rit = rows.end(); + RowList::const_iterator const begin = rows.begin(); + + for (--rit; rit != begin && rit->pos() > pos; --rit) + ; + + return rit - begin; +} + + +unsigned char Paragraph::transformChar(unsigned char c, pos_type pos) const +{ + if (!Encodings::is_arabic(c)) + if (lyxrc.font_norm_type == LyXRC::ISO_8859_6_8 && IsDigit(c)) + return c + (0xb0 - '0'); + else + return c; + + unsigned char const prev_char = pos > 0 ? getChar(pos - 1) : ' '; + unsigned char next_char = ' '; + + for (pos_type i = pos + 1, end = size(); i < end; ++i) { + unsigned char const par_char = getChar(i); + if (!Encodings::IsComposeChar_arabic(par_char)) { + next_char = par_char; + break; + } + } + + if (Encodings::is_arabic(next_char)) { + if (Encodings::is_arabic(prev_char) && + !Encodings::is_arabic_special(prev_char)) + return Encodings::TransformChar(c, Encodings::FORM_MEDIAL); + else + return Encodings::TransformChar(c, Encodings::FORM_INITIAL); + } else { + if (Encodings::is_arabic(prev_char) && + !Encodings::is_arabic_special(prev_char)) + return Encodings::TransformChar(c, Encodings::FORM_FINAL); + else + return Encodings::TransformChar(c, Encodings::FORM_ISOLATED); + } }