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

Reply via email to