GUI: add "Open With" entry in reslist/table popups to let the user choose the app
This commit is contained in:
parent
b0b372e350
commit
c897a09cd3
@ -301,6 +301,8 @@ void RclMain::init()
|
||||
this, SLOT(startPreview(Rcl::Doc)));
|
||||
connect(restable, SIGNAL(editRequested(Rcl::Doc)),
|
||||
this, SLOT(startNativeViewer(Rcl::Doc)));
|
||||
connect(restable, SIGNAL(openWithRequested(Rcl::Doc, string)),
|
||||
this, SLOT(openWith(Rcl::Doc, string)));
|
||||
connect(restable, SIGNAL(docSaveToFileClicked(Rcl::Doc)),
|
||||
this, SLOT(saveDocToFile(Rcl::Doc)));
|
||||
connect(restable, SIGNAL(showSnippets(Rcl::Doc)),
|
||||
@ -341,6 +343,8 @@ void RclMain::init()
|
||||
this, SLOT(saveDocToFile(Rcl::Doc)));
|
||||
connect(reslist, SIGNAL(editRequested(Rcl::Doc)),
|
||||
this, SLOT(startNativeViewer(Rcl::Doc)));
|
||||
connect(reslist, SIGNAL(openWithRequested(Rcl::Doc, string)),
|
||||
this, SLOT(openWith(Rcl::Doc, string)));
|
||||
connect(reslist, SIGNAL(docPreviewClicked(int, Rcl::Doc, int)),
|
||||
this, SLOT(startPreview(int, Rcl::Doc, int)));
|
||||
connect(reslist, SIGNAL(previewRequested(Rcl::Doc)),
|
||||
@ -1641,6 +1645,39 @@ void RclMain::showSubDocs(Rcl::Doc doc)
|
||||
res->show();
|
||||
}
|
||||
|
||||
void RclMain::openWith(Rcl::Doc doc, string cmdspec)
|
||||
{
|
||||
LOGDEB(("RclMain::openWith: %s\n", cmdspec.c_str()));
|
||||
|
||||
// Split the command line
|
||||
vector<string> lcmd;
|
||||
if (!stringToStrings(cmdspec, lcmd)) {
|
||||
QMessageBox::warning(0, "Recoll",
|
||||
tr("Bad desktop app spec for %1: [%2]\n"
|
||||
"Please check the desktop file")
|
||||
.arg(QString::fromAscii(doc.mimetype.c_str()))
|
||||
.arg(QString::fromLocal8Bit(cmdspec.c_str())));
|
||||
return;
|
||||
}
|
||||
|
||||
// Look for the command to execute in the exec path and the filters
|
||||
// directory
|
||||
string execname = lcmd.front();
|
||||
lcmd.erase(lcmd.begin());
|
||||
string url = doc.url;
|
||||
string fn = fileurltolocalpath(doc.url);
|
||||
|
||||
// Try to keep the letters used more or less consistent with the reslist
|
||||
// paragraph format.
|
||||
map<string, string> subs;
|
||||
subs["F"] = fn;
|
||||
subs["f"] = fn;
|
||||
subs["U"] = url;
|
||||
subs["u"] = url;
|
||||
|
||||
execViewer(subs, false, execname, lcmd, cmdspec, doc);
|
||||
}
|
||||
|
||||
void RclMain::startNativeViewer(Rcl::Doc doc, int pagenum, QString term)
|
||||
{
|
||||
string apptag;
|
||||
@ -1705,7 +1742,6 @@ void RclMain::startNativeViewer(Rcl::Doc doc, int pagenum, QString term)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Command not found: start the user dialog to help find another one:
|
||||
if (execpath.empty()) {
|
||||
QString mt = QString::fromAscii(doc.mimetype.c_str());
|
||||
@ -1731,7 +1767,6 @@ void RclMain::startNativeViewer(Rcl::Doc doc, int pagenum, QString term)
|
||||
// Get rid of the command name. lcmd is now argv[1...n]
|
||||
lcmd.erase(lcmd.begin());
|
||||
|
||||
|
||||
// Process the command arguments to determine if we need to create
|
||||
// a temporary file.
|
||||
|
||||
@ -1868,12 +1903,21 @@ void RclMain::startNativeViewer(Rcl::Doc doc, int pagenum, QString term)
|
||||
it != doc.meta.end(); it++) {
|
||||
subs[it->first] = it->second;
|
||||
}
|
||||
execViewer(subs, istempfile, execpath, lcmd, cmd, doc);
|
||||
}
|
||||
|
||||
void RclMain::execViewer(const map<string, string>& subs, bool istempfile,
|
||||
const string& execpath,
|
||||
const vector<string>& _lcmd, const string& cmd,
|
||||
Rcl::Doc doc)
|
||||
{
|
||||
string ncmd;
|
||||
for (vector<string>::iterator it = lcmd.begin();
|
||||
it != lcmd.end(); it++) {
|
||||
vector<string> lcmd;
|
||||
for (vector<string>::const_iterator it = _lcmd.begin();
|
||||
it != _lcmd.end(); it++) {
|
||||
pcSubst(*it, ncmd, subs);
|
||||
LOGDEB(("%s->%s\n", it->c_str(), ncmd.c_str()));
|
||||
*it = ncmd;
|
||||
lcmd.push_back(ncmd);
|
||||
}
|
||||
|
||||
// Also substitute inside the unsplitted command line and display
|
||||
|
||||
@ -133,6 +133,7 @@ public slots:
|
||||
virtual void startPreview(Rcl::Doc);
|
||||
virtual void startNativeViewer(Rcl::Doc, int pagenum = -1,
|
||||
QString term=QString());
|
||||
virtual void openWith(Rcl::Doc, string);
|
||||
virtual void saveDocToFile(Rcl::Doc);
|
||||
virtual void previewNextInTab(Preview *, int sid, int docnum);
|
||||
virtual void previewPrevInTab(Preview *, int sid, int docnum);
|
||||
@ -197,6 +198,9 @@ private:
|
||||
virtual void init();
|
||||
virtual void previewPrevOrNextInTab(Preview *, int sid, int docnum,
|
||||
bool next);
|
||||
virtual void execViewer(const map<string, string>& subs, bool istempfile,
|
||||
const string& execpath, const vector<string>& lcmd,
|
||||
const string& cmd, Rcl::Doc doc);
|
||||
virtual void setStemLang(const QString& lang);
|
||||
virtual void onSortCtlChanged();
|
||||
virtual void showIndexConfig(bool modal);
|
||||
|
||||
@ -1027,6 +1027,15 @@ void ResList::menuEdit()
|
||||
if (getDoc(m_popDoc, doc))
|
||||
emit editRequested(doc);
|
||||
}
|
||||
void ResList::menuOpenWith(QAction *act)
|
||||
{
|
||||
if (act == 0)
|
||||
return;
|
||||
string cmd = qs2utf8s(act->data().toString());
|
||||
Rcl::Doc doc;
|
||||
if (getDoc(m_popDoc, doc))
|
||||
emit openWithRequested(doc, cmd);
|
||||
}
|
||||
|
||||
void ResList::menuCopyFN()
|
||||
{
|
||||
|
||||
@ -81,6 +81,7 @@ class ResList : public RESLIST_PARENTCLASS
|
||||
virtual void menuPreview();
|
||||
virtual void menuSaveToFile();
|
||||
virtual void menuEdit();
|
||||
virtual void menuOpenWith(QAction *);
|
||||
virtual void menuCopyFN();
|
||||
virtual void menuCopyURL();
|
||||
virtual void menuExpand();
|
||||
@ -104,6 +105,7 @@ class ResList : public RESLIST_PARENTCLASS
|
||||
void showSnippets(Rcl::Doc);
|
||||
void showSubDocs(Rcl::Doc);
|
||||
void editRequested(Rcl::Doc);
|
||||
void openWithRequested(Rcl::Doc, string cmd);
|
||||
void docExpand(Rcl::Doc);
|
||||
void wordSelect(QString);
|
||||
void wordReplace(const QString&, const QString&);
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
#include "recoll.h"
|
||||
#include "docseq.h"
|
||||
#include "respopup.h"
|
||||
#include "appformime.h"
|
||||
|
||||
namespace ResultPopup {
|
||||
|
||||
@ -47,6 +48,27 @@ QMenu *create(QWidget *me, int opts, RefCntr<DocSequence> source, Rcl::Doc& doc)
|
||||
popup->addAction(me->tr("&Open"), me, SLOT(menuEdit()));
|
||||
}
|
||||
|
||||
if (doc.ipath.empty()) {
|
||||
vector<DesktopDb::AppDef> aps;
|
||||
DesktopDb *ddb = DesktopDb::getDb();
|
||||
if (ddb && ddb->appForMime(doc.mimetype, &aps) &&
|
||||
!aps.empty()) {
|
||||
QMenu *sub = popup->addMenu(me->tr("Open With"));
|
||||
if (sub) {
|
||||
for (vector<DesktopDb::AppDef>::const_iterator it = aps.begin();
|
||||
it != aps.end(); it++) {
|
||||
QAction *act = new
|
||||
QAction(QString::fromUtf8(it->name.c_str()), me);
|
||||
QVariant v(QString::fromUtf8(it->command.c_str()));
|
||||
act->setData(v);
|
||||
sub->addAction(act);
|
||||
}
|
||||
sub->connect(sub, SIGNAL(triggered(QAction *)), me,
|
||||
SLOT(menuOpenWith(QAction *)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
popup->addAction(me->tr("Copy &File Name"), me, SLOT(menuCopyFN()));
|
||||
popup->addAction(me->tr("Copy &URL"), me, SLOT(menuCopyURL()));
|
||||
|
||||
|
||||
@ -880,6 +880,14 @@ void ResTable::menuEdit()
|
||||
if (m_detaildocnum >= 0)
|
||||
emit editRequested(m_detaildoc);
|
||||
}
|
||||
void ResTable::menuOpenWith(QAction *act)
|
||||
{
|
||||
if (act == 0)
|
||||
return;
|
||||
string cmd = qs2utf8s(act->data().toString());
|
||||
if (m_detaildocnum >= 0)
|
||||
emit openWithRequested(m_detaildoc, cmd);
|
||||
}
|
||||
|
||||
void ResTable::menuCopyFN()
|
||||
{
|
||||
|
||||
@ -137,6 +137,7 @@ public slots:
|
||||
virtual void menuSaveToFile();
|
||||
virtual void menuSaveSelection();
|
||||
virtual void menuEdit();
|
||||
virtual void menuOpenWith(QAction *);
|
||||
virtual void menuCopyFN();
|
||||
virtual void menuCopyURL();
|
||||
virtual void menuExpand();
|
||||
@ -157,6 +158,7 @@ signals:
|
||||
void docSaveToFileClicked(Rcl::Doc);
|
||||
void previewRequested(Rcl::Doc);
|
||||
void editRequested(Rcl::Doc);
|
||||
void openWithRequested(Rcl::Doc, string cmd);
|
||||
void headerClicked();
|
||||
void docExpand(Rcl::Doc);
|
||||
void showSubDocs(Rcl::Doc);
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
* code which would parse /usr/share/applications to return a list of
|
||||
* apps for a given mime type. So here goes. Note that the implementation
|
||||
* is very primitive for now (no use of cache file, no updating once built).
|
||||
* Also, this is not thread-safe, but could be made so quite easily.
|
||||
*/
|
||||
class DesktopDb {
|
||||
public:
|
||||
@ -49,7 +50,7 @@ public:
|
||||
* problem was detected.
|
||||
*/
|
||||
bool appForMime(const std::string& mime, vector<AppDef> *apps,
|
||||
std::string *reason);
|
||||
std::string *reason = 0);
|
||||
|
||||
private:
|
||||
DesktopDb();
|
||||
|
||||
@ -534,7 +534,7 @@ string escapeShell(const string &in)
|
||||
|
||||
|
||||
// Substitute printf-like percent cmds inside a string
|
||||
bool pcSubst(const string& in, string& out, map<char, string>& subs)
|
||||
bool pcSubst(const string& in, string& out, const map<char, string>& subs)
|
||||
{
|
||||
string::const_iterator it;
|
||||
for (it = in.begin(); it != in.end();it++) {
|
||||
@ -547,7 +547,7 @@ bool pcSubst(const string& in, string& out, map<char, string>& subs)
|
||||
out += '%';
|
||||
continue;
|
||||
}
|
||||
map<char,string>::iterator tr;
|
||||
map<char,string>::const_iterator tr;
|
||||
if ((tr = subs.find(*it)) != subs.end()) {
|
||||
out += tr->second;
|
||||
} else {
|
||||
@ -561,7 +561,7 @@ bool pcSubst(const string& in, string& out, map<char, string>& subs)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pcSubst(const string& in, string& out, map<string, string>& subs)
|
||||
bool pcSubst(const string& in, string& out, const map<string, string>& subs)
|
||||
{
|
||||
out.erase();
|
||||
string::size_type i;
|
||||
@ -592,7 +592,7 @@ bool pcSubst(const string& in, string& out, map<string, string>& subs)
|
||||
} else {
|
||||
key = in[i];
|
||||
}
|
||||
map<string,string>::iterator tr;
|
||||
map<string,string>::const_iterator tr;
|
||||
if ((tr = subs.find(key)) != subs.end()) {
|
||||
out += tr->second;
|
||||
} else {
|
||||
|
||||
@ -143,9 +143,9 @@ string displayableBytes(off_t size);
|
||||
string breakIntoLines(const string& in, unsigned int ll = 100,
|
||||
unsigned int maxlines= 50);
|
||||
/** Small utility to substitute printf-like percents cmds in a string */
|
||||
bool pcSubst(const string& in, string& out, map<char, string>& subs);
|
||||
bool pcSubst(const string& in, string& out, const map<char, string>& subs);
|
||||
/** Substitute printf-like percents and also %(key) */
|
||||
bool pcSubst(const string& in, string& out, map<string, string>& subs);
|
||||
bool pcSubst(const string& in, string& out, const map<string, string>& subs);
|
||||
|
||||
/** Append system error message */
|
||||
void catstrerror(string *reason, const char *what, int _errno);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user