Improve CITATION_OPEN

* The lyxpaperview script now only provides the paths and let us do the opening
* We use our own viewers for local files rather than QDesktopServices

Plus several minor improvements and code cleanup
This commit is contained in:
Juergen Spitzmueller 2023-08-30 15:30:29 +02:00
parent 0912f7c356
commit 4dc9e0c4e6
4 changed files with 79 additions and 110 deletions

View File

@ -10,19 +10,10 @@
# Full author contact details are available in file CREDITS # Full author contact details are available in file CREDITS
# This script searches the home directory for a PDF or PS # This script searches the home directory for a PDF or PS
# file with a name containing year and author. If found, # file with a name containing specific keywords (year and author by default).
# it opens the file in a viewer. # If found, it returns the path(s), separated by \n.
import getopt, os, sys, subprocess import os, sys, subprocess
pdf_viewers = ('pdfview', 'kpdf', 'okular', 'qpdfview --unique',
'evince', 'xreader', 'kghostview', 'xpdf', 'SumatraPDF',
'acrobat', 'acroread', 'mupdf',
'gv', 'ghostview', 'AcroRd32', 'gsview64', 'gsview32')
ps_viewers = ("kghostview", "okular", "qpdfview --unique",
"evince", "xreader", "gv", "ghostview -swap",
"gsview64", "gsview32")
def message(message): def message(message):
sys.stderr.write("lyxpaperview: %s\n" % message) sys.stderr.write("lyxpaperview: %s\n" % message)
@ -32,7 +23,7 @@ def error(message):
exit(1) exit(1)
def usage(prog_name): def usage(prog_name):
msg = "Usage: %s [-v pdfviewer] [-w psviewer] titletoken-1 [titletoken-2] ... [titletoken-n]\n" \ msg = "Usage: %s titletoken-1 [titletoken-2] ... [titletoken-n]\n" \
" Each title token must occur in the filename (at an arbitrary position).\n" \ " Each title token must occur in the filename (at an arbitrary position).\n" \
" You might use quotes to enter multi-word tokens" " You might use quotes to enter multi-word tokens"
return msg % prog_name return msg % prog_name
@ -66,13 +57,6 @@ def find_exe(candidates):
return None return None
def find_exe_or_terminate(candidates):
exe = find_exe(candidates)
if exe == None:
error("Unable to find executable from '%s'" % " ".join(candidates))
return exe
def find(args, path): def find(args, path):
if os.name != 'nt': if os.name != 'nt':
# use locate if possible (faster) # use locate if possible (faster)
@ -84,10 +68,9 @@ def find(args, path):
# have this already # have this already
continue continue
px = subprocess.Popen(['grep', '-i', arg], stdin=px.stdout, stdout=subprocess.PIPE) px = subprocess.Popen(['grep', '-i', arg], stdin=px.stdout, stdout=subprocess.PIPE)
p4 = subprocess.Popen(['head', '-n 1'], stdin=px.stdout, stdout=subprocess.PIPE)
p1.stdout.close() p1.stdout.close()
output = p4.communicate() output = px.communicate()
return output[0].decode("utf8")[:-1]# strip trailing '\n' return output[0].decode("utf8").strip('\n')
# FIXME add something for windows as well? # FIXME add something for windows as well?
# Maybe dir /s /b %WINDIR%\*author* | findstr .*year.*\."ps pdf" # Maybe dir /s /b %WINDIR%\*author* | findstr .*year.*\."ps pdf"
@ -107,44 +90,14 @@ def find(args, path):
def main(argv): def main(argv):
progname = argv[0] progname = argv[0]
opts, args = getopt.getopt(sys.argv[1:], "v:w:") args = sys.argv[1:]
pdfviewer = ""
psviewer = ""
for o, v in opts:
if o == "-v":
pdfviewer = v
if o == "-w":
psviewer = v
if len(args) < 1: if len(args) < 1:
error(usage(progname)) error(usage(progname))
result = find(args, path = os.environ["HOME"]) result = find(args, path = os.environ["HOME"])
if result == "":
message("no document found!")
exit(2)
else:
message("found document %s" % result)
viewer = ""
if result.lower().endswith('.ps'):
if psviewer == "":
viewer = find_exe_or_terminate(ps_viewers)
else:
viewer = psviewer
else:
if pdfviewer == "":
viewer = find_exe_or_terminate(pdf_viewers)
else:
viewer = pdfviewer
cmdline = viewer.split(" -", 1)
if len(cmdline) == 1:
subprocess.Popen([viewer, result], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
elif len(cmdline) == 2:
subprocess.Popen([cmdline[0], "-" + cmdline[1] , result], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
print(result)
exit(0) exit(0)
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -5072,12 +5072,7 @@ void GuiView::dispatch(FuncRequest const & cmd, DispatchResult & dr)
case LFUN_CITATION_OPEN: { case LFUN_CITATION_OPEN: {
LASSERT(doc_buffer, break); LASSERT(doc_buffer, break);
string pdfv, psv; frontend::showTarget(argument, *doc_buffer);
if (theFormats().getFormat("pdf"))
pdfv = theFormats().getFormat("pdf")->viewer();
if (theFormats().getFormat("ps"))
psv = theFormats().getFormat("ps")->viewer();
frontend::showTarget(argument, doc_buffer->absFileName(), pdfv, psv);
break; break;
} }

View File

@ -14,6 +14,7 @@
#include "qt_helpers.h" #include "qt_helpers.h"
#include "Format.h"
#include "LengthCombo.h" #include "LengthCombo.h"
#include "LyXRC.h" #include "LyXRC.h"
@ -32,6 +33,7 @@
#include <QComboBox> #include <QComboBox>
#include <QDesktopServices> #include <QDesktopServices>
#include <QDir> #include <QDir>
#include <QInputDialog>
#include <QLineEdit> #include <QLineEdit>
#include <QMessageBox> #include <QMessageBox>
#include <QLocale> #include <QLocale>
@ -295,30 +297,61 @@ void showDirectory(FileName const & directory)
qstring_to_ucs4(qurl.toString()))); qstring_to_ucs4(qurl.toString())));
} }
void showTarget(string const & target, string const & docpath, void showTarget(string const & target_in, Buffer const & buf)
string const & pdfv, string const & psv)
{ {
LYXERR(Debug::INSETS, "Showtarget:" << target << "\n"); LYXERR(Debug::INSETS, "Showtarget:" << target_in << "\n");
string target = target_in;
string const & docpath = buf.absFileName();
bool const is_external = prefixIs(target, "EXTERNAL ");
if (is_external) {
if (!lyxrc.citation_search)
return;
string tmp, tar;
tar = split(target, tmp, ' ');
string const scriptcmd = subst(lyxrc.citation_search_view, "$${python}", os::python());
string const command = scriptcmd + " " + tar;
cmd_ret const ret = runCommand(commandPrep(command));
if (!ret.valid) {
// Script failed
frontend::Alert::error(_("Could not open file"),
_("The lyxpaperview script failed."));
return;
}
// lyxpaperview returns a \n-separated list of paths
vector<string> targets = getVectorFromString(rtrim(ret.result, "\n"), "\n");
if (targets.empty()) {
frontend::Alert::error(_("Could not open file"),
bformat(_("No file was found using the pattern `%1$s'."),
from_utf8(tar)));
return;
}
if (targets.size() > 1) {
QStringList files;
for (auto const & t : targets)
files << toqstr(t);
bool ok;
QString file = QInputDialog::getItem(nullptr, qt_("Multiple files found!"),
qt_("Select the file that should be opened:"),
files, 0, false, &ok);
if (!ok || file.isEmpty())
return;
target = fromqstr(file);
} else
target = targets.front();
}
// security measure: ask user before opening if document is not marked trusted. // security measure: ask user before opening if document is not marked trusted.
QSettings settings; QSettings settings;
if (!settings.value("trusted documents/" + toqstr(docpath), false).toBool()) { if (!settings.value("trusted documents/" + toqstr(docpath), false).toBool()) {
QCheckBox * dontShowAgainCB = new QCheckBox(); QCheckBox * dontShowAgainCB = new QCheckBox();
dontShowAgainCB->setText(qt_("&Trust this document and do not ask me again!")); dontShowAgainCB->setText(qt_("&Trust this document and do not ask me again!"));
dontShowAgainCB->setToolTip(qt_("If you check this, LyX will open all targets without asking for the given document in the future.")); dontShowAgainCB->setToolTip(qt_("If you check this, LyX will open all targets without asking for the given document in the future."));
docstring const warn = docstring const warn = bformat(_("LyX wants to open the following target in an external application:\n"
prefixIs(target, "EXTERNAL ") ? "%1$s\n"
bformat(_("LyX will search your directory for files with the following keywords in their name " "Be aware that this might entail security infringements!\n"
"and then open it in an external application, if a file is found:\n" "Only do this if you trust origin of the document and the target of the link!\n"
"'%1$s'\n" "How do you want to proceed?"), from_utf8(target));
"Be aware that this might entail security infringements!\n"
"Only do this if you trust origin of the document and the keywords used!\n"
"How do you want to proceed?"), from_utf8(target).substr(9, docstring::npos))
: bformat(_("LyX wants to open the following link in an external application:\n"
"%1$s\n"
"Be aware that this might entail security infringements!\n"
"Only do this if you trust origin of the document and the target of the link!\n"
"How do you want to proceed?"), from_utf8(target));
QMessageBox box(QMessageBox::Warning, qt_("Open external target?"), toqstr(warn), QMessageBox box(QMessageBox::Warning, qt_("Open external target?"), toqstr(warn),
QMessageBox::NoButton, qApp->focusWidget()); QMessageBox::NoButton, qApp->focusWidget());
QPushButton * openButton = box.addButton(qt_("&Open Target"), QMessageBox::ActionRole); QPushButton * openButton = box.addButton(qt_("&Open Target"), QMessageBox::ActionRole);
@ -333,32 +366,22 @@ void showTarget(string const & target, string const & docpath,
+ toqstr(docpath), true); + toqstr(docpath), true);
} }
if (prefixIs(target, "EXTERNAL ")) { bool success = false;
if (!lyxrc.citation_search) QUrl url = is_external
return; ? QUrl::fromLocalFile(toqstr(target))
string tmp, tar, opts; : QUrl(toqstr(target), QUrl::TolerantMode);
tar = split(target, tmp, ' '); if (url.isLocalFile()) {
if (!pdfv.empty()) // For local files, we use our own viewers
opts = " -v \"" + pdfv + "\""; // (QDesktopServices employs xdg-open which
if (!psv.empty()) // does not yet work everywhere)
opts += " -w \"" + psv + "\""; FileName fn(fromqstr(url.path()));
if (!opts.empty()) string const format = theFormats().getFormatFromFile(fn);
opts += " "; success = theFormats().view(buf, fn, format);
Systemcall one; } else
string const viewer = subst(lyxrc.citation_search_view, "$${python}", os::python()); // For external files, we rely on QDesktopServices
string const command = viewer + " " + opts + tar; success = QDesktopServices::openUrl(url);
int const result = one.startscript(Systemcall::Wait, command);
if (result == 1) if (!success)
// Script failed
frontend::Alert::error(_("Could not open file"),
_("The lyxpaperview script failed."));
else if (result == 2)
frontend::Alert::error(_("Could not open file"),
bformat(_("No file was found using the pattern `%1$s'."),
from_utf8(tar)));
return;
}
if (!QDesktopServices::openUrl(QUrl(toqstr(target), QUrl::TolerantMode)))
frontend::Alert::error(_("Could not open file"), frontend::Alert::error(_("Could not open file"),
bformat(_("The target `%1$s' could not be resolved."), bformat(_("The target `%1$s' could not be resolved."),
from_utf8(target))); from_utf8(target)));

View File

@ -13,6 +13,7 @@
#ifndef QTHELPERS_H #ifndef QTHELPERS_H
#define QTHELPERS_H #define QTHELPERS_H
#include "Buffer.h"
#include "ColorSet.h" #include "ColorSet.h"
#include "support/Length.h" #include "support/Length.h"
#include "support/qstring_helpers.h" #include "support/qstring_helpers.h"
@ -93,12 +94,9 @@ void setMessageColour(std::list<QWidget *> highlighted,
void showDirectory(support::FileName const & directory); void showDirectory(support::FileName const & directory);
/// handle request for showing citation content - shows pdf/ps or /// handle request for showing citation content - shows pdf/ps or
/// web page in target; external script can be used for pdf/ps view /// web page in target; external script can be used for pdf/ps view
/// \p docpath holds the document path, /// \p docpath holds the document path
/// \p pdfv takes a pad viewer, \p psv a ps viewer
void showTarget(std::string const & target, void showTarget(std::string const & target,
std::string const & docpath, Buffer const & buf);
std::string const & pdfv,
std::string const & psv);
} // namespace frontend } // namespace frontend