diff --git a/src/doc/user/usermanual.sgml b/src/doc/user/usermanual.sgml
index 88fffbde..93dcde7d 100644
--- a/src/doc/user/usermanual.sgml
+++ b/src/doc/user/usermanual.sgml
@@ -215,7 +215,7 @@
Python
programming interface, a
KDE KIO slave module, and
- a Ubuntu Unity Lens module.
+ a Ubuntu Unity Lens module.
@@ -2825,8 +2825,29 @@ dir:recoll dir:src -dir:utils -dir:common
Desktop integration
Being independant of the desktop type has its drawbacks: &RCL;
- desktop integration is minimal. Here follow a few things that may
- help.
+ desktop integration is minimal. However there are a few tools
+ available:
+
+
+ The KDE KIO Slave was
+ described in a previous
+ section.
+
+
+ If you use a recent version of Ubuntu Linux, you may
+ find the Ubuntu Unity
+ Lens module useful.
+
+
+ There is also an independantly developed
+
+ Krunner plugin.
+
+
+
+ Here follow a few other things that may help.
Hotkeying recoll
@@ -2844,6 +2865,7 @@ dir:recoll dir:src -dir:utils -dir:common
The KDE Kicker Recoll applet
+ This is probably obsolete now. Anyway:
The &RCL; source tree contains the source code to the
recoll_applet, a small application derived
from the find_applet. This can be used to
diff --git a/src/filters/rclchm b/src/filters/rclchm
index dff3b853..39e415b0 100755
--- a/src/filters/rclchm
+++ b/src/filters/rclchm
@@ -190,7 +190,6 @@ class rclCHM:
def __init__(self, em):
self.contents = []
self.chm = chm.CHMFile()
- self.currentindex = 0
self.em = em
if rclchm_catenate:
self.em.setmimetype("text/plain")
@@ -240,7 +239,7 @@ class rclCHM:
"""Open the chm file and build the contents list by extracting and
parsing the Topics object"""
- self.currentindex = 0
+ self.currentindex = -1
self.contents = []
filename = params["filename:"]
@@ -248,8 +247,6 @@ class rclCHM:
self.em.rclog("LoadCHM failed")
return False
- self.sfn = os.path.basename(filename)
-
#self.em.rclog("home [%s] topics [%s] title [%s]" %
# (self.chm.home, self.chm.topics, self.chm.title))
@@ -293,6 +290,16 @@ class rclCHM:
else:
return (False, "", "", rclexecm.RclExecM.eofnow)
+ if self.currentindex == -1:
+ # Return "self" doc
+ self.currentindex = 0
+ self.em.setmimetype('text/plain')
+ if len(self.contents) == 0:
+ eof = rclexecm.RclExecM.eofnext
+ else:
+ eof = rclexecm.RclExecM.noteof
+ return (True, "", "", eof)
+
if self.currentindex >= len(self.contents):
return (False, "", "", rclexecm.RclExecM.eofnow)
else:
diff --git a/src/filters/rclepub b/src/filters/rclepub
index dac4293c..545b3763 100755
--- a/src/filters/rclepub
+++ b/src/filters/rclepub
@@ -48,7 +48,7 @@ class rclEPUB:
def openfile(self, params):
"""Open the EPUB file, create a contents array"""
- self.currentindex = 0
+ self.currentindex = -1
self.contents = []
try:
self.book = epub.open(params["filename:"])
@@ -65,6 +65,17 @@ class rclEPUB:
return self.extractone(params["ipath:"])
def getnext(self, params):
+
+ if self.currentindex == -1:
+ # Return "self" doc
+ self.currentindex = 0
+ self.em.setmimetype('text/plain')
+ if len(self.contents) == 0:
+ eof = rclexecm.RclExecM.eofnext
+ else:
+ eof = rclexecm.RclExecM.noteof
+ return (True, "", "", eof)
+
if self.currentindex >= len(self.contents):
return (False, "", "", rclexecm.RclExecM.eofnow)
else:
diff --git a/src/filters/rclics b/src/filters/rclics
index 866b8b33..6ad3f632 100755
--- a/src/filters/rclics
+++ b/src/filters/rclics
@@ -60,7 +60,7 @@ class IcalExtractor:
self.em.rclog("Openfile: open: %s" % str(e))
return False
- self.currentindex = 0
+ self.currentindex = -1
if usemodule == 'internal':
self.contents = ICalSimpleSplitter().splitcalendar(calstr)
@@ -96,6 +96,17 @@ class IcalExtractor:
return self.extractone(index)
def getnext(self, params):
+
+ if self.currentindex == -1:
+ # Return "self" doc
+ self.currentindex = 0
+ self.em.setmimetype('text/plain')
+ if len(self.contents) == 0:
+ eof = rclexecm.RclExecM.eofnext
+ else:
+ eof = rclexecm.RclExecM.noteof
+ return (True, "", "", eof)
+
if self.currentindex >= len(self.contents):
self.em.rclog("getnext: EOF hit")
return (False, "", "", rclexecm.RclExecM.eofnow)
diff --git a/src/filters/rclinfo b/src/filters/rclinfo
index 01ef47d9..c6b8a8b1 100755
--- a/src/filters/rclinfo
+++ b/src/filters/rclinfo
@@ -73,7 +73,7 @@ class InfoExtractor:
sys.exit(1);
- self.currentindex = 0
+ self.currentindex = -1
self.contents = InfoSimpleSplitter().splitinfo(self.file, infostream)
@@ -90,6 +90,17 @@ class InfoExtractor:
# Extract next in list
def getnext(self, params):
+
+ if self.currentindex == -1:
+ # Return "self" doc
+ self.currentindex = 0
+ self.em.setmimetype('text/plain')
+ if len(self.contents) == 0:
+ eof = rclexecm.RclExecM.eofnext
+ else:
+ eof = rclexecm.RclExecM.noteof
+ return (True, "", "", eof)
+
if self.currentindex >= len(self.contents):
self.em.rclog("getnext: EOF hit")
return (False, "", "", rclexecm.RclExecM.eofnow)
diff --git a/src/filters/rclrar b/src/filters/rclrar
index aa10d602..b661f510 100755
--- a/src/filters/rclrar
+++ b/src/filters/rclrar
@@ -73,7 +73,7 @@ class RarExtractor:
###### File type handler api, used by rclexecm ---------->
def openfile(self, params):
- self.currentindex = 0
+ self.currentindex = -1
try:
self.rar = RarFile(params["filename:"])
return True
@@ -93,6 +93,17 @@ class RarExtractor:
return (ok, data, ipath, eof)
def getnext(self, params):
+
+ if self.currentindex == -1:
+ # Return "self" doc
+ self.currentindex = 0
+ self.em.setmimetype('text/plain')
+ if len(self.rar.namelist()) == 0:
+ eof = rclexecm.RclExecM.eofnext
+ else:
+ eof = rclexecm.RclExecM.noteof
+ return (True, "", "", eof)
+
if self.currentindex >= len(self.rar.namelist()):
#self.em.rclog("getnext: EOF hit")
return (False, "", "", rclexecm.RclExecM.eofnow)
diff --git a/src/filters/rcltar b/src/filters/rcltar
index 7e285a0f..14f98c0e 100755
--- a/src/filters/rcltar
+++ b/src/filters/rcltar
@@ -43,7 +43,7 @@ class TarExtractor:
return (ok, docdata, ipath, iseof)
def openfile(self, params):
- self.currentindex = 0
+ self.currentindex = -1
try:
self.tar = open(name=params["filename:"],mode='r')
self.namen = [ y.name for y in filter(lambda z:z.isfile(),self.tar.getmembers())]
@@ -63,6 +63,17 @@ class TarExtractor:
return (ok, data, ipath, eof)
def getnext(self, params):
+
+ if self.currentindex == -1:
+ # Return "self" doc
+ self.currentindex = 0
+ self.em.setmimetype('text/plain')
+ if len(self.namen) == 0:
+ eof = rclexecm.RclExecM.eofnext
+ else:
+ eof = rclexecm.RclExecM.noteof
+ return (True, "", "", eof)
+
if self.currentindex >= len(self.namen):
self.namen=[]
return (False, "", "", rclexecm.RclExecM.eofnow)
diff --git a/src/filters/rclwar b/src/filters/rclwar
index f102d5b5..8fe46638 100755
--- a/src/filters/rclwar
+++ b/src/filters/rclwar
@@ -22,7 +22,7 @@ class WarExtractor:
###### File type handler api, used by rclexecm ---------->
def openfile(self, params):
- self.currentindex = 0
+ self.currentindex = -1
try:
self.tar = tarfile.open(params["filename:"])
return True
@@ -40,6 +40,11 @@ class WarExtractor:
return self.extractone(tarinfo)
def getnext(self, params):
+ if self.currentindex == -1:
+ # Return "self" doc
+ self.currentindex = 0
+ return (True, "", "", rclexecm.RclExecM.noteof)
+
tarinfo = self.tar.next()
if tarinfo is None:
#self.em.rclog("getnext: EOF hit")
diff --git a/src/filters/rclzip b/src/filters/rclzip
index d9ea904f..eebe0cc3 100755
--- a/src/filters/rclzip
+++ b/src/filters/rclzip
@@ -67,7 +67,7 @@ class ZipExtractor:
###### File type handler api, used by rclexecm ---------->
def openfile(self, params):
- self.currentindex = 0
+ self.currentindex = -1
try:
self.zip = ZipFile(params["filename:"])
return True
@@ -87,6 +87,16 @@ class ZipExtractor:
return (ok, data, ipath, eof)
def getnext(self, params):
+ if self.currentindex == -1:
+ # Return "self" doc
+ self.currentindex = 0
+ self.em.setmimetype('text/plain')
+ if len(self.zip.namelist()) == 0:
+ eof = rclexecm.RclExecM.eofnext
+ else:
+ eof = rclexecm.RclExecM.noteof
+ return (True, "", "", eof)
+
if self.currentindex >= len(self.zip.namelist()):
#self.em.rclog("getnext: EOF hit")
return (False, "", "", rclexecm.RclExecM.eofnow)
diff --git a/src/internfile/internfile.cpp b/src/internfile/internfile.cpp
index cdbf1bae..c3d59698 100644
--- a/src/internfile/internfile.cpp
+++ b/src/internfile/internfile.cpp
@@ -126,6 +126,16 @@ bool FileInterner::getEnclosing(const string &url, const string &ipath,
return true;
}
+string FileInterner::getLastIpathElt(const string& ipath)
+{
+ string::size_type sep;
+ if ((sep = ipath.find_last_of(cstr_isep)) != string::npos) {
+ return ipath.substr(sep + 1);
+ } else {
+ return ipath;
+ }
+}
+
// Uncompress input file into a temporary one, by executing the appropriate
// script.
static bool uncompressfile(RclConfig *conf, const string& ifn,
diff --git a/src/internfile/internfile.h b/src/internfile/internfile.h
index 9b801b8c..7abf9e95 100644
--- a/src/internfile/internfile.h
+++ b/src/internfile/internfile.h
@@ -83,6 +83,9 @@ class FileInterner {
static bool getEnclosing(const string &url, const string &ipath,
string &eurl, string &eipath, string& udi);
+ /** Return last element in ipath, like basename */
+ static std::string getLastIpathElt(const std::string& ipath);
+
/** Constructors take the initial step to preprocess the data object and
* create the top filter */
diff --git a/src/qtgui/rclmain_w.cpp b/src/qtgui/rclmain_w.cpp
index 04ee7b24..93c9d772 100644
--- a/src/qtgui/rclmain_w.cpp
+++ b/src/qtgui/rclmain_w.cpp
@@ -1501,13 +1501,17 @@ static bool lookForHtmlBrowser(string &exefile)
void RclMain::startNativeViewer(Rcl::Doc doc, int pagenum, QString term)
{
- LOGDEB(("RclMain::startNativeViewer: page %d\n", pagenum));
- // Look for appropriate viewer
string apptag;
doc.getmeta(Rcl::Doc::keyapptg, &apptag);
+ LOGDEB(("RclMain::startNativeViewer: mtype [%s] apptag [%s] page %d "
+ "term [%s] url [%s] ipath [%s]\n",
+ doc.mimetype.c_str(), apptag.c_str(), pagenum,
+ (const char *)(term.toUtf8()), doc.url.c_str(), doc.ipath.c_str()
+ ));
+
+ // Look for appropriate viewer
string cmdplusattr = theconfig->getMimeViewerDef(doc.mimetype, apptag,
prefs.useDesktopOpen);
-
if (cmdplusattr.empty()) {
QMessageBox::warning(0, "Recoll",
tr("No external viewer configured for mime type [")
@@ -1515,25 +1519,12 @@ void RclMain::startNativeViewer(Rcl::Doc doc, int pagenum, QString term)
return;
}
- if (pagenum == -1) {
- pagenum = 1;
- string lterm;
- if (m_source.isNotNull())
- pagenum = m_source->getFirstMatchPage(doc, lterm);
- if (pagenum == -1)
- pagenum = 1;
- else
- term = QString::fromUtf8(lterm.c_str());
- }
- char cpagenum[20];
- sprintf(cpagenum, "%d", pagenum);
-
- // Extract possible viewer attributes
- ConfSimple attrs;
+ // Separate command string and viewer attributes (if any)
+ ConfSimple viewerattrs;
string cmd;
- theconfig->valueSplitAttributes(cmdplusattr, cmd, attrs);
+ theconfig->valueSplitAttributes(cmdplusattr, cmd, viewerattrs);
bool ignoreipath = false;
- if (attrs.get("ignoreipath", cmdplusattr))
+ if (viewerattrs.get("ignoreipath", cmdplusattr))
ignoreipath = stringToBool(cmdplusattr);
// Split the command line
@@ -1541,7 +1532,7 @@ void RclMain::startNativeViewer(Rcl::Doc doc, int pagenum, QString term)
if (!stringToStrings(cmd, lcmd)) {
QMessageBox::warning(0, "Recoll",
tr("Bad viewer command line for %1: [%2]\n"
- "Please check the mimeconf file")
+ "Please check the mimeview file")
.arg(QString::fromAscii(doc.mimetype.c_str()))
.arg(QString::fromLocal8Bit(cmd.c_str())));
return;
@@ -1549,23 +1540,23 @@ void RclMain::startNativeViewer(Rcl::Doc doc, int pagenum, QString term)
// Look for the command to execute in the exec path and the filters
// directory
- string cmdpath;
- if (!ExecCmd::which(lcmd.front(), cmdpath)) {
- cmdpath = theconfig->findFilter(lcmd.front());
+ string execpath;
+ if (!ExecCmd::which(lcmd.front(), execpath)) {
+ execpath = theconfig->findFilter(lcmd.front());
// findFilter returns its input param if the filter is not in
// the normal places. As we already looked in the path, we
// have no use for a simple command name here (as opposed to
// mimehandler which will just let execvp do its thing). Erase
- // cmdpath so that the user dialog will be started further
+ // execpath so that the user dialog will be started further
// down.
- if (!cmdpath.compare(lcmd.front()))
- cmdpath.erase();
+ if (!execpath.compare(lcmd.front()))
+ execpath.erase();
// Specialcase text/html because of the help browser need
- if (cmdpath.empty() && !doc.mimetype.compare("text/html")) {
- if (lookForHtmlBrowser(cmdpath)) {
+ if (execpath.empty() && !doc.mimetype.compare("text/html")) {
+ if (lookForHtmlBrowser(execpath)) {
lcmd.clear();
- lcmd.push_back(cmdpath);
+ lcmd.push_back(execpath);
lcmd.push_back("%u");
}
}
@@ -1573,7 +1564,7 @@ void RclMain::startNativeViewer(Rcl::Doc doc, int pagenum, QString term)
// Command not found: start the user dialog to help find another one:
- if (cmdpath.empty()) {
+ if (execpath.empty()) {
QString mt = QString::fromAscii(doc.mimetype.c_str());
QString message = tr("The viewer specified in mimeview for %1: %2"
" is not found.\nDo you want to start the "
@@ -1594,22 +1585,68 @@ void RclMain::startNativeViewer(Rcl::Doc doc, int pagenum, QString term)
// new command.
return;
}
+ // Get rid of the command name. lcmd is now argv[1...n]
+ lcmd.erase(lcmd.begin());
- // We may need a temp file, or not, depending on the command
- // arguments and the fact that this is a subdoc or not.
- bool wantsipath = (cmd.find("%i") != string::npos) || ignoreipath;
+
+ // Process the command arguments to determine if we need to create
+ // a temporary file.
+
+ // If the command has a %i parameter it will manage the
+ // un-embedding. Else if ipath is not empty, we need a temp file.
+ // This can be overridden with the "ignoreipath" attribute
+ bool groksipath = (cmd.find("%i") != string::npos) || ignoreipath;
+
+ // wantsfile: do we actually need a local file ? The only other
+ // case here is an url %u (ie: for web history).
bool wantsfile = cmd.find("%f") != string::npos;
- bool istempfile = false;
- string fn = fileurltolocalpath(doc.url);
- string orgfn = fn;
+ bool wantsparentfile = cmd.find("%F") != string::npos;
+
+ if (wantsfile && wantsparentfile) {
+ QMessageBox::warning(0, "Recoll",
+ tr("Viewer command line for %1 specifies both "
+ "file and parent file value: unsupported")
+ .arg(QString::fromAscii(doc.mimetype.c_str())));
+ return;
+ }
+
string url = doc.url;
+ string fn = fileurltolocalpath(doc.url);
+ Rcl::Doc pdoc;
+ if (wantsparentfile) {
+ // We want the path for the parent document. For example to
+ // open the chm file, not the internal page. Note that we just
+ // override the other file name in this case.
+ if (m_source.isNull() || !m_source->getEnclosing(doc, pdoc)) {
+ QMessageBox::warning(0, "Recoll",
+ tr("Cannot find parent document"));
+ return;
+ }
+ // Override fn with the parent's :
+ fn = fileurltolocalpath(pdoc.url);
+
+ // If the parent document has an ipath too, we need to create
+ // a temp file even if the command takes an ipath
+ // parameter. We have no viewer which could handle a double
+ // embedding. Will have to change if such a one appears.
+ if (!pdoc.ipath.empty()) {
+ groksipath = false;
+ }
+ }
+
+ bool istempfile = false;
+
+ LOGDEB(("RclMain::startNV: groksipath %d wantsf %d wantsparentf %d\n",
+ groksipath, wantsfile, wantsparentfile));
// If the command wants a file but this is not a file url, or
// there is an ipath that it won't understand, we need a temp file:
theconfig->setKeyDir(path_getfather(fn));
- if ((wantsfile && fn.empty()) || (!wantsipath && !doc.ipath.empty())) {
+ if (((wantsfile || wantsparentfile) && fn.empty()) ||
+ (!groksipath && !doc.ipath.empty())) {
TempFile temp;
- if (!FileInterner::idocToFile(temp, string(), theconfig, doc)) {
+ Rcl::Doc& thedoc = wantsparentfile ? pdoc : doc;
+ if (!FileInterner::idocToFile(temp, string(), theconfig, thedoc)) {
QMessageBox::warning(0, "Recoll",
tr("Cannot extract document or create "
"temporary file"));
@@ -1647,8 +1684,21 @@ 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());
+ // If we are not called with a page number (which would happen for a call
+ // from the snippets window), see if we can compute a page number anyway.
+ if (pagenum == -1) {
+ pagenum = 1;
+ string lterm;
+ if (m_source.isNotNull())
+ pagenum = m_source->getFirstMatchPage(doc, lterm);
+ if (pagenum == -1)
+ pagenum = 1;
+ else // We get the match term used to compute the page
+ term = QString::fromUtf8(lterm.c_str());
+ }
+ char cpagenum[20];
+ sprintf(cpagenum, "%d", pagenum);
+
// Substitute %xx inside arguments
string efftime;
@@ -1662,8 +1712,8 @@ void RclMain::startNativeViewer(Rcl::Doc doc, int pagenum, QString term)
map subs;
subs["D"] = efftime;
subs["f"] = fn;
- subs["F"] = orgfn;
- subs["i"] = doc.ipath;
+ subs["F"] = fn;
+ subs["i"] = FileInterner::getLastIpathElt(doc.ipath);
subs["M"] = doc.mimetype;
subs["p"] = cpagenum;
subs["s"] = (const char*)term.toLocal8Bit();
@@ -1705,7 +1755,7 @@ void RclMain::startNativeViewer(Rcl::Doc doc, int pagenum, QString term)
// We keep pushing back and never deleting. This can't be good...
ExecCmd *ecmd = new ExecCmd;
m_viewers.push_back(ecmd);
- ecmd->startExec(cmdpath, lcmd, false, false);
+ ecmd->startExec(execpath, lcmd, false, false);
}
void RclMain::startManual()
diff --git a/tests/chm/chm.txt b/tests/chm/chm.txt
index 56f97cef..85c55d19 100644
--- a/tests/chm/chm.txt
+++ b/tests/chm/chm.txt
@@ -1,7 +1,8 @@
1 results
text/html [file:///home/dockes/projets/fulltext/testrecoll/chm/Nokia_Nseries_Help_jpn.chm] [デジタル著作権管理(DRM)] 2948 bytes
-1 results
+2 results
text/html [file:///home/dockes/projets/fulltext/testrecoll/chm/soundrec.chm] [Superposer (mixer) des fichiers son] 2279 bytes
+text/html [file:///home/dockes/projets/fulltext/testrecoll/chm/zippedsoundrec.zip] [Superposer (mixer) des fichiers son] 2279 bytes
1 results
text/html [file:///home/dockes/projets/fulltext/testrecoll/chm/Django-1.1a1-r9905.chm] [User authentication in Django] 115179 bytes
1 results