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
8 * Full author contact details are available in file CREDITS
16 #include "BufferView.h"
21 #include "frontends/font_metrics.h"
22 #include "frontends/LyXView.h"
24 #include "frontends/Dialogs.h"
26 #include "support/filetools.h"
27 #include "support/path.h"
28 #include "support/os.h"
29 #include "support/lstrings.h"
30 #include "support/LAssert.h"
43 int InsetBibKey::key_counter = 0;
44 const string key_prefix = "key-";
46 InsetBibKey::InsetBibKey(InsetCommandParams const & p)
47 : InsetCommand(p), counter(1)
49 if (getContents().empty())
50 setContents(key_prefix + tostr(++key_counter));
54 InsetBibKey::~InsetBibKey()
59 Inset * InsetBibKey::clone(Buffer const &, bool) const
61 InsetBibKey * b = new InsetBibKey(params());
62 b->setCounter(counter);
67 void InsetBibKey::setCounter(int c)
73 // I'm sorry but this is still necessary because \bibitem is used also
74 // as a LyX 2.x command, and lyxlex is not enough smart to understand
75 // real LaTeX commands. Yes, that could be fixed, but would be a waste
76 // of time cause LyX3 won't use lyxlex anyway. (ale)
77 void InsetBibKey::write(Buffer const *, ostream & os) const
79 os << "\n\\layout Bibliography\n\\bibitem ";
80 if (! getOptions().empty())
81 os << '[' << getOptions() << ']';
83 << getContents() << "}\n";
87 // This is necessary here because this is written without begin_inset
88 // This should be changed!!! (Jug)
89 void InsetBibKey::read(Buffer const *, LyXLex & lex)
92 string const token = lex.getString();
95 lex.printError("InsetCommand: Parse error: `$$Token'");
98 if (prefixIs(getContents(), key_prefix)) {
99 int key = strToInt(getContents().substr(key_prefix.length()));
100 key_counter = max(key_counter, key);
104 string const InsetBibKey::getBibLabel() const
106 if (! getOptions().empty())
108 return tostr(counter);
111 string const InsetBibKey::getScreenLabel(Buffer const *) const
113 return getContents() + " [" + getBibLabel() + ']';
117 void InsetBibKey::edit(BufferView * bv, int, int, mouse_button::state)
119 bv->owner()->getDialogs().showBibitem(this);
123 void InsetBibKey::edit(BufferView * bv, bool)
125 edit(bv, 0, 0, mouse_button::none);
129 InsetBibtex::InsetBibtex(InsetCommandParams const & p, bool)
134 InsetBibtex::~InsetBibtex()
139 string const InsetBibtex::getScreenLabel(Buffer const *) const
141 return _("BibTeX Generated References");
145 int InsetBibtex::latex(Buffer const * buffer, ostream & os,
146 bool /*fragile*/, bool/*fs*/) const
148 // changing the sequence of the commands
149 // 1. \bibliographystyle{style}
150 // 2. \addcontentsline{...} - if option bibtotoc set
151 // 3. \bibliography{database}
153 string db_in = getContents();
154 db_in = split(db_in, adb, ',');
157 string style = getOptions(); // maybe empty! and with bibtotoc
159 if (prefixIs(style, "bibtotoc")) {
160 bibtotoc = "bibtotoc";
161 if (contains(style, ',')) {
162 style = split(style, bibtotoc, ',');
166 if (!buffer->niceFile
167 && IsFileReadable(MakeAbsPath(style, buffer->filePath()) + ".bst")) {
168 style = MakeAbsPath(style, buffer->filePath());
171 if (!style.empty()) { // we want no \biblio...{}
172 os << "\\bibliographystyle{" << style << "}\n";
176 if (!bibtotoc.empty()) {
177 // maybe a problem when a textclass has no "art" as
178 // part of its name, because it's than book.
179 // For the "official" lyx-layouts it's no problem to support
181 if (!contains(buffer->params.getLyXTextClass().name(),
183 if (buffer->params.sides == LyXTextClass::OneSide) {
188 os << "\\cleardoublepage";
192 os << "\\addcontentsline{toc}{chapter}{\\bibname}";
196 os << "\\addcontentsline{toc}{section}{\\refname}";
201 // If we generate in a temp dir, we might need to give an
202 // absolute path there. This is a bit complicated since we can
203 // have a comma-separated list of bibliographies
205 while (!adb.empty()) {
206 if (!buffer->niceFile &&
207 IsFileReadable(MakeAbsPath(adb, buffer->filePath())+".bib"))
208 adb = os::external_path(MakeAbsPath(adb, buffer->filePath()));
211 db_in= split(db_in, adb,',');
213 db_out = rtrim(db_out, ",");
214 os << "\\bibliography{" << db_out << "}\n";
219 vector<string> const InsetBibtex::getFiles(Buffer const & buffer) const
221 // Doesn't appear to be used (Angus, 31 July 2001)
222 Path p(buffer.filePath());
227 string bibfiles = getContents();
228 bibfiles = split(bibfiles, tmp, ',');
229 while (!tmp.empty()) {
230 string file = findtexfile(ChangeExtension(tmp, "bib"), "bib");
231 lyxerr[Debug::LATEX] << "Bibfile: " << file << endl;
233 // If we didn't find a matching file name just fail silently
237 // Get next file name
238 bibfiles = split(bibfiles, tmp, ',');
244 // This method returns a comma separated list of Bibtex entries
245 vector<pair<string, string> > const InsetBibtex::getKeys(Buffer const * buffer) const
247 vector<pair<string,string> > keys;
250 vector<string> const files = getFiles(*buffer);
251 for (vector<string>::const_iterator it = files.begin();
252 it != files.end(); ++ it) {
253 // This is a _very_ simple parser for Bibtex database
254 // files. All it does is to look for lines starting
255 // in @ and not being @preamble and @string entries.
256 // It does NOT do any syntax checking!
257 ifstream ifs(it->c_str());
259 while (getline(ifs, linebuf0)) {
260 string linebuf = trim(linebuf0);
261 if (linebuf.empty()) continue;
262 if (prefixIs(linebuf, "@")) {
263 linebuf = subst(linebuf, '{', '(');
265 linebuf = split(linebuf, tmp, '(');
266 tmp = ascii_lowercase(tmp);
267 if (!prefixIs(tmp, "@string")
268 && !prefixIs(tmp, "@preamble")) {
269 linebuf = split(linebuf, tmp, ',');
270 tmp = ltrim(tmp, " \t");
272 keys.push_back(pair<string,string>(tmp,string()));
275 } else if (!keys.empty()) {
276 keys.back().second += linebuf + "\n";
284 void InsetBibtex::edit(BufferView * bv, int, int, mouse_button::state)
286 bv->owner()->getDialogs().showBibtex(this);
290 void InsetBibtex::edit(BufferView * bv, bool)
292 edit(bv, 0, 0, mouse_button::none);
296 bool InsetBibtex::addDatabase(string const & db)
298 string contents(getContents());
299 if (!contains(contents, db)) {
300 if (!contents.empty())
302 setContents(contents + db);
309 bool InsetBibtex::delDatabase(string const & db)
311 if (contains(getContents(), db)) {
313 int const n = tokenPos(getContents(), ',', bd);
315 // Weird code, would someone care to explain this?(Lgb)
318 setContents(subst(getContents(), tmp, ", "));
320 setContents(split(getContents(), bd, ','));
328 // ale070405 This function maybe shouldn't be here. We'll fix this at 0.13.
329 int bibitemMaxWidth(BufferView * bv, LyXFont const & font)
332 // Ha, now we are mainly at 1.2.0 and it is still here (Jug)
333 // Does look like a hack? It is! (but will change at 0.13)
334 ParagraphList::iterator it = bv->buffer()->paragraphs.begin();
335 ParagraphList::iterator end = bv->buffer()->paragraphs.end();
336 for (; it != end; ++it) {
338 int const wx = it->bibkey()->width(bv, font);
348 string const bibitemWidest(Buffer const * buffer)
351 // Does look like a hack? It is! (but will change at 0.13)
353 InsetBibKey * bkey = 0;
356 ParagraphList::iterator it = buffer->paragraphs.begin();
357 ParagraphList::iterator end = buffer->paragraphs.end();
358 for (; it != end; ++it) {
361 font_metrics::width(it->bibkey()->getBibLabel(),
370 if (bkey && !bkey->getBibLabel().empty())
371 return bkey->getBibLabel();