#include "TexRow.h"
#include "VSpace.h"
+#include "frontends/alert.h"
#include "frontends/FontMetrics.h"
#include "insets/InsetBibitem.h"
namespace lyx {
using support::contains;
+using support::suffixIs;
using support::rsplit;
/////////////////////////////////////////////////////////////////////
class Encoding;
-class LyXLayout;
+class Layout;
class Paragraph::Pimpl {
/// Output the surrogate pair formed by \p c and \p next to \p os.
/// \return the number of characters written.
int latexSurrogatePair(odocstream & os, value_type c, value_type next,
- Encoding const &);
+ Encoding const &);
/// Output a space in appropriate formatting (or a surrogate pair
/// if the next character is a combining character).
/// \return whether a surrogate pair was output.
bool simpleTeXBlanks(Encoding const &,
- odocstream &, TexRow & texrow,
+ odocstream &, TexRow & texrow,
pos_type & i,
unsigned int & column,
Font const & font,
- LyXLayout const & style);
+ Layout const & style);
///
void simpleTeXSpecialChars(Buffer const &, BufferParams const &,
- odocstream &,
- TexRow & texrow, OutputParams const &,
- Font & running_font,
+ odocstream &,
+ TexRow & texrow, OutputParams &,
+ Font & running_font,
Font & basefont,
Font const & outerfont,
bool & open_font,
- Change::Type & running_change,
- LyXLayout const & style,
+ Change & running_change,
+ Layout const & style,
pos_type & i,
unsigned int & column, value_type const c);
///
void validate(LaTeXFeatures & features,
- LyXLayout const & layout) const;
+ Layout const & layout) const;
///
unsigned int id_;
///
ParagraphParameters params;
-private:
+//private:
///
pos_type size() const { return owner_->size(); }
/// match a string against a particular point in the paragraph
// Update the font table.
FontTable search_font(pos, Font());
- for (FontList::iterator it
+ for (FontList::iterator it
= lower_bound(fontlist.begin(), fontlist.end(), search_font, matchFT());
it != fontlist.end(); ++it)
{
void Paragraph::Pimpl::insertInset(pos_type pos, Inset * inset,
- Change const & change)
+ Change const & change)
{
BOOST_ASSERT(inset);
BOOST_ASSERT(pos >= 0 && pos <= size());
if (trackChanges) {
Change change = changes_.lookup(pos);
- // set the character to DELETED if
+ // set the character to DELETED if
// a) it was previously unchanged or
// b) it was inserted by a co-author
bool Paragraph::Pimpl::simpleTeXBlanks(Encoding const & encoding,
- odocstream & os, TexRow & texrow,
- pos_type & i,
+ odocstream & os, TexRow & texrow,
+ pos_type & i,
unsigned int & column,
Font const & font,
- LyXLayout const & style)
+ Layout const & style)
{
if (style.pass_thru)
return false;
BufferParams const & bparams,
odocstream & os,
TexRow & texrow,
- OutputParams const & runparams,
+ OutputParams & runparams,
Font & running_font,
Font & basefont,
Font const & outerfont,
bool & open_font,
- Change::Type & running_change,
- LyXLayout const & style,
+ Change & running_change,
+ Layout const & style,
pos_type & i,
unsigned int & column,
value_type const c)
} else {
if (open_font) {
column += running_font.latexWriteEndChanges(
- os, basefont, basefont);
+ os, bparams, runparams,
+ basefont, basefont);
open_font = false;
}
break;
}
- // output change tracking marks only if desired,
- // if dvipost is installed,
- // and with dvi/ps (other formats don't work)
- LaTeXFeatures features(buf, bparams, runparams);
- bool const output = bparams.outputChanges
- && runparams.flavor == OutputParams::LATEX
- && features.isAvailable("dvipost");
+ if (lookupChange(i).type == Change::DELETED) {
+ if( ++runparams.inDeletedInset == 1)
+ runparams.changeOfDeletedInset = lookupChange(i);
+ }
if (inset->canTrackChanges()) {
- column += Changes::latexMarkChange(os, running_change,
- Change::UNCHANGED, output);
- running_change = Change::UNCHANGED;
+ column += Changes::latexMarkChange(os, bparams, running_change,
+ Change(Change::UNCHANGED));
+ running_change = Change(Change::UNCHANGED);
}
bool close = false;
|| inset->lyxCode() == Inset::MATH_CODE
|| inset->lyxCode() == Inset::URL_CODE)
&& running_font.isRightToLeft()) {
- os << "\\L{";
+ if (running_font.language()->lang() == "farsi")
+ os << "\\beginL{}";
+ else
+ os << "\\L{";
close = true;
}
-#ifdef WITH_WARNINGS
-#warning Bug: we can have an empty font change here!
+// FIXME: Bug: we can have an empty font change here!
// if there has just been a font change, we are going to close it
// right now, which means stupid latex code like \textsf{}. AFAIK,
// this does not harm dvi output. A minor bug, thus (JMarc)
-#endif
- // some insets cannot be inside a font change command
+ // Some insets cannot be inside a font change command.
+ // However, even such insets *can* be placed in \L or \R
+ // or their equivalents (for RTL language switches), so we don't
+ // close the language in those cases.
+ // ArabTeX, though, cannot handle this special behavior, it seems.
+ bool arabtex = basefont.language()->lang() == "arabic_arabtex" ||
+ running_font.language()->lang() == "arabic_arabtex";
if (open_font && inset->noFontChange()) {
- column += running_font.latexWriteEndChanges(
- os, basefont, basefont);
- open_font = false;
- basefont = owner_->getLayoutFont(bparams, outerfont);
- running_font = basefont;
+ bool closeLanguage = arabtex ||
+ basefont.isRightToLeft() == running_font.isRightToLeft();
+ unsigned int count = running_font.latexWriteEndChanges(
+ os, bparams, runparams,
+ basefont, basefont, closeLanguage);
+ column += count;
+ // if any font properties were closed, update the running_font,
+ // making sure, however, to leave the language as it was
+ if (count > 0) {
+ // FIXME: probably a better way to keep track of the old
+ // language, than copying the entire font?
+ Font const copy_font(running_font);
+ basefont = owner_->getLayoutFont(bparams, outerfont);
+ running_font = basefont;
+ if (!closeLanguage)
+ running_font.setLanguage(copy_font.language());
+ // leave font open if language is still open
+ open_font = (running_font.language() == basefont.language());
+ if (closeLanguage)
+ runparams.local_font = &basefont;
+ }
}
int tmp = inset->latex(buf, os, runparams);
- if (close)
- os << '}';
+ if (close) {
+ if (running_font.language()->lang() == "farsi")
+ os << "\\endL{}";
+ else
+ os << '}';
+ }
if (tmp) {
for (int j = 0; j < tmp; ++j) {
} else {
column += os.tellp() - len;
}
+
+ if (lookupChange(i).type == Change::DELETED) {
+ --runparams.inDeletedInset;
+ }
}
break;
void Paragraph::Pimpl::validate(LaTeXFeatures & features,
- LyXLayout const & layout) const
+ Layout const & layout) const
{
BufferParams const & bparams = features.bufferParams();
{
features.useLanguage(language);
LYXERR(Debug::LATEX) << "Found language "
- << language->babel() << endl;
+ << language->lang() << endl;
}
}
}
// First write the layout
- os << "\n\\begin_layout " << layout()->name() << '\n';
+ os << "\n\\begin_layout " << to_utf8(layout()->name()) << '\n';
params().write(os);
void Paragraph::insert(pos_type start, docstring const & str,
- Font const & font, Change const & change)
+ Font const & font, Change const & change)
{
for (size_t i = 0, n = str.size(); i != n ; ++i)
insertChar(start + i, str[i], font, change);
void Paragraph::insertChar(pos_type pos, Paragraph::value_type c,
- bool trackChanges)
+ bool trackChanges)
{
pimpl_->insertChar(pos, c, Change(trackChanges ?
- Change::INSERTED : Change::UNCHANGED));
+ Change::INSERTED : Change::UNCHANGED));
}
void Paragraph::insertChar(pos_type pos, Paragraph::value_type c,
- Font const & font, bool trackChanges)
+ Font const & font, bool trackChanges)
{
pimpl_->insertChar(pos, c, Change(trackChanges ?
- Change::INSERTED : Change::UNCHANGED));
+ Change::INSERTED : Change::UNCHANGED));
setFont(pos, font);
}
void Paragraph::insertChar(pos_type pos, Paragraph::value_type c,
- Font const & font, Change const & change)
+ Font const & font, Change const & change)
{
pimpl_->insertChar(pos, c, change);
setFont(pos, font);
void Paragraph::insertInset(pos_type pos, Inset * inset,
- Change const & change)
+ Change const & change)
{
pimpl_->insertInset(pos, inset, change);
}
void Paragraph::insertInset(pos_type pos, Inset * inset,
- Font const & font, Change const & change)
+ Font const & font, Change const & change)
{
pimpl_->insertInset(pos, inset, change);
+ // Set the font/language of the inset...
setFont(pos, font);
+ // ... as well as the font/language of the text inside the inset
+ // FIXME: This is far from perfect. It basically overrides work being done
+ // in the InsetText constructor. Also, it doesn't work for Tables
+ // (precisely because each cell's font/language is set in the Table's
+ // constructor, so by now it's too late). The long-term solution should
+ // be moving current_font into Cursor, and getting rid of all this...
+ // (see http://thread.gmane.org/gmane.editors.lyx.devel/88869/focus=88944)
+ if (inset->asTextInset()) {
+ inset->asTextInset()->text_.current_font = font;
+ inset->asTextInset()->text_.real_current_font = font;
+ }
}
// Gets the fully instantiated font at a given position in a paragraph
-// This is basically the same function as LyXText::GetFont() in text2.cpp.
+// This is basically the same function as Text::GetFont() in text2.cpp.
// The difference is that this one is used for generating the LaTeX file,
// and thus cosmetic "improvements" are disallowed: This has to deliver
// the true picture of the buffer. (Asger)
{
BOOST_ASSERT(pos >= 0);
- LyXLayout_ptr const & lout = layout();
+ Layout_ptr const & lout = layout();
pos_type const body_pos = beginOfBody();
}
-docstring Paragraph::expandLabel(LyXLayout_ptr const & layout,
+docstring Paragraph::expandLabel(Layout_ptr const & layout,
BufferParams const & bparams, bool process_appendix) const
{
- LyXTextClass const & tclass = bparams.getLyXTextClass();
+ TextClass const & tclass = bparams.getTextClass();
docstring fmt;
if (process_appendix && params().appendix())
else
fmt = translateIfPossible(layout->labelstring(), bparams);
+ if (fmt.empty() && layout->labeltype == LABEL_COUNTER
+ && !layout->counter.empty())
+ fmt = "\\the" + layout->counter;
+
// handle 'inherited level parts' in 'fmt',
// i.e. the stuff between '@' in '@Section@.\arabic{subsection}'
size_t const i = fmt.find('@', 0);
size_t const j = fmt.find('@', i + 1);
if (j != docstring::npos) {
docstring parent(fmt, i + 1, j - i - 1);
- // FIXME UNICODE
- docstring label = expandLabel(tclass[to_utf8(parent)], bparams);
- fmt = docstring(fmt, 0, i) + label + docstring(fmt, j + 1, docstring::npos);
+ docstring label = expandLabel(tclass[parent], bparams,
+ process_appendix);
+ fmt = docstring(fmt, 0, i) + label
+ + docstring(fmt, j + 1, docstring::npos);
}
}
}
-void Paragraph::applyLayout(LyXLayout_ptr const & new_layout)
+void Paragraph::applyLayout(Layout_ptr const & new_layout)
{
layout(new_layout);
- params().labelWidthString(docstring());
- params().align(LYX_ALIGN_LAYOUT);
- params().spacing(Spacing(Spacing::Default));
+ LyXAlignment const oldAlign = params().align();
+
+ if (!(oldAlign & layout()->alignpossible)) {
+ frontend::Alert::warning(_("Alignment not permitted"),
+ _("The new layout does not permit the alignment previously used.\nSetting to default."));
+ params().align(LYX_ALIGN_LAYOUT);
+ }
}
// This could go to ParagraphParameters if we want to
int Paragraph::startTeXParParams(BufferParams const & bparams,
- odocstream & os, TexRow & texrow,
+ odocstream & os, TexRow & texrow,
bool moving_arg) const
{
int column = 0;
os << "\\noindent ";
column += 10;
}
+
+ LyXAlignment const curAlign = params().align();
- switch (params().align()) {
+ if (curAlign == layout()->align)
+ return column;
+
+ switch (curAlign) {
case LYX_ALIGN_NONE:
case LYX_ALIGN_BLOCK:
case LYX_ALIGN_LAYOUT:
break;
}
- switch (params().align()) {
+ switch (curAlign) {
case LYX_ALIGN_NONE:
case LYX_ALIGN_BLOCK:
case LYX_ALIGN_LAYOUT:
// This could go to ParagraphParameters if we want to
-int Paragraph::endTeXParParams(BufferParams const & bparams,
- odocstream & os, TexRow & texrow,
+int Paragraph::endTeXParParams(BufferParams const & bparams,
+ odocstream & os, TexRow & texrow,
bool moving_arg) const
{
int column = 0;
bool return_value = false;
- LyXLayout_ptr style;
+ Layout_ptr style;
// well we have to check if we are in an inset with unlimited
// length (all in one row) if that is true then we don't allow
bool asdefault = forceDefaultParagraphs();
if (asdefault) {
- style = bparams.getLyXTextClass().defaultLayout();
+ style = bparams.getTextClass().defaultLayout();
} else {
style = layout();
}
// of the body.
Font basefont;
- // output change tracking marks only if desired,
- // if dvipost is installed,
- // and with dvi/ps (other formats don't work)
- bool const output = bparams.outputChanges
- && runparams.flavor == OutputParams::LATEX
- && LaTeXFeatures::isAvailable("dvipost");
-
// Maybe we have to create a optional argument.
pos_type body_pos = beginOfBody();
unsigned int column = 0;
// Do we have an open font change?
bool open_font = false;
- Change::Type runningChangeType = Change::UNCHANGED;
+ Change runningChange = Change(Change::UNCHANGED);
texrow.start(id(), 0);
if (body_pos > 0) {
if (open_font) {
column += running_font.latexWriteEndChanges(
- os, basefont, basefont);
+ os, bparams, runparams,
+ basefont, basefont);
open_font = false;
}
basefont = getLayoutFont(bparams, outerfont);
running_font = basefont;
- column += Changes::latexMarkChange(os,
- runningChangeType, Change::UNCHANGED, output);
- runningChangeType = Change::UNCHANGED;
+ column += Changes::latexMarkChange(os, bparams,
+ runningChange, Change(Change::UNCHANGED));
+ runningChange = Change(Change::UNCHANGED);
os << "}] ";
column +=3;
}
if (!asdefault)
- column += startTeXParParams(bparams, os,
+ column += startTeXParParams(bparams, os,
texrow,
runparams.moving_arg);
}
- Change::Type changeType = pimpl_->lookupChange(i).type;
+ Change const & change = runparams.inDeletedInset ? runparams.changeOfDeletedInset
+ : pimpl_->lookupChange(i);
+
+ if (bparams.outputChanges && runningChange != change) {
+ if (open_font) {
+ column += running_font.latexWriteEndChanges(
+ os, bparams, runparams, basefont, basefont);
+ open_font = false;
+ }
+ basefont = getLayoutFont(bparams, outerfont);
+ running_font = basefont;
+
+ column += Changes::latexMarkChange(os, bparams, runningChange, change);
+ runningChange = change;
+ }
// do not output text which is marked deleted
// if change tracking output is disabled
- if (!output && changeType == Change::DELETED) {
- runningChangeType = changeType;
+ if (!bparams.outputChanges && change.type == Change::DELETED) {
continue;
}
++column;
-
- column += Changes::latexMarkChange(os, runningChangeType,
- changeType, output);
- runningChangeType = changeType;
value_type const c = getChar(i);
font.language() != running_font.language()))
{
column += running_font.latexWriteEndChanges(
- os, basefont,
+ os, bparams, runparams, basefont,
(i == body_pos-1) ? basefont : font);
running_font = basefont;
open_font = false;
}
// Switch file encoding if necessary
- int const count = switchEncoding(os, bparams,
- runparams.moving_arg, *(runparams.encoding),
- *(font.language()->encoding()));
- if (count > 0) {
- column += count;
- runparams.encoding = font.language()->encoding();
+ if (runparams.encoding->package() == Encoding::inputenc &&
+ font.language()->encoding()->package() == Encoding::inputenc) {
+ std::pair<bool, int> const enc_switch = switchEncoding(os, bparams,
+ runparams.moving_arg, *(runparams.encoding),
+ *(font.language()->encoding()));
+ if (enc_switch.first) {
+ column += enc_switch.second;
+ runparams.encoding = font.language()->encoding();
+ }
}
// Do we need to change font?
font.language() != running_font.language()) &&
i != body_pos - 1)
{
- column += font.latexWriteStartChanges(os, basefont,
- last_font);
+ odocstringstream ods;
+ column += font.latexWriteStartChanges(ods, bparams,
+ runparams, basefont,
+ last_font);
running_font = font;
open_font = true;
+ docstring fontchange = ods.str();
+ // check if the fontchange ends with a trailing blank
+ // (like "\small " (see bug 3382)
+ if (suffixIs(fontchange, ' ') && c == ' ')
+ os << fontchange.substr(0, fontchange.size() - 1)
+ << from_ascii("{}");
+ else
+ os << fontchange;
}
if (c == ' ') {
pimpl_->simpleTeXSpecialChars(buf, bparams, os,
texrow, rp, running_font,
basefont, outerfont, open_font,
- runningChangeType, *style, i, column, c);
+ runningChange, *style, i, column, c);
+
+ // Set the encoding to that returned from simpleTeXSpecialChars (see
+ // comment for encoding member in OutputParams.h)
+ runparams.encoding = rp.encoding;
}
// If we have an open font definition, we have to close it
#ifdef FIXED_LANGUAGE_END_DETECTION
if (next_) {
running_font
- .latexWriteEndChanges(os, basefont,
+ .latexWriteEndChanges(os, bparams, runparams,
+ basefont,
next_->getFont(bparams, 0, outerfont));
} else {
- running_font.latexWriteEndChanges(os, basefont,
- basefont);
+ running_font.latexWriteEndChanges(os, bparams,
+ runparams, basefont, basefont);
}
#else
-#ifdef WITH_WARNINGS
-//#warning For now we ALWAYS have to close the foreign font settings if they are
-//#warning there as we start another \selectlanguage with the next paragraph if
-//#warning we are in need of this. This should be fixed sometime (Jug)
-#endif
- running_font.latexWriteEndChanges(os, basefont, basefont);
+//FIXME: For now we ALWAYS have to close the foreign font settings if they are
+//FIXME: there as we start another \selectlanguage with the next paragraph if
+//FIXME: we are in need of this. This should be fixed sometime (Jug)
+ running_font.latexWriteEndChanges(os, bparams, runparams,
+ basefont, basefont);
#endif
}
- column += Changes::latexMarkChange(os,
- runningChangeType, Change::UNCHANGED, output);
+ column += Changes::latexMarkChange(os, bparams, runningChange, Change(Change::UNCHANGED));
// Needed if there is an optional argument but no contents.
if (body_pos > 0 && body_pos == size()) {
}
if (!asdefault) {
- column += endTeXParParams(bparams, os, texrow,
+ column += endTeXParParams(bparams, os, texrow,
runparams.moving_arg);
}
lyx_code != Inset::INCLUDE_CODE &&
lyx_code != Inset::GRAPHICS_CODE &&
lyx_code != Inset::ERT_CODE &&
+ lyx_code != Inset::LISTINGS_CODE &&
lyx_code != Inset::FLOAT_CODE &&
lyx_code != Inset::TABULAR_CODE) {
return false;
if (c == ' ')
break;
os << sgml::escapeChar(c);
- }
+ }
}
return i;
}
{
bool emph_flag = false;
- LyXLayout_ptr const & style = layout();
+ Layout_ptr const & style = layout();
Font font_old =
style->labeltype == LABEL_MANUAL ? style->labelfont : style->font;
value_type c = getChar(i);
if (style->pass_thru)
- os.put(c);
+ os.put(c);
else
- os << sgml::escapeChar(c);
+ os << sgml::escapeChar(c);
}
font_old = font;
}
{
if (!empty())
return getFirstFontSettings(bparams).language();
-#ifdef WITH_WARNINGS
-#warning FIXME we should check the prev par as well (Lgb)
-#endif
+ // FIXME: we should check the prev par as well (Lgb)
return bparams.language;
}
{
return lyxrc.rtl_support
&& getParLanguage(bparams)->rightToLeft()
- && ownerCode() != Inset::ERT_CODE;
+ && ownerCode() != Inset::ERT_CODE
+ && ownerCode() != Inset::LISTINGS_CODE;
}
os << params().labelString() << ' ';
for (pos_type i = beg; i < end; ++i) {
- value_type const c = getUChar(buffer.params(), i);
+ value_type const c = getChar(i);
if (isPrintable(c))
os.put(c);
else if (c == META_INSET)
}
-LyXLayout_ptr const & Paragraph::layout() const
+Layout_ptr const & Paragraph::layout() const
{
return layout_;
}
-void Paragraph::layout(LyXLayout_ptr const & new_layout)
+void Paragraph::layout(Layout_ptr const & new_layout)
{
layout_ = new_layout;
}
// for now we just need this, later should we need this in some
// other way we can always add a function to Inset too.
- return ownerCode() == Inset::ERT_CODE;
+ return ownerCode() == Inset::ERT_CODE || ownerCode() == Inset::LISTINGS_CODE;
}
{
if (layout()->keepempty)
return true;
- return ownerCode() == Inset::ERT_CODE;
+ return ownerCode() == Inset::ERT_CODE || ownerCode() == Inset::LISTINGS_CODE;
}
}
-bool Paragraph::checkBiblio(bool track_changes)
+int Paragraph::checkBiblio(bool track_changes)
{
+ //FIXME From JS:
+ //This is getting more and more a mess. ...We really should clean
+ //up this bibitem issue for 1.6. See also bug 2743.
+
// Add bibitem insets if necessary
if (layout()->labeltype != LABEL_BIBLIO)
- return false;
+ return 0;
bool hasbibitem = !insetlist.empty()
// Insist on it being in pos 0
&& getChar(0) == Paragraph::META_INSET
&& insetlist.begin()->inset->lyxCode() == Inset::BIBITEM_CODE;
- if (hasbibitem)
- return false;
+ docstring oldkey;
+ docstring oldlabel;
+
+ // remove a bibitem in pos != 0
+ // restore it later in pos 0 if necessary
+ // (e.g. if a user inserts contents _before_ the item)
+ // we're assuming there's only one of these, which there
+ // should be.
+ int erasedInsetPosition = -1;
+ InsetList::iterator it = insetlist.begin();
+ InsetList::iterator end = insetlist.end();
+ for (; it != end; ++it)
+ if (it->inset->lyxCode() == Inset::BIBITEM_CODE
+ && it->pos > 0) {
+ InsetBibitem * olditem = static_cast<InsetBibitem *>(it->inset);
+ oldkey = olditem->getParam("key");
+ oldlabel = olditem->getParam("label");
+ erasedInsetPosition = it->pos;
+ eraseChar(erasedInsetPosition, track_changes);
+ break;
+ }
+
+ //There was an InsetBibitem at the beginning, and we didn't
+ //have to erase one.
+ if (hasbibitem && erasedInsetPosition < 0)
+ return 0;
+ //There was an InsetBibitem at the beginning and we did have to
+ //erase one. So we give its properties to the beginning inset.
+ if (hasbibitem) {
+ InsetBibitem * inset =
+ static_cast<InsetBibitem *>(insetlist.begin()->inset);
+ if (!oldkey.empty())
+ inset->setParam("key", oldkey);
+ inset->setParam("label", oldlabel);
+ return -erasedInsetPosition;
+ }
+
+ //There was no inset at the beginning, so we need to create one with
+ //the key and label of the one we erased.
InsetBibitem * inset(new InsetBibitem(InsetCommandParams("bibitem")));
+ // restore values of previously deleted item in this par.
+ if (!oldkey.empty())
+ inset->setParam("key", oldkey);
+ inset->setParam("label", oldlabel);
insertInset(0, static_cast<Inset *>(inset),
- Change(track_changes ? Change::INSERTED : Change::UNCHANGED));
+ Change(track_changes ? Change::INSERTED : Change::UNCHANGED));
- return true;
+ return 1;
+}
+
+
+void Paragraph::checkAuthors(AuthorList const & authorList)
+{
+ pimpl_->changes_.checkAuthors(authorList);
}
} // namespace lyx