On Tue, Aug 18, 2020 at 10:21:23PM -0400, Richard Kimberly Heck wrote: > This does work with JabRef.
Thanks for testing. > Space after the "&". Some other places for this, too, and spaces around > commas. Fixed. > > + if (is_bibtex_) { > > + doi = operator[]("doi"); > > + if (!doi.empty() && !prefixIs(doi,from_ascii("http"))) > > + doi = "https://doi.org/" + doi; > > + url = operator[]("url"); > > I'm confused about what this is for. Comment? Not sure what line you refer to. As a whole we try to digest DOI specifier and prefix it by DOI domain if not already prefixed with URL. (Not sure whether its guaranteed that the entry never contains http part). > > + file = operator[]("file"); > > + > > + // Jabref case, field has a format: > > + // Description:Location:Filetype;Description:Location:Filetype... > > + // We will grab only first pdf > > Since the second might be an absolute path, it might be worth a loop. > Shouldn't be too hard. Just split on ; first and loop over the results. > (Same with kbibtex.) Makes sense. Do you prefer me to commit it now and continue working on updates within master or wait for finished patch? (I won't have time to work on this in next days). > > + if (!file.empty()) { > > + docstring ret, filedest, tmp; > > + ret = split(file, tmp, ':'); > > + tmp = split(ret, filedest, ':'); > > + //TODO howto deal with relative directories? > > We'd have (i) to know the name of the bibfile from which this reference > came and then (ii) be able to find its absolute path. I'm not sure it's > worth it, though somewhere we should document that this only works with > absolute paths. Yeah, I'll plan to add some documentation + template lyxpaperview script once the patch is stable. > > + FileName f(to_utf8(filedest)); > > + if (f.exists()) > > + file = "file:///" + filedest; > > + } > > + > > + // kbibtex case, format: > > + // file1.pdf;file2.pdf > > + // We will grab only first pdf > > + docstring kfile; > > + if (file.empty()) > > + kfile = operator[]("localfile"); > > + if (!kfile.empty()) { > > + docstring filedest, tmp; > > + tmp = split(kfile, filedest, ';'); > > + //TODO howto deal with relative directories? > > + FileName f(to_utf8(filedest)); > > + if (f.exists()) > > + file = "file:///" + filedest; > > + } > > It occurred to me (and maybe I'll do this) that we could possibly have a > configuration file for this that would look something like: > > localfile : ^([^;]+?) > file ^:([^:]+?) > > I.e., for each possible field, we have a regex telling how to get the > path we want. That could simplify the code, too. Please feel free to adjust the code for files any way you want once committed. I coded the whole biblatex + jabref/kbibtex part without testing because I don't use these tools. It was nice surprise that it actually worked for both Juergen and you ;) I suspect that there will be bunch of other tools and other people will fill in those gaps later. Pavel
diff --git a/lib/ui/stdcontext.inc b/lib/ui/stdcontext.inc index c2beb316f4..691596f865 100644 --- a/lib/ui/stdcontext.inc +++ b/lib/ui/stdcontext.inc @@ -128,6 +128,7 @@ Menuset CiteStyles Separator Item "Settings...|S" "inset-settings" + Item "Open Citation Content|O" "inset-edit" End diff --git a/src/BiblioInfo.cpp b/src/BiblioInfo.cpp index e37d56389a..2600f26d8a 100644 --- a/src/BiblioInfo.cpp +++ b/src/BiblioInfo.cpp @@ -651,6 +651,72 @@ docstring const BibTeXInfo::getYear() const } +void BibTeXInfo::getLocators(docstring & doi, docstring & url, docstring & file) const +{ + if (is_bibtex_) { + doi = operator[]("doi"); + if (!doi.empty() && !prefixIs(doi,from_ascii("http"))) + doi = "https://doi.org/" + doi; + url = operator[]("url"); + file = operator[]("file"); + + // Jabref case, field has a format: + // Description:Location:Filetype;Description:Location:Filetype... + // We will grab only first pdf + if (!file.empty()) { + docstring ret, filedest, tmp; + ret = split(file, tmp, ':'); + tmp = split(ret, filedest, ':'); + //TODO howto deal with relative directories? + FileName f(to_utf8(filedest)); + if (f.exists()) + file = "file:///" + filedest; + } + + // kbibtex case, format: + // file1.pdf;file2.pdf + // We will grab only first pdf + docstring kfile; + if (file.empty()) + kfile = operator[]("localfile"); + if (!kfile.empty()) { + docstring filedest, tmp; + tmp = split(kfile, filedest, ';'); + //TODO howto deal with relative directories? + FileName f(to_utf8(filedest)); + if (f.exists()) + file = "file:///" + filedest; + } + + if (!url.empty()) + return; + + // try biblatex specific fields, see its manual + // 3.13.7 "Electronic Publishing Informationl" + docstring eprinttype = operator[]("eprinttype"); + docstring eprint = operator[]("eprint"); + if (eprint.empty()) + return; + + if (eprinttype == "arxiv") + url = "https://arxiv.org/abs/" + eprint; + if (eprinttype == "jstor") + url = "https://www.jstor.org/stable/" + eprint; + if (eprinttype == "pubmed") + url = "http://www.ncbi.nlm.nih.gov/pubmed/" + eprint; + if (eprinttype == "hdl") + url = "https://hdl.handle.net/" + eprint; + if (eprinttype == "googlebooks") + url = "http://books.google.com/books?id=" + eprint; + + return; + } + + // Here can be handled the bibliography environment. All one could do + // here is let LyX scan the entry for URL or HRef insets. +} + + namespace { docstring parseOptions(docstring const & format, string & optkey, @@ -1269,6 +1335,15 @@ docstring const BiblioInfo::getCiteNumber(docstring const & key) const return data.citeNumber(); } +void BiblioInfo::getLocators(docstring const & key, docstring & doi, docstring & url, docstring & file) const +{ + BiblioInfo::const_iterator it = find(key); + if (it == end()) + return; + BibTeXInfo const & data = it->second; + data.getLocators(doi,url,file); +} + docstring const BiblioInfo::getYear(docstring const & key, bool use_modifier) const { diff --git a/src/BiblioInfo.h b/src/BiblioInfo.h index 4509101fd3..00cdfcfd1d 100644 --- a/src/BiblioInfo.h +++ b/src/BiblioInfo.h @@ -70,6 +70,8 @@ public: bool const allnames = false, bool const beginning = true) const; /// docstring const getYear() const; + /// + void getLocators(docstring & doi, docstring & url, docstring & file) const; /// \return formatted BibTeX data suitable for framing. /// \param vector of pointers to crossref/xdata information docstring const & getInfo(BibTeXInfoList const & xrefs, @@ -213,6 +215,9 @@ public: /// language. docstring const getYear(docstring const & key, Buffer const & buf, bool use_modifier = false) const; + /// get either local pdf or web location of the citation referenced by key. + /// DOI/file are prefixed so they form proper URL for generic qt handler + void getLocators(docstring const & key, docstring & doi, docstring & url, docstring & file) const; /// docstring const getCiteNumber(docstring const & key) const; /// \return formatted BibTeX data associated with a given key. diff --git a/src/FuncCode.h b/src/FuncCode.h index 585d1e1580..391faf71ce 100644 --- a/src/FuncCode.h +++ b/src/FuncCode.h @@ -490,6 +490,7 @@ enum FuncCode LFUN_MASTER_BUFFER_FORALL, // spitz 20191231 LFUN_IF_RELATIVES, // spitz 20200102 LFUN_WINDOW_RAISE, // forenr, 20202104 + LFUN_CITATION_OPEN, // sanda, 20200815 LFUN_LASTACTION // end of the table }; diff --git a/src/LyXAction.cpp b/src/LyXAction.cpp index 3de816a68f..3e1e023550 100644 --- a/src/LyXAction.cpp +++ b/src/LyXAction.cpp @@ -1239,6 +1239,18 @@ void LyXAction::init() * \endvar */ { LFUN_CITATION_INSERT, "citation-insert", Noop, Edit }, +/*! + * \var lyx::FuncCode lyx::LFUN_CITATION_OPEN + * \li Action: Opens the corresponding pdf/url for a given citation inset. + * \li Syntax: citation-open [EXTERNAL] TARGET + * \li Params: <TARGET>: URL (https:,file:) of the document. \n + <EXTERNAL>: Use external executable script for finding target \n + and launching viewer. In this case TARGET consists of author and year \n + and will be passed as an input argument to the script. + * \li Origin: Sanda, 16 Aug 2020 + * \endvar + */ + { LFUN_CITATION_OPEN, "citation-open", ReadOnly | NoUpdate | Argument, Edit }, /*! * \var lyx::FuncCode lyx::LFUN_CLIPBOARD_PASTE diff --git a/src/frontends/qt/GuiView.cpp b/src/frontends/qt/GuiView.cpp index 1b9f0ef27c..cdd99f137a 100644 --- a/src/frontends/qt/GuiView.cpp +++ b/src/frontends/qt/GuiView.cpp @@ -2371,6 +2371,10 @@ bool GuiView::getStatus(FuncRequest const & cmd, FuncStatus & flag) flag.setOnOff(lyxrc.spellcheck_continuously); break; + case LFUN_CITATION_OPEN: + enable = true; + break; + default: return false; } @@ -4620,6 +4624,10 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr) dr.screenUpdate(Update::Force); break; + case LFUN_CITATION_OPEN: { + frontend::showTarget(argument); + } + default: // The LFUN must be for one of BufferView, Buffer or Cursor; // let's try that: diff --git a/src/frontends/qt/qt_helpers.cpp b/src/frontends/qt/qt_helpers.cpp index 9d44c3f9c1..0ef077590b 100644 --- a/src/frontends/qt/qt_helpers.cpp +++ b/src/frontends/qt/qt_helpers.cpp @@ -21,7 +21,10 @@ #include "BufferParams.h" #include "FloatList.h" +#include "FuncRequest.h" #include "Language.h" +#include "LyX.h" +#include "LyXAction.h" #include "TextClass.h" #include "support/convert.h" @@ -293,6 +296,18 @@ void showDirectory(FileName const & directory) if (!QDesktopServices::openUrl(qurl)) LYXERR0("Unable to open QUrl even though dir exists!"); } + +void showTarget(string const & target){ + LYXERR(Debug::INSETS, "Showtarget:" << target << "\n"); + if (prefixIs(target,"EXTERNAL ")) { + string tmp,tar; + tar = split(target, tmp, ' '); + FuncRequest cmd = FuncRequest(LFUN_VC_COMMAND,"U . \"lyxpaperview " + tar + "\""); + lyx::dispatch(cmd); + return; + } + QDesktopServices::openUrl(QUrl(toqstr(target), QUrl::TolerantMode)); +} } // namespace frontend QString const qt_(char const * str, const char *) diff --git a/src/frontends/qt/qt_helpers.h b/src/frontends/qt/qt_helpers.h index 970a02707f..6c7c366f3d 100644 --- a/src/frontends/qt/qt_helpers.h +++ b/src/frontends/qt/qt_helpers.h @@ -101,6 +101,9 @@ void setSectionResizeMode(QHeaderView * view, QHeaderView::ResizeMode mode); /// Shows a directory in OSs file browser void showDirectory(support::FileName const & directory); +/// handle request for showing citation content - shows pdf or +/// web page in target; external script can be used for pdf view +void showTarget(std::string const & target); } // namespace frontend diff --git a/src/insets/InsetCitation.cpp b/src/insets/InsetCitation.cpp index 14a05a097a..66db11a593 100644 --- a/src/insets/InsetCitation.cpp +++ b/src/insets/InsetCitation.cpp @@ -23,6 +23,7 @@ #include "FuncRequest.h" #include "FuncStatus.h" #include "LaTeXFeatures.h" +#include "LyX.h" #include "output_xhtml.h" #include "output_docbook.h" #include "ParIterator.h" @@ -133,6 +134,9 @@ CitationStyle InsetCitation::getCitationStyle(BufferParams const & bp, string co void InsetCitation::doDispatch(Cursor & cur, FuncRequest & cmd) { switch (cmd.action()) { + case LFUN_INSET_EDIT: + openCitation(); + break; case LFUN_INSET_MODIFY: { buffer().removeBiblioTempFiles(); cache.recalculate = true; @@ -165,6 +169,44 @@ void InsetCitation::doDispatch(Cursor & cur, FuncRequest & cmd) } +void InsetCitation::openCitation(){ + Buffer const & buf = *buffer_; + // Only after the buffer is loaded from file... + if (!buf.isFullyLoaded()) + return; + + BiblioInfo const & bi = buf.masterBibInfo(); + if (bi.empty()) + return; + + docstring const & key = getParam("key"); + if (key.empty()) + return; + + vector<docstring> keys = getVectorFromString(key); + docstring year, author, doi, url, file; + for (docstring const & kvar : keys) { + year = bi.getYear(kvar, buffer(), false); + author = bi.getAuthorOrEditorList(kvar, buffer()); + bi.getLocators(kvar, doi, url, file); + LYXERR(Debug::INSETS, "Locators: doi:" << doi << " url:" + << url << " file:" << file << " author:" << author << " year:" << year); + docstring locator; + if (!file.empty()) { + locator = file; + } else if (!doi.empty()) { + locator = doi; + } else if (!url.empty()) { + locator = url; + } else { + locator = "EXTERNAL " + year + " " + author; + } + FuncRequest cmd = FuncRequest(LFUN_CITATION_OPEN, locator); + lyx::dispatch(cmd); + } +} + + bool InsetCitation::getStatus(Cursor & cur, FuncRequest const & cmd, FuncStatus & status) const { @@ -203,6 +245,8 @@ bool InsetCitation::getStatus(Cursor & cur, FuncRequest const & cmd, } } return true; + case LFUN_INSET_EDIT: + return true; default: return InsetCommand::getStatus(cur, cmd, status); } diff --git a/src/insets/InsetCitation.h b/src/insets/InsetCitation.h index bc15e11a6f..29e4b1f67b 100644 --- a/src/insets/InsetCitation.h +++ b/src/insets/InsetCitation.h @@ -94,6 +94,8 @@ public: QualifiedList getQualifiedLists(docstring const & p) const; /// static bool last_literal; + /// + void openCitation(); private: /// tries to make a pretty label and makes a basic one if not
-- lyx-devel mailing list lyx-devel@lists.lyx.org http://lists.lyx.org/mailman/listinfo/lyx-devel