3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alejandro Aguilar Sierra
7 * \author Angus Leeming
9 * Full author contact details are available in file CREDITS.
14 #include "insetbibtex.h"
15 #include "metricsinfo.h"
17 #include "BufferView.h"
19 #include "funcrequest.h"
21 #include "latexrunparams.h"
24 #include "metricsinfo.h"
26 #include "support/filetools.h"
27 #include "support/path.h"
28 #include "support/os.h"
29 #include "support/lstrings.h"
30 #include "support/lyxalgo.h"
31 #include "support/LAssert.h"
32 #include "support/tostr.h"
37 using support::FileName;
46 InsetBibtexParams::InsetBibtexParams()
51 bool InsetBibtexParams::empty() const
53 return databases.empty();
57 void InsetBibtexParams::erase()
65 void InsetBibtexParams::write(Buffer const & buffer, std::ostream & os) const
69 vector<FileName>::const_iterator it = databases.begin();
70 vector<FileName>::const_iterator end = databases.end();
71 for (; it != end; ++it) {
73 << it->outputFilename(buffer.filePath())
77 os << "\tstyle " << style << '\n';
79 os << "\tbibtotoc " << tostr(bibtotoc) << '\n';
83 void InsetBibtexParams::read(Buffer const & buffer, LyXLex & lex)
92 keyword_item bibtex_tags[] = {
93 { "\\end_inset", BIB_END },
94 { "bibtotoc", BIB_BIBTOTOC },
95 { "filename", BIB_FILENAME},
99 pushpophelper pph(lex, bibtex_tags, BIB_END);
101 bool found_end = false;
102 bool read_error = false;
109 filename.set(lex.getString(), buffer.filePath());
110 databases.push_back(filename);
116 style = lex.getString();
122 bibtotoc = lex.getBool();
131 lex.printError("BibtexInset::read: "
132 "Wrong tag: $$Token");
137 if (found_end || read_error)
142 lex.printError("BibtexInset::read: "
143 "Missing \\end_inset.");
148 InsetBibtex::InsetBibtex()
149 : set_label_(false), center_indent_(0)
154 InsetBibtex::InsetBibtex(InsetBibtexParams const & p)
155 : params_(p), set_label_(false), center_indent_(0)
159 InsetBibtex::~InsetBibtex()
161 InsetBibtexMailer(*this).hideDialog();
165 std::auto_ptr<InsetBase> InsetBibtex::clone() const
167 return std::auto_ptr<InsetBase>(new InsetBibtex(*this));
171 dispatch_result InsetBibtex::localDispatch(FuncRequest const & cmd)
173 switch (cmd.action) {
175 case LFUN_INSET_EDIT:
176 InsetBibtexMailer(*this).showDialog(cmd.view());
179 case LFUN_INSET_MODIFY: {
180 Buffer const * buffer = cmd.view()->buffer();
182 InsetBibtexMailer::string2params(cmd.argument, *buffer, p);
187 case LFUN_INSET_DIALOG_UPDATE:
188 InsetBibtexMailer(*this).updateDialog(cmd.view());
191 case LFUN_MOUSE_RELEASE:
192 return localDispatch(FuncRequest(cmd.view(), LFUN_INSET_EDIT));
195 return InsetOld::localDispatch(cmd);
200 string const InsetBibtex::getScreenLabel(Buffer const &) const
202 return _("BibTeX Generated References");
206 void InsetBibtex::metrics(MetricsInfo & mi, Dimension & dim) const
210 button_.update(getScreenLabel(*mi.base.bv->buffer()),
211 editable() != NOT_EDITABLE);
213 button_.metrics(mi, dim);
214 center_indent_ = (mi.base.textwidth - dim.wid) / 2;
215 dim.wid = mi.base.textwidth;
220 void InsetBibtex::draw(PainterInfo & pi, int x, int y) const
222 button_.draw(pi, x + center_indent_, y);
226 void InsetBibtex::write(Buffer const & buffer, std::ostream & os) const
228 params().write(buffer, os);
232 void InsetBibtex::read(Buffer const & buffer, LyXLex & lex)
237 // Replace the inset's store
242 int InsetBibtex::latex(Buffer const & buffer, ostream & os,
243 LatexRunParams const & runparams) const
246 // 1. \bibliographystyle{style}
247 if (!params().style.empty()) { // we want no \biblio...{}
248 string style = params().style;
250 string const abs_style =
251 support::MakeAbsPath(style, buffer.filePath());
252 if (!runparams.nice && support::IsFileReadable(abs_style + ".bst"))
255 ss << "\\bibliographystyle{" << style << "}\n";
258 // 2. \addcontentsline{...} - if option bibtotoc set
259 if (params().bibtotoc) {
260 // Assumption: if the textclass name does not contain "art",
262 BufferParams const & bp = buffer.params;
263 if (!support::contains(bp.getLyXTextClass().name(), "art")) {
264 if (bp.sides == LyXTextClass::OneSide) {
267 ss << "\\cleardoublepage";
271 ss << "\\addcontentsline{toc}{chapter}{\\bibname}\n";
274 ss << "\\addcontentsline{toc}{section}{\\refname}\n";
278 // 3. \bibliography{database}
279 // If we generate in a temp dir, we _need_ to use the absolute path,
280 // else rely on the user.
281 ss << "\\bibliography{";
282 vector<FileName>::const_iterator begin = params().databases.begin();
283 vector<FileName>::const_iterator end = params().databases.end();
284 vector<FileName>::const_iterator it = begin;
285 for (; it != end; ++it) {
288 string db = it->outputFilename(buffer.filePath());
289 if (!runparams.nice &&
290 support::IsFileReadable(it->absFilename())+".bib")
291 db = support::os::external_path(it->absFilename());
297 string const output = STRCONV(ss.str());
299 return int(lyx::count(output.begin(), output.end(),'\n') + 1);
303 int InsetBibtex::ascii(Buffer const &, std::ostream &, int) const
309 int InsetBibtex::linuxdoc(Buffer const &, std::ostream &) const
315 int InsetBibtex::docbook(Buffer const &, std::ostream &, bool) const
321 vector<string> const InsetBibtex::getFiles(Buffer const & buffer) const
323 support::Path p(buffer.filePath());
325 vector<string> files;
326 vector<FileName>::const_iterator it = params().databases.begin();
327 vector<FileName>::const_iterator end = params().databases.end();
328 for (; it != end; ++it) {
329 // I really do need to pass the buffer path here...
330 // FileName needs extending it would seem.
331 string file_in = it->relFilename(buffer.filePath());
332 string file_out = support::findtexfile(
333 support::ChangeExtension(file_in, "bib"), "bib");
334 lyxerr[Debug::LATEX] << "Bibfile: " << file_in
335 << ' ' << file_out << endl;
337 // If we don't find a matching file name just fail silently
338 if (!file_out.empty())
339 files.push_back(file_out);
346 // This method returns a comma separated list of Bibtex entries
347 void InsetBibtex::fillWithBibKeys(Buffer const & buffer,
348 std::vector<std::pair<string, string> > & keys) const
350 vector<string> const files = getFiles(buffer);
351 for (vector<string>::const_iterator it = files.begin();
352 it != files.end(); ++ it) {
353 // This is a _very_ simple parser for Bibtex database
354 // files. All it does is to look for lines starting
355 // in @ and not being @preamble and @string entries.
356 // It does NOT do any syntax checking!
357 ifstream ifs(it->c_str());
359 while (getline(ifs, linebuf0)) {
360 string linebuf = support::trim(linebuf0);
361 if (linebuf.empty()) continue;
362 if (support::prefixIs(linebuf, "@")) {
363 linebuf = support::subst(linebuf, '{', '(');
365 linebuf = support::split(linebuf, tmp, '(');
366 tmp = support::ascii_lowercase(tmp);
367 if (!support::prefixIs(tmp, "@string")
368 && !support::prefixIs(tmp, "@preamble")) {
369 linebuf = support::split(linebuf, tmp, ',');
370 tmp = support::ltrim(tmp, " \t");
372 keys.push_back(pair<string,string>(tmp,string()));
375 } else if (!keys.empty()) {
376 keys.back().second += linebuf + "\n";
383 bool InsetBibtex::addDatabase(string const & /* db */)
386 #warning addDatabase is currently disabled (no LFUN).
390 string contents(getContents());
391 if (!support::contains(contents, db)) {
392 if (!contents.empty())
394 setContents(contents + db);
402 bool InsetBibtex::delDatabase(string const & /* db */)
405 #warning delDatabase is currently disabled (no LFUN).
408 if (support::contains(getContents(), db)) {
410 int const n = tokenPos(getContents(), ',', bd);
412 // Weird code, would someone care to explain this?(Lgb)
415 setContents(support::subst(getContents(), tmp, ", "));
417 setContents(support::split(getContents(), bd, ','));
426 void InsetBibtex::setParams(InsetBibtexParams const & params)
432 string const InsetBibtexMailer::name_ = "bibtex";
435 InsetBibtexMailer::InsetBibtexMailer(InsetBibtex & inset)
440 string const InsetBibtexMailer::inset2string(Buffer const & buffer) const
442 return params2string(inset_.params(), buffer);
446 void InsetBibtexMailer::string2params(string const & in,
447 Buffer const & buffer,
448 InsetBibtexParams & params)
450 params = InsetBibtexParams();
455 istringstream data(STRCONV(in));
461 string const token = lex.getString();
466 // This is part of the inset proper that is usually swallowed
467 // by Buffer::readInset
470 string const token = lex.getString();
471 if (token != "Bibtex")
476 params.read(buffer, lex);
481 string const InsetBibtexMailer::params2string(InsetBibtexParams const & params,
482 Buffer const & buffer)
485 data << name_ << ' ';
486 params.write(buffer, data);
487 data << "\\end_inset\n";
488 return STRCONV(data.str());