Arrange so we can now open the parent of a document (e.g. chm file instead of temp copy of html page inside chm), even when the parent is itself embedded in an archive
This commit is contained in:
parent
382ae1f718
commit
5add2e2384
@ -215,7 +215,7 @@
|
||||
<application>Python</application>
|
||||
programming interface</link>, a <link linkend="rcl.search.kio">
|
||||
<application>KDE</application> KIO slave module</link>, and
|
||||
a <application>Ubuntu Unity Lens</application> module.
|
||||
a <ulink url="http://bitbucket.org/medoc/recoll/wiki/UnityLens">Ubuntu Unity Lens</ulink> module.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
@ -2825,8 +2825,29 @@ dir:recoll dir:src -dir:utils -dir:common
|
||||
<title>Desktop integration</title>
|
||||
|
||||
<para>Being independant of the desktop type has its drawbacks: &RCL;
|
||||
desktop integration is minimal. Here follow a few things that may
|
||||
help.</para>
|
||||
desktop integration is minimal. However there are a few tools
|
||||
available:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>The <application>KDE</application> KIO Slave was
|
||||
described in a <link linkend="rcl.search.kio">previous
|
||||
section</link>.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>If you use a recent version of Ubuntu Linux, you may
|
||||
find the <ulink
|
||||
url="http://bitbucket.org/medoc/recoll/wiki/UnityLens">Ubuntu Unity
|
||||
Lens</ulink> module useful.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>There is also an independantly developed
|
||||
<ulink
|
||||
url="http://kde-apps.org/content/show.php/recollrunner?content=128203">
|
||||
Krunner plugin</ulink>.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>Here follow a few other things that may help.</para>
|
||||
|
||||
<sect2 id="rcl.search.shortcut">
|
||||
<title>Hotkeying recoll</title>
|
||||
@ -2844,6 +2865,7 @@ dir:recoll dir:src -dir:utils -dir:common
|
||||
<sect2 id="rcl.kicker-applet">
|
||||
<title>The KDE Kicker Recoll applet</title>
|
||||
|
||||
<para>This is probably obsolete now. Anyway:</para>
|
||||
<para>The &RCL; source tree contains the source code to the
|
||||
<application>recoll_applet</application>, a small application derived
|
||||
from the <application>find_applet</application>. This can be used to
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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")
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 */
|
||||
|
||||
|
||||
@ -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<string, string> 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()
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user