]> git.lyx.org Git - lyx.git/blobdiff - src/paragraph.C
Continue to improve GtkLengthEntry
[lyx.git] / src / paragraph.C
index 5e02c66dd232ca71270e53cf31566983f262c4ca..227568b43f2067155a02c48d60358c590768753c 100644 (file)
@@ -27,6 +27,7 @@
 #include "debug.h"
 #include "gettext.h"
 #include "language.h"
+#include "LaTeXFeatures.h"
 #include "lyxfont.h"
 #include "lyxrc.h"
 #include "lyxrow.h"
 
 #include "support/lstrings.h"
 #include "support/textutils.h"
-#include "support/tostr.h"
+#include "support/convert.h"
 
 #include <boost/tuple/tuple.hpp>
 #include <boost/bind.hpp>
 
+#include <algorithm>
 #include <list>
 #include <stack>
 #include <sstream>
 
 using lyx::pos_type;
 
-using lyx::support::contains;
 using lyx::support::subst;
 
 using std::distance;
@@ -70,10 +71,8 @@ ParagraphList::ParagraphList()
 
 
 Paragraph::Paragraph()
-       : y(0), height(0), begin_of_body_(0),
-         pimpl_(new Paragraph::Pimpl(this))
+       : begin_of_body_(0), pimpl_(new Paragraph::Pimpl(this))
 {
-       //lyxerr << "sizeof Paragraph::Pimpl: " << sizeof(Paragraph::Pimpl) << endl;
        itemdepth = 0;
        params().clear();
 }
@@ -81,8 +80,9 @@ Paragraph::Paragraph()
 
 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_),
