#include "BiblioInfo.h"
#include "Buffer.h"
+#include "Cursor.h"
#include "buffer_funcs.h"
#include "BufferParams.h"
#include "BufferView.h"
#include "Counters.h"
#include "DispatchResult.h"
+#include "Encoding.h"
#include "FuncRequest.h"
#include "InsetIterator.h"
#include "InsetList.h"
+#include "Language.h"
#include "Lexer.h"
+#include "output_xhtml.h"
#include "Paragraph.h"
#include "ParagraphList.h"
+#include "ParIterator.h"
#include "TextClass.h"
#include "frontends/alert.h"
+#include "support/lassert.h"
#include "support/convert.h"
+#include "support/debug.h"
#include "support/docstream.h"
#include "support/gettext.h"
#include "support/lstrings.h"
+#include "support/mutex.h"
using namespace std;
using namespace lyx::support;
int InsetBibitem::key_counter = 0;
+static Mutex counter_mutex;
docstring const key_prefix = from_ascii("key-");
-InsetBibitem::InsetBibitem(Buffer const & buf, InsetCommandParams const & p)
- : InsetCommand(p, "bibitem")
+InsetBibitem::InsetBibitem(Buffer * buf, InsetCommandParams const & p)
+ : InsetCommand(buf, p)
{
- Inset::setBuffer(const_cast<Buffer &>(buf));
- buffer_->invalidateBibinfoCache();
- if (getParam("key").empty())
+ buffer().invalidateBibinfoCache();
+ if (getParam("key").empty()) {
+ Mutex::Locker lock(&counter_mutex);
setParam("key", key_prefix + convert<docstring>(++key_counter));
+ }
}
InsetBibitem::~InsetBibitem()
{
- if (isBufferValid())
+ if (isBufferLoaded()) {
+ /* We do not use buffer() because Coverity believes that this
+ * may throw an exception. Actually this code path is not
+ * taken when buffer_ == 0 */
buffer_->invalidateBibinfoCache();
+ }
}
void InsetBibitem::updateCommand(docstring const & new_key, bool)
{
- docstring const old_key = getParam("key");
docstring key = new_key;
-
vector<docstring> bibkeys = buffer().masterBibInfo().getKeys();
- int i = 1;
-
if (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
+ int i = 1;
// generate unique label
key = new_key + '-' + convert<docstring>(i);
while (find(bibkeys.begin(), bibkeys.end(), key) != bibkeys.end()) {
"it will be changed to %2$s."), new_key, key));
}
setParam("key", key);
-
- buffer().updateLabels();
+ buffer().invalidateBibinfoCache();
}
{
static ParamInfo param_info_;
if (param_info_.empty()) {
- param_info_.add("label", ParamInfo::LATEX_OPTIONAL);
- param_info_.add("key", ParamInfo::LATEX_REQUIRED);
+ param_info_.add("label", ParamInfo::LATEX_OPTIONAL,
+ ParamInfo::HANDLING_LATEXIFY);
+ param_info_.add("key", ParamInfo::LATEX_REQUIRED,
+ ParamInfo::ParamHandling(ParamInfo::HANDLING_ESCAPE
+ | ParamInfo::HANDLING_LTRIM));
+ param_info_.add("literal", ParamInfo::LYX_INTERNAL);
}
return param_info_;
}
void InsetBibitem::doDispatch(Cursor & cur, FuncRequest & cmd)
{
- switch (cmd.action) {
+ switch (cmd.action()) {
case LFUN_INSET_MODIFY: {
InsetCommandParams p(BIBITEM_CODE);
- InsetCommand::string2params("bibitem", to_utf8(cmd.argument()), p);
+ InsetCommand::string2params(to_utf8(cmd.argument()), p);
if (p.getCmdName().empty()) {
- cur.noUpdate();
+ cur.noScreenUpdate();
break;
}
+
+ cur.recordUndo();
+
docstring const & old_key = params()["key"];
+ docstring const & old_label = params()["label"];
+ docstring const & old_literal = params()["literal"];
+ docstring label = p["label"];
+ docstring literal = p["literal"];
+
+ if (old_label != label) {
+ p["label"] = label;
+ cur.forceBufferUpdate();
+ buffer().invalidateBibinfoCache();
+ }
setParam("label", p["label"]);
+
+ if (old_literal != literal) {
+ p["literal"] = literal;
+ cur.forceBufferUpdate();
+ buffer().invalidateBibinfoCache();
+ }
+ setParam("literal", p["literal"]);
+
if (p["key"] != old_key) {
+ // changeRefsIfUnique handles undo
+ cur.bv().buffer().changeRefsIfUnique(old_key, p["key"]);
updateCommand(p["key"]);
- cur.bv().buffer().changeRefsIfUnique(old_key,
- params()["key"], CITE_CODE);
+ cur.forceBufferUpdate();
+ buffer().invalidateBibinfoCache();
}
- buffer_->invalidateBibinfoCache();
break;
}
if (prefixIs(getParam("key"), key_prefix)) {
int const key = convert<int>(getParam("key").substr(key_prefix.length()));
+ Mutex::Locker lock(&counter_mutex);
key_counter = max(key_counter, key);
}
}
docstring InsetBibitem::bibLabel() const
{
- docstring const & label = getParam("label");
+ BufferParams const & bp = buffer().masterBuffer()->params();
+ if (bp.citeEngineType() == ENGINE_TYPE_NUMERICAL)
+ return autolabel_;
+ docstring label = getParam("label");
+ if (!label.empty() && bp.citeEngine() == "natbib") {
+ // Add a space before opening paren
+ label = subst(label, from_ascii("("), from_ascii(" ("));
+ // and strip off long author list
+ docstring striplabel;
+ label = rsplit(label, striplabel, ')');
+ if (!striplabel.empty())
+ label = striplabel + ")";
+ }
return label.empty() ? autolabel_ : label;
}
}
-int InsetBibitem::plaintext(odocstream & os, OutputParams const &) const
+int InsetBibitem::plaintext(odocstringstream & os,
+ OutputParams const &, size_t) const
{
odocstringstream oss;
oss << '[' << bibLabel() << "] ";
docstring const str = oss.str();
os << str;
- return str.size();
+ return int(str.size());
}
// ale070405
-docstring bibitemWidest(Buffer const & buffer)
+docstring bibitemWidest(Buffer const & buffer, OutputParams const & runparams)
{
+ BufferParams const & bp = buffer.masterBuffer()->params();
+ if (bp.citeEngineType() == ENGINE_TYPE_NUMERICAL)
+ return from_ascii("99");
+
int w = 0;
- InsetBibitem const * bitem = 0;
+ InsetBibitem const * bitem = nullptr;
- // FIXME: this font is used unitialized for now but should be set to
+ // FIXME: this font is used uninitialized for now but should be set to
// a proportional font. Here is what Georg Baum has to say about it:
/*
bibitemWidest() is supposed to find the bibitem with the widest label in the
font.
*/
+ docstring lbl;
+
ParagraphList::const_iterator it = buffer.paragraphs().begin();
ParagraphList::const_iterator end = buffer.paragraphs().end();
+ bool is_literal = false;
for (; it != end; ++it) {
if (it->insetList().empty())
continue;
// So for now we just use the label size in order to be sure
// that GUI and no-GUI gives the same bibitem (even if that is
// potentially the wrong one.
- int const wx = label.size();
+ int const wx = int(label.size());
- if (wx > w)
+ if (wx > w) {
w = wx;
+ lbl = label;
+ is_literal = (bitem->getParam("literal") == "true");
+ }
}
- if (bitem && !bitem->bibLabel().empty())
- return bitem->bibLabel();
+ if (!lbl.empty()) {
+ InsetCommandParams p(BIBITEM_CODE);
+ if (is_literal)
+ p["literal"] = from_ascii("true");
+ return p.prepareCommand(runparams, lbl, ParamInfo::HANDLING_LATEXIFY);
+ }
return from_ascii("99");
}
-void InsetBibitem::fillWithBibKeys(BiblioInfo & keys, InsetIterator const & it) const
+void InsetBibitem::collectBibKeys(InsetIterator const & it, FileNameList & /*checkedFiles*/) const
{
docstring const key = getParam("key");
+ docstring const label = getParam("label");
BibTeXInfo keyvalmap(false);
- keyvalmap[from_ascii("label")] = getParam("label");
- DocIterator doc_it(it);
+ keyvalmap.key(key);
+ keyvalmap.label(label);
+
+ BufferParams const & bp = buffer().masterBuffer()->params();
+ Counters & counters = bp.documentClass().counters();
+ docstring const bibitem = from_ascii("bibitem");
+ if (bp.citeEngineType() == ENGINE_TYPE_NUMERICAL || getParam("label").empty()) {
+ if (counters.hasCounter(bibitem))
+ counters.step(bibitem, InternalUpdate);
+ string const & lang = it.paragraph().getParLanguage(bp)->code();
+ keyvalmap.setCiteNumber(counters.theCounter(bibitem, lang));
+ }
+
+ DocIterator doc_it(it);
doc_it.forwardPos();
- keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString();
- keys[key] = keyvalmap;
+ keyvalmap[from_ascii("ref")] = doc_it.paragraph().asString(
+ AS_STR_INSETS | AS_STR_SKIPDELETE);
+ buffer().addBibTeXInfo(key, keyvalmap);
}
-/// Update the counters of this inset and of its contents
-void InsetBibitem::updateLabels(ParIterator const &)
+// Update the counters of this inset and of its contents
+void InsetBibitem::updateBuffer(ParIterator const & it, UpdateType utype, bool const /*deleted*/)
{
- Counters & counters = buffer().masterBuffer()->params().documentClass().counters();
+ BufferParams const & bp = buffer().masterBuffer()->params();
+ Counters & counters = bp.documentClass().counters();
docstring const bibitem = from_ascii("bibitem");
- if (counters.hasCounter(bibitem) && getParam("label").empty()) {
- counters.step(bibitem);
- autolabel_ = counters.theCounter(bibitem);
+ if (bp.citeEngineType() == ENGINE_TYPE_NUMERICAL || getParam("label").empty()) {
+ if (counters.hasCounter(bibitem))
+ counters.step(bibitem, utype);
+ string const & lang = it.paragraph().getParLanguage(bp)->code();
+ autolabel_ = counters.theCounter(bibitem, lang);
} else {
autolabel_ = from_ascii("??");
}
}
+void InsetBibitem::docbook(XMLStream &, OutputParams const &) const
+{
+ // Nothing to do: everything is implemented in makeParagraphBibliography.
+}
+
+
+docstring InsetBibitem::xhtml(XMLStream & xs, OutputParams const &) const
+{
+ // FIXME XHTML
+ // XHTML 1.1 doesn't have the "name" attribute for <a>, so we have to use
+ // the "id" attribute to get the document to validate. Probably, we will
+ // need to use "name" anyway, eventually, because some browsers do not
+ // handle jumping to ids. If we don't do that, though, we can just put the
+ // id into the span tag.
+ string const attrs =
+ "id='LyXCite-" + to_utf8(xml::cleanAttr(getParam("key"))) + "'";
+ xs << xml::CompTag("a", attrs);
+ xs << xml::StartTag("span", "class='bibitemlabel'");
+ xs << bibLabel();
+ xs << xml::EndTag("span");
+ return docstring();
+}
+
+
} // namespace lyx