]> git.lyx.org Git - lyx.git/commitdiff
Allow LyX to find pdfs and urls of citation references and follow them from context...
authorPavel Sanda <sanda@lyx.org>
Thu, 20 Aug 2020 06:33:40 +0000 (08:33 +0200)
committerPavel Sanda <sanda@lyx.org>
Thu, 20 Aug 2020 07:12:54 +0000 (09:12 +0200)
Currently tested:
- url & doi fields for bibtex.
- all documented eprinttypes of biblatex
- absolute paths of first entry of 'file' field for jabref and kbibtex
- external script searching for author + year pdf

Additional polishing will follow.

https://www.mail-archive.com/lyx-devel@lists.lyx.org/msg212505.html

lib/ui/stdcontext.inc
src/BiblioInfo.cpp
src/BiblioInfo.h
src/FuncCode.h
src/LyXAction.cpp
src/frontends/qt/GuiView.cpp
src/frontends/qt/qt_helpers.cpp
src/frontends/qt/qt_helpers.h
src/insets/InsetCitation.cpp
src/insets/InsetCitation.h

index c2beb316f4bf715c6581b8ec5d675f3eac77c107..691596f86579bfc2f5e50b3056cde101c6f70b1d 100644 (file)
@@ -128,6 +128,7 @@ Menuset
                CiteStyles
                Separator
                Item "Settings...|S" "inset-settings"
+               Item "Open Citation Content|O" "inset-edit"
        End
 
 
index e37d56389a7efda7cbd3e148881314753a293e96..ab073ae600a85db78efcead957f67a7a6ba01bd9 100644 (file)
@@ -651,6 +651,75 @@ docstring const BibTeXInfo::getYear() const
 }
 
 
+void BibTeXInfo::getLocators(docstring & doi, docstring & url, docstring & file) const
+{
+       if (is_bibtex_) {
+               // get "doi" entry from citation record
+               doi = operator[]("doi");
+               if (!doi.empty() && !prefixIs(doi,from_ascii("http")))
+                       doi = "https://doi.org/" + doi;
+               // get "url" entry from citation record
+               url = operator[]("url");
+               // get "file" entry from citation record
+               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 +1338,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
 {
index 4509101fd379486c7b5ed200b3f23e0088b53a02..00cdfcfd1d1676fc8ab6cf59ec779d4e94acbe01 100644 (file)
@@ -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.
index 585d1e15809de8aec6e9193c5195e24a66ced47f..391faf71ce621c6d359eff8ee866afdbbd9d04f7 100644 (file)
@@ -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
 };
 
index 3de816a68f8de89de1f3acb724757e55d28fdd48..3e1e023550882fbfc8aa1c1d1b6a4f594439f13c 100644 (file)
@@ -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
index 1b9f0ef27c1d2617250f465321d7b32a4afb5e42..cdd99f137ac5950d1de299179e29c611ad22ad5d 100644 (file)
@@ -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:
index 9d44c3f9c1ee33527aefbfc70ac6f99668b422b4..0ef077590bf27feefb6acc1245aaa1a8cb00a9fe 100644 (file)
 
 #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 *)
index 970a02707f41119eb0d7bed6c226fbe27c062fe1..6c7c366f3d9d46d9813d36e79dfb2debcda63ca4 100644 (file)
@@ -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
 
index 14a05a097a4d2385ebc81bf0cf7c7e493ede9f88..66db11a593b656debe0570076d0dd3f412f60658 100644 (file)
@@ -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);
        }
index bc15e11a6f28609e8acec5db1fcb1f694b159c0c..29e4b1f67b88522f2b761d9bda11e918c3489f7e 100644 (file)
@@ -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