+               dim_(par.dim_),
+               rows_(par.rows_), rowSignature_(par.rowSignature_), 
+               layout_(par.layout_),
                text_(par.text_), begin_of_body_(par.begin_of_body_),
          pimpl_(new Paragraph::Pimpl(*par.pimpl_, this))
 {
@@ -106,10 +106,9 @@ Paragraph & Paragraph::operator=(Paragraph const & par)
                for (; it != end; ++it)
                        it->inset = it->inset->clone().release();
 
-               rows = par.rows;
-               y = par.y;
-               height = par.height;
-               width = par.width;
+               rows_ = par.rows_;
+               dim_ = par.dim_;
+               rowSignature_ = par.rowSignature_;
                layout_ = par.layout();
                text_ = par.text_;
                begin_of_body_ = par.begin_of_body_;
@@ -161,10 +160,6 @@ void Paragraph::write(Buffer const & buf, ostream & os,
 
        int column = 0;
        for (pos_type i = 0; i < size(); ++i) {
-               if (!i) {
-                       os << '\n';
-                       column = 0;
-               }
 
                Change change = pimpl_->lookupChangeFull(i);
                Changes::lyxMarkChange(os, column, curtime, running_change, change);
@@ -190,7 +185,9 @@ void Paragraph::write(Buffer const & buf, ostream & os,
                                        // the file
                                        inset->write(buf, os);
                                } else {
-                                       os << "\n\\begin_inset ";
+                                       if (i)
+                                               os << '\n';
+                                       os << "\\begin_inset ";
                                        inset->write(buf, os);
                                        os << "\n\\end_inset\n\n";
                                        column = 0;
@@ -266,18 +263,11 @@ int Paragraph::erase(pos_type start, pos_type end)
 void Paragraph::insert(pos_type start, string const & str,
                       LyXFont const & font)
 {
-       int size = str.size();
-       for (int i = 0 ; i < size ; ++i)
+       for (size_t i = 0, n = str.size(); i != n ; ++i)
                insertChar(start + i, str[i], font);
 }
 
 
-bool Paragraph::checkInsertChar(LyXFont &)
-{
-       return true;
-}
-
-
 void Paragraph::insertChar(pos_type pos, Paragraph::value_type c,
                           Change change)
 {
@@ -307,26 +297,12 @@ void Paragraph::insertInset(pos_type pos, InsetBase * inset,
 }
 
 
-bool Paragraph::insetAllowed(InsetOld_code code)
+bool Paragraph::insetAllowed(InsetBase_code code)
 {
        return !pimpl_->inset_owner || pimpl_->inset_owner->insetAllowed(code);
 }
 
 
-InsetBase * Paragraph::getInset(pos_type pos)
-{
-       BOOST_ASSERT(pos < size());
-       return insetlist.get(pos);
-}
-
-
-InsetBase const * Paragraph::getInset(pos_type pos) const
-{
-       BOOST_ASSERT(pos < size());
-       return insetlist.get(pos);
-}
-
-
 // Gets uninstantiated font setting at position.
 LyXFont const Paragraph::getFontSettings(BufferParams const & bparams,
                                         pos_type pos) const
@@ -352,20 +328,30 @@ LyXFont const Paragraph::getFontSettings(BufferParams const & bparams,
 }
 
 
-lyx::pos_type Paragraph::getEndPosOfFontSpan(lyx::pos_type pos) const
+FontSpan Paragraph::fontSpan(lyx::pos_type pos) const
 {
        BOOST_ASSERT(pos <= size());
+       lyx::pos_type start = 0;
 
        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();
+       for (; cit != end; ++cit) {
+               if (cit->pos() >= pos) {
+                       if (pos >= beginOfBody())
+                               return FontSpan(std::max(start, beginOfBody()),
+                                               cit->pos());
+                       else
+                               return FontSpan(start, 
+                                               std::min(beginOfBody() - 1, 
+                                                        cit->pos()));
+               }
+               start = cit->pos() + 1;
+       }
 
        // This should not happen, but if so, we take no chances.
        //lyxerr << "Paragraph::getEndPosOfFontSpan: This should not happen!"
        //      << endl;
-       return pos;
+       return FontSpan(pos, pos);
 }
 
 
@@ -408,8 +394,8 @@ LyXFont const Paragraph::getFont(BufferParams const & bparams, pos_type pos,
 }
 
 
-LyXFont const Paragraph::getLabelFont(BufferParams const & bparams,
-                                     LyXFont const & outerfont) const
+LyXFont const Paragraph::getLabelFont
+       (BufferParams const & bparams, LyXFont const & outerfont) const
 {
        LyXFont tmpfont = layout()->labelfont;
        tmpfont.setLanguage(getParLanguage(bparams));
@@ -419,8 +405,8 @@ LyXFont const Paragraph::getLabelFont(BufferParams const & bparams,
 }
 
 
-LyXFont const Paragraph::getLayoutFont(BufferParams const & bparams,
-                                      LyXFont const & outerfont) const
+LyXFont const Paragraph::getLayoutFont
+       (BufferParams const & bparams, LyXFont const & outerfont) const
 {
        LyXFont tmpfont = layout()->font;
        tmpfont.setLanguage(getParLanguage(bparams));
@@ -431,9 +417,8 @@ LyXFont const Paragraph::getLayoutFont(BufferParams const & bparams,
 
 
 /// Returns the height of the highest font in range
-LyXFont_size
-Paragraph::highestFontInRange(pos_type startpos, pos_type endpos,
-                             LyXFont_size def_size) const
+LyXFont_size Paragraph::highestFontInRange
+       (pos_type startpos, pos_type endpos, LyXFont_size def_size) const
 {
        if (pimpl_->fontlist.empty())
                return def_size;
@@ -525,7 +510,7 @@ void Paragraph::setFont(pos_type pos, LyXFont const & font)
                if (it->pos() >= pos)
                        break;
        }
-       unsigned int i = distance(beg, it);
+       size_t const i = distance(beg, it);
        bool notfound = (it == endit);
 
        if (!notfound && pimpl_->fontlist[i].font() == font)
@@ -585,7 +570,9 @@ int Paragraph::stripLeadingSpaces()
 
        int i = 0;
        while (!empty() && (isNewline(0) || isLineSeparator(0))) {
-               pimpl_->eraseIntern(0);
+               // Set Change::Type to Change::INSERTED to quietly remove it
+               setChange(0, Change::INSERTED);
+               erase(0);
                ++i;
        }
 
@@ -709,7 +696,7 @@ InsetBibitem * Paragraph::bibitem() const
 {
        if (!insetlist.empty()) {
                InsetBase * inset = insetlist.begin()->inset;
-               if (inset->lyxCode() == InsetBase::BIBTEX_CODE)
+               if (inset->lyxCode() == InsetBase::BIBITEM_CODE)
                        return static_cast<InsetBibitem *>(inset);
        }
        return 0;
@@ -718,13 +705,7 @@ InsetBibitem * Paragraph::bibitem() const
 
 bool Paragraph::forceDefaultParagraphs() const
 {
-       return inInset() && inInset()->forceDefaultParagraphs(inInset());
-}
-
-
-bool Paragraph::autoBreakRows() const
-{
-       return inInset() && static_cast<InsetText *>(inInset())->getAutoBreakRows();
+       return inInset() && inInset()->forceDefaultParagraphs(0);
 }
 
 
@@ -915,6 +896,15 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
 
        LyXFont basefont;
 
+       LaTeXFeatures features(buf, bparams, runparams.nice);
+
+       // output change tracking marks only if desired,
+       // if dvipost is installed,
+       // and with dvi/ps (other formats don't work)
+       bool const output = bparams.output_changes
+               && runparams.flavor == OutputParams::LATEX
+               && features.isAvailable("dvipost");
+
        // Maybe we have to create a optional argument.
        pos_type body_pos = beginOfBody();
        unsigned int column = 0;
@@ -929,8 +919,6 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
                basefont = getLayoutFont(bparams, outerfont);
        }
 
-       bool const moving_arg = runparams.moving_arg | style->needprotect;
-
        // Which font is currently active?
        LyXFont running_font(basefont);
        // Do we have an open font change?
@@ -947,7 +935,8 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
                        ++column;
                }
                if (!asdefault)
-                       column += startTeXParParams(bparams, os, moving_arg);
+                       column += startTeXParParams(bparams, os,
+                                                   runparams.moving_arg);
        }
 
        for (pos_type i = 0; i < size(); ++i) {
@@ -971,7 +960,7 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
 
                        if (!asdefault)
                                column += startTeXParParams(bparams, os,
-                                                           moving_arg);
+                                                           runparams.moving_arg);
                }
 
                value_type c = getChar(i);
@@ -1025,24 +1014,28 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
 
                Change::Type change = pimpl_->lookupChange(i);
 
-               column += Changes::latexMarkChange(os, running_change, change);
+               column += Changes::latexMarkChange(os, running_change,
+                       change, output);
                running_change = change;
 
-               OutputParams rp = runparams;
-               rp.moving_arg = moving_arg;
-               rp.free_spacing = style->free_spacing;
-               rp.local_language = font.language()->babel();
-               rp.intitle = style->intitle;
-               pimpl_->simpleTeXSpecialChars(buf, bparams,
-                                             os, texrow, rp,
-                                             font, running_font,
-                                             basefont, outerfont, open_font,
-                                             running_change,
-                                             *style, i, column, c);
+               // do not output text which is marked deleted
+               // if change tracking output is not desired
+               if (output || running_change != Change::DELETED) {
+                       OutputParams rp = runparams;
+                       rp.free_spacing = style->free_spacing;
+                       rp.local_font = &font;
+                       rp.intitle = style->intitle;
+                       pimpl_->simpleTeXSpecialChars(buf, bparams,
+                                               os, texrow, rp,
+                                               font, running_font,
+                                               basefont, outerfont, open_font,
+                                               running_change,
+                                               *style, i, column, c);
+               }
        }
 
        column += Changes::latexMarkChange(os,
-                       running_change, Change::UNCHANGED);
+                       running_change, Change::UNCHANGED, output);
 
        // If we have an open font definition, we have to close it
        if (open_font) {
@@ -1068,12 +1061,12 @@ bool Paragraph::simpleTeXOnePar(Buffer const & buf,
 
        // Needed if there is an optional argument but no contents.
        if (body_pos > 0 && body_pos == size()) {
-               os << "]~";
+               os << "}]~";
                return_value = false;
        }
 
        if (!asdefault) {
-               column += endTeXParParams(bparams, os, moving_arg);
+               column += endTeXParParams(bparams, os, runparams.moving_arg);
        }
 
        lyxerr[Debug::LATEX] << "SimpleTeXOnePar...done " << this << endl;
@@ -1279,7 +1272,7 @@ void Paragraph::simpleLinuxDocOnePar(Buffer const & buf,
                        os << '<' << tag_name(*j) << '>';
                }
 
-               char c = getChar(i);
+               value_type c = getChar(i);
 
 
                if (c == Paragraph::META_INSET) {
@@ -1337,20 +1330,19 @@ bool Paragraph::emptyTag() const
                if (isInset(i)) {
                        InsetBase const * inset = getInset(i);
                        InsetBase::Code lyx_code = inset->lyxCode();
-                       if (lyx_code != InsetBase::TOC_CODE and
-                           lyx_code != InsetBase::INCLUDE_CODE and
-                           lyx_code != InsetBase::GRAPHICS_CODE and
-                           lyx_code != InsetBase::ERT_CODE and
-                           lyx_code != InsetBase::FLOAT_CODE and
+                       if (lyx_code != InsetBase::TOC_CODE &&
+                           lyx_code != InsetBase::INCLUDE_CODE &&
+                           lyx_code != InsetBase::GRAPHICS_CODE &&
+                           lyx_code != InsetBase::ERT_CODE &&
+                           lyx_code != InsetBase::FLOAT_CODE &&
                            lyx_code != InsetBase::TABULAR_CODE) {
                                return false;
                        }
                } else {
-                       char c = getChar(i);
-                       if(c!= ' ' and c!= '\t')
+                       value_type c = getChar(i);
+                       if (c != ' ' && c != '\t')
                                return false;
                }
-
        }
        return true;
 }
@@ -1381,7 +1373,7 @@ pos_type Paragraph::getFirstWord(Buffer const & buf, ostream & os, OutputParams
                        InsetBase const * inset = getInset(i);
                        inset->docbook(buf, os, runparams);
                } else {
-                       char c = getChar(i);
+                       value_type c = getChar(i);
                        if (c == ' ')
                                break;
                        bool ws;
@@ -1397,14 +1389,13 @@ pos_type Paragraph::getFirstWord(Buffer const & buf, ostream & os, OutputParams
 
 bool Paragraph::onlyText(Buffer const & buf, LyXFont const & outerfont, pos_type initial) const
 {
-       LyXLayout_ptr const & style = layout();
        LyXFont font_old;
 
        for (pos_type i = initial; i < size(); ++i) {
                LyXFont font = getFont(buf.params(), i, outerfont);
                if (isInset(i))
                        return false;
-               if ( i != initial and font != font_old)
+               if (i != initial && font != font_old)
                        return false;
                font_old = font;
        }
@@ -1425,8 +1416,9 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf,
        LyXFont font_old =
                style->labeltype == LABEL_MANUAL ? style->labelfont : style->font;
 
-       if (style->pass_thru and not onlyText(buf, outerfont, initial))
+       if (style->pass_thru && !onlyText(buf, outerfont, initial))
                os << "]]>";
+
        // parsing main loop
        for (pos_type i = initial; i < size(); ++i) {
                LyXFont font = getFont(buf.params(), i, outerfont);
@@ -1446,7 +1438,7 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf,
                        InsetBase const * inset = getInset(i);
                        inset->docbook(buf, os, runparams);
                } else {
-                       char c = getChar(i);
+                       value_type c = getChar(i);
                        bool ws;
                        string str;
                        boost::tie(ws, str) = sgml::escapeChar(c);
@@ -1465,31 +1457,11 @@ void Paragraph::simpleDocBookOnePar(Buffer const & buf,
 
        if (style->free_spacing)
                os << '\n';
-       if (style->pass_thru and not onlyText(buf, outerfont, initial))
+       if (style->pass_thru && !onlyText(buf, outerfont, initial))
                os << "<![CDATA[";
 }
 
 
-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 isInset(pos)
@@ -1497,49 +1469,24 @@ bool Paragraph::isNewline(pos_type pos) const
 }
 
 
-bool Paragraph::isSeparator(pos_type pos) const
-{
-       return IsSeparatorChar(getChar(pos));
-}
-
-
 bool Paragraph::isLineSeparator(pos_type pos) const
 {
        value_type const c = getChar(pos);
        return IsLineSeparatorChar(c)
-               || (IsInsetChar(c) && getInset(pos) &&
+               || (c == Paragraph::META_INSET && getInset(pos) &&
                getInset(pos)->isLineSeparator());
 }
 
 
-bool Paragraph::isKomma(pos_type pos) const
-{
-       return IsKommaChar(getChar(pos));
-}
-
-
 /// Used by the spellchecker
 bool Paragraph::isLetter(pos_type pos) const
-{
-       value_type const c = getChar(pos);
-       if (IsLetterChar(c))
-               return true;
-       if (isInset(pos))
-               return getInset(pos)->isLetter();
-       // We want to pass the ' and escape chars to ispell
-       string const extra = lyxrc.isp_esc_chars + '\'';
-       return contains(extra, c);
-}
-
-
-bool Paragraph::isWord(pos_type pos) const
 {
        if (isInset(pos))
                return getInset(pos)->isLetter();
-       value_type const c = getChar(pos);
-       return !(IsSeparatorChar(c)
-                 || IsKommaChar(c)
-                 || IsInsetChar(c));
+       else {
+               value_type const c = getChar(pos);
+               return IsLetterChar(c) || IsDigit(c);
+       }
 }
 
 
@@ -1653,14 +1600,14 @@ string const Paragraph::asString(Buffer const & buffer,
                if (IsPrintable(c))
                        os << c;
                else if (c == META_INSET)
-                       getInset(i)->plaintext(buffer, os, runparams);
+                       getInset(i)->textString(buffer, os, runparams);
        }
 
        return os.str();
 }
 
 
-void Paragraph::setInsetOwner(UpdatableInset * inset)
+void Paragraph::setInsetOwner(InsetBase * inset)
 {
        pimpl_->inset_owner = inset;
 }
@@ -1722,9 +1669,9 @@ void Paragraph::setChange(lyx::pos_type pos, Change::Type type)
 }
 
 
-void Paragraph::markErased()
+void Paragraph::markErased(bool erased)
 {
-       pimpl_->markErased();
+       pimpl_->markErased(erased);
 }
 
 
@@ -1758,7 +1705,7 @@ void Paragraph::layout(LyXLayout_ptr const & new_layout)
 }
 
 
-UpdatableInset * Paragraph::inInset() const
+InsetBase * Paragraph::inInset() const
 {
        return pimpl_->inset_owner;
 }
@@ -1814,34 +1761,50 @@ bool Paragraph::allowEmpty() const
 }
 
 
-RowList::iterator Paragraph::getRow(pos_type pos)
+Row & Paragraph::getRow(pos_type pos, bool boundary)
 {
-       RowList::iterator rit = rows.end();
-       RowList::iterator const begin = rows.begin();
+       BOOST_ASSERT(!rows().empty());
+
+       // If boundary is set we should return the row on which
+       // the character before is inside.
+       if (pos > 0 && boundary)
+               --pos;
+
+       RowList::iterator rit = rows_.end();
+       RowList::iterator const begin = rows_.begin();
 
        for (--rit; rit != begin && rit->pos() > pos; --rit)
                ;
 
-       return rit;
+       return *rit;
 }
 
 
-RowList::const_iterator Paragraph::getRow(pos_type pos) const
+Row const & Paragraph::getRow(pos_type pos, bool boundary) const
 {
-       RowList::const_iterator rit = rows.end();
-       RowList::const_iterator const begin = rows.begin();
+       BOOST_ASSERT(!rows().empty());
+
+       // If boundary is set we should return the row on which
+       // the character before is inside.
+       if (pos > 0 && boundary)
+               --pos;
+
+       RowList::const_iterator rit = rows_.end();
+       RowList::const_iterator const begin = rows_.begin();
 
        for (--rit; rit != begin && rit->pos() > pos; --rit)
                ;
 
-       return rit;
+       return *rit;
 }
 
 
-size_t Paragraph::row(pos_type pos) const
+size_t Paragraph::pos2row(pos_type pos) const
 {
-       RowList::const_iterator rit = rows.end();
-       RowList::const_iterator const begin = rows.begin();
+       BOOST_ASSERT(!rows().empty());
+
+       RowList::const_iterator rit = rows_.end();
+       RowList::const_iterator const begin = rows_.begin();
 
        for (--rit; rit != begin && rit->pos() > pos; --rit)
                ;
@@ -1883,3 +1846,13 @@ unsigned char Paragraph::transformChar(unsigned char c, pos_type pos) const
                        return Encodings::TransformChar(c, Encodings::FORM_ISOLATED);
        }
 }
+
+
+void Paragraph::dump() const
+{
+       lyxerr << "Paragraph::dump: rows.size(): " << rows_.size() << endl;
+       for (size_t i = 0; i != rows_.size(); ++i) {
+               lyxerr << "  row " << i << ":   ";
+               rows_[i].dump();
+       }
+}