From 030e576cdb71fe05d9e35db949fbe82fb5709285 Mon Sep 17 00:00:00 2001 From: Jean-Francois Dockes Date: Fri, 2 May 2014 10:07:26 +0200 Subject: [PATCH] add excludedmimetypes configuration variable --- src/common/rclconfig.cpp | 96 ++++++++++++++++++++++----------- src/common/rclconfig.h | 40 ++++++++++---- src/doc/user/usermanual.xml | 99 +++++++++++++++++++---------------- src/qtgui/respopup.cpp | 12 ++++- src/sampleconf/recoll.conf.in | 7 ++- src/utils/smallut.cpp | 2 + src/utils/smallut.h | 2 - tests/boolean/boolean.sh | 9 ++-- tests/config/recoll.conf | 8 +++ tests/dir/dir.sh | 3 +- tests/incexcl/incexcl.sh | 22 ++++++++ tests/incexcl/incexcl.txt | 7 +++ website/download.html | 10 ---- website/release-1.19.html | 2 +- 14 files changed, 210 insertions(+), 109 deletions(-) create mode 100755 tests/incexcl/incexcl.sh create mode 100644 tests/incexcl/incexcl.txt diff --git a/src/common/rclconfig.cpp b/src/common/rclconfig.cpp index ae9b1266..f75931f3 100644 --- a/src/common/rclconfig.cpp +++ b/src/common/rclconfig.cpp @@ -85,17 +85,21 @@ bool ParamStale::needrecompute() return false; } -void ParamStale::init(RclConfig *rconf, ConfNull *cnf, const string& nm) +void ParamStale::init(ConfNull *cnf) { - parent = rconf; conffile = cnf; - paramname = nm; active = false; if (conffile) - active = conffile->hasNameAnywhere(nm); + active = conffile->hasNameAnywhere(paramname); savedkeydirgen = -1; } +ParamStale::ParamStale(RclConfig *rconf, const string& nm) + : parent(rconf), conffile(0), paramname(nm), + active(false), savedkeydirgen(-1) +{ +} + void RclConfig::zeroMe() { m_ok = false; m_keydirgen = 0; @@ -107,10 +111,12 @@ void RclConfig::zeroMe() { m_ptrans = 0; m_stopsuffixes = 0; m_maxsufflen = 0; - m_stpsuffstate.init(this, 0, "recoll_noindex"); - m_skpnstate.init(this, 0, "skippedNames"); - m_rmtstate.init(this, 0, "indexedmimetypes"); - m_mdrstate.init(this, 0, "metadatacmds"); + + m_stpsuffstate.init(0); + m_skpnstate.init(0); + m_rmtstate.init(0); + m_xmtstate.init(0); + m_mdrstate.init(0); } bool RclConfig::isDefaultConfig() const @@ -122,6 +128,11 @@ bool RclConfig::isDefaultConfig() const } RclConfig::RclConfig(const string *argcnf) + : m_stpsuffstate(this, "recoll_noindex"), + m_skpnstate(this, "skippedNames"), + m_rmtstate(this, "indexedmimetypes"), + m_xmtstate(this, "excludedmimetypes"), + m_mdrstate(this, "metadatacmds") { zeroMe(); @@ -269,10 +280,12 @@ RclConfig::RclConfig(const string *argcnf) m_ok = true; setKeyDir(cstr_null); - m_stpsuffstate.init(this, mimemap, "recoll_noindex"); - m_skpnstate.init(this, m_conf, "skippedNames"); - m_rmtstate.init(this, m_conf, "indexedmimetypes"); - m_mdrstate.init(this, m_conf, "metadatacmds"); + m_stpsuffstate.init(mimemap); + m_skpnstate.init(m_conf); + m_rmtstate.init(m_conf); + m_xmtstate.init(m_conf); + m_mdrstate.init(m_conf); + return; } @@ -287,16 +300,20 @@ bool RclConfig::updateMainConfig() stringsToString(m_cdirs, where); m_reason = string("No/bad main configuration file in: ") + where; m_ok = false; - m_skpnstate.init(this, 0, "skippedNames"); - m_rmtstate.init(this, 0, "indexedmimetypes"); - m_mdrstate.init(this, 0, "metadatacmds"); + m_skpnstate.init(0); + m_rmtstate.init(0); + m_xmtstate.init(0); + m_mdrstate.init(0); return false; } + delete m_conf; m_conf = newconf; - m_skpnstate.init(this, m_conf, "skippedNames"); - m_rmtstate.init(this, m_conf, "indexedmimetypes"); - m_mdrstate.init(this, m_conf, "metadatacmds"); + + m_skpnstate.init(m_conf); + m_rmtstate.init(m_conf); + m_xmtstate.init(m_conf); + m_mdrstate.init(m_conf); setKeyDir(cstr_null); bool nocjk = false; @@ -677,17 +694,30 @@ bool RclConfig::getMimeCatTypes(const string& cat, vector& tps) const string RclConfig::getMimeHandlerDef(const string &mtype, bool filtertypes) { string hs; - if (filtertypes && m_rmtstate.needrecompute()) { - m_restrictMTypes.clear(); - stringToStrings(stringtolower((const string&)m_rmtstate.savedvalue), - m_restrictMTypes); - } - if (filtertypes && !m_restrictMTypes.empty()) { - string mt = mtype; - stringtolower(mt); - if (m_restrictMTypes.find(mt) == m_restrictMTypes.end()) - return hs; + + if (filtertypes) { + if(m_rmtstate.needrecompute()) { + m_restrictMTypes.clear(); + stringToStrings(stringtolower((const string&)m_rmtstate.savedvalue), + m_restrictMTypes); + } + if (m_xmtstate.needrecompute()) { + m_excludeMTypes.clear(); + stringToStrings(stringtolower((const string&)m_xmtstate.savedvalue), + m_excludeMTypes); + } + if (!m_restrictMTypes.empty() && + !m_restrictMTypes.count(stringtolower(mtype))) { + LOGDEB2(("RclConfig::getMimeHandlerDef: not in mime type list\n")); + return hs; + } + if (!m_excludeMTypes.empty() && + m_excludeMTypes.count(stringtolower(mtype))) { + LOGDEB2(("RclConfig::getMimeHandlerDef: in excluded mime list\n")); + return hs; + } } + if (!mimeconf->get(mtype, hs, "index")) { LOGDEB1(("getMimeHandler: no handler for '%s'\n", mtype.c_str())); } @@ -1397,10 +1427,12 @@ void RclConfig::initFrom(const RclConfig& r) m_maxsufflen = r.m_maxsufflen; m_defcharset = r.m_defcharset; - m_stpsuffstate.init(this, mimemap, r.m_stpsuffstate.paramname); - m_skpnstate.init(this, m_conf, r.m_skpnstate.paramname); - m_rmtstate.init(this, m_conf, r.m_rmtstate.paramname); - m_mdrstate.init(this, m_conf, r.m_mdrstate.paramname); + m_stpsuffstate.init(mimemap); + m_skpnstate.init(m_conf); + m_rmtstate.init(m_conf); + m_xmtstate.init(m_conf); + m_mdrstate.init(m_conf); + m_thrConf = r.m_thrConf; } diff --git a/src/common/rclconfig.h b/src/common/rclconfig.h index e158286d..6868721f 100644 --- a/src/common/rclconfig.h +++ b/src/common/rclconfig.h @@ -22,6 +22,7 @@ #include #include #include +#include "unordered_defs.h" using std::string; using std::vector; @@ -48,7 +49,8 @@ public: int savedkeydirgen; string savedvalue; - void init(RclConfig *rconf, ConfNull *cnf, const string& nm); + ParamStale(RclConfig *rconf, const string& nm); + void init(ConfNull *cnf); bool needrecompute(); }; @@ -76,6 +78,19 @@ class RclConfig { // argcnf RclConfig(const string *argcnf = 0); + RclConfig(const RclConfig &r) + : m_stpsuffstate(this, "recoll_noindex"), + m_skpnstate(this, "skippedNames"), + m_rmtstate(this, "indexedmimetypes"), + m_xmtstate(this, "excludedmimetypes"), + m_mdrstate(this, "metadatacmds") { + initFrom(r); + } + + ~RclConfig() { + freeAll(); + } + // Return a writable clone of the main config. This belongs to the // caller (must delete it when done) ConfNull *cloneMainConfig(); @@ -226,15 +241,21 @@ class RclConfig { /** fields: get field prefix from field name */ bool getFieldTraits(const string& fldname, const FieldTraits **) const; + const set& getStoredFields() const {return m_storedFields;} + set getIndexedFields() const; + /** Get canonic name for possible alias */ string fieldCanon(const string& fld) const; + /** Get xattr name to field names translations */ const map& getXattrToField() const {return m_xattrtofld;} + /** Get value of a parameter inside the "fields" file. Only some filters - use this (ie: mh_mail). The information specific to a given filter - is typically stored in a separate section(ie: [mail]) */ + * use this (ie: mh_mail). The information specific to a given filter + * is typically stored in a separate section(ie: [mail]) + */ vector getFieldSectNames(const string &sk, const char* = 0) const; bool getFieldConfParam(const string &name, const string &sk, string &value) const; @@ -272,13 +293,6 @@ class RclConfig { return o_origcwd; } - ~RclConfig() { - freeAll(); - } - - RclConfig(const RclConfig &r) { - initFrom(r); - } RclConfig& operator=(const RclConfig &r) { if (this != &r) { freeAll(); @@ -326,7 +340,11 @@ class RclConfig { static string o_localecharset; // Limiting set of mime types to be processed. Normally empty. ParamStale m_rmtstate; - set m_restrictMTypes; + STD_UNORDERED_SET m_restrictMTypes; + // Exclusion set of mime types. Normally empty + ParamStale m_xmtstate; + STD_UNORDERED_SET m_excludeMTypes; + vector > m_thrConf; // Same idea with the metadata-gathering external commands, diff --git a/src/doc/user/usermanual.xml b/src/doc/user/usermanual.xml index 380c07c2..50bc8f03 100644 --- a/src/doc/user/usermanual.xml +++ b/src/doc/user/usermanual.xml @@ -374,20 +374,16 @@ contrary to define a positive list of types to be indexed. In the latter case, any type not in the list will be ignored. + Excluding types can be done by adding wildcard name patterns to the skippedNames list, which - can be done from the GUI Index configuration menu. It is - also possible to exclude a mime type independantly of the - file name by associating it with the - rclnull input handler. This can be done - by editing the - mimeconf configuration - file. + can be done from the GUI Index configuration menu. For + versions 1.20 and later, you can alternatively set the + excludedmimetypes list in the + configuration file. This can be redefined for + subdirectories. - In order to define a positive list, You need to edit the - main - configuration file - (recoll.conf) and set + You can also define an exclusive list of MIME types to be indexed (no others will be indexed), by settting the indexedmimetypes configuration variable. Example: indexedmimetypes = text/html application/pdf @@ -399,12 +395,17 @@ indexedmimetypes = application/pdf (When using sections like this, don't forget that they remain in effect until the end of the file or another section - indicator). - There is no GUI way to edit the parameter, because this - option runs contrary to &RCL; main goal which is to help you - find information, independantly of how it may be stored. - + indicator). + In order to set excludedmimetypes + or indexedmimetypes, you need to edit the + main + configuration file + (recoll.conf). I used to have + a bogus reason for this, but the really true truth is that + I was too lazy to extend the GUI for these relatively + rarely used parameters. + @@ -789,7 +790,7 @@ recoll mime_type If set, this overrides any other - determination of the file mime type. + determination of the file MIME type. charset @@ -1253,11 +1254,11 @@ fs.inotify.max_user_watches=32768 uncheck the Use desktop preferences option in the GUI preferences dialog, and click the Choose editor applications button to adjust the predefined &RCL; - choices. The tool accepts multiple selections of mime types (e.g. to + choices. The tool accepts multiple selections of MIME types (e.g. to set up the editor for the dozens of office file types). Even when Use desktop preferences is - checked, there is a small list of exceptions, for mime types where + checked, there is a small list of exceptions, for MIME types where the &RCL; choice should override the desktop one. These are applications which are well integrated with &RCL;, especially evince for viewing PDF and Postscript @@ -1559,7 +1560,7 @@ fs.inotify.max_user_watches=32768 The second tab lets filter the results according - to file size, date of modification, mime type, or + to file size, date of modification, MIME type, or location. @@ -1656,8 +1657,8 @@ fs.inotify.max_user_watches=32768 - The next section allows filtering the results by their mime - types, or mime categories (ie: media/text/message/etc.). + The next section allows filtering the results by their MIME + types, or MIME categories (ie: media/text/message/etc.). You can transfer the types between two boxes, to define which will be included or excluded by the search. The state of the file type selection can be saved as @@ -2178,7 +2179,7 @@ fs.inotify.max_user_watches=32768 Exceptions: when using the - desktop preferences for opening documents, these are mime types + desktop preferences for opening documents, these are MIME types that will still be opened according to &RCL; preferences. This is useful for passing parameters like page numbers or search strings to applications that support them @@ -2403,7 +2404,7 @@ fs.inotify.max_user_watches=32768 %DDate %IIcon image - name. This is normally determined from the mime type. The + name. This is normally determined from the MIME type. The associations are defined inside the mimeconf configuration file. @@ -2417,7 +2418,7 @@ fs.inotify.max_user_watches=32768 %LPrecooked Preview, Edit, and possibly Snippets links - %MMime + %MMIME type %Nresult Number inside @@ -2922,7 +2923,7 @@ dir:recoll dir:src -dir:utils -dir:common mime or format for specifying the - mime type. This one is quite special because you can specify + MIME type. This one is quite special because you can specify several values which will be OR'ed (the normal default for the language is AND). Ex: mime:text/plain mime:text/html. Specifying an explicit boolean @@ -2939,12 +2940,12 @@ dir:recoll dir:src -dir:utils -dir:common type or rclcat for specifying the category (as in - text/media/presentation/etc.). The classification of mime + text/media/presentation/etc.). The classification of MIME types in categories is defined in the &RCL; configuration (mimeconf), and can be modified or extended. The default category names are those which permit filtering results in the main GUI screen. Categories are OR'ed - like mime types above. This can't be negated with + like MIME types above. This can't be negated with - either. @@ -3480,10 +3481,10 @@ dir:recoll dir:src -dir:utils -dir:common Telling &RCL; about the handler There are two elements that link a file to the handler which - should process it: the association of file to mime type and the - association of a mime type with a handler. + should process it: the association of file to MIME type and the + association of a MIME type with a handler. - The association of files to mime types is mostly based on + The association of files to MIME types is mostly based on name suffixes. The types are defined inside the mimemap file. Example: @@ -3493,7 +3494,7 @@ dir:recoll dir:src -dir:utils -dir:common If no suffix association is found for the file name, &RCL; will try to execute the file -i command to determine a - mime type. + MIME type. The association of file types to handlers is performed in the @@ -5020,12 +5021,18 @@ skippedPaths = ~/somedir/*.txt indexedmimetypes &RCL; normally indexes any file which it knows how to read. This list lets you restrict the indexed - mime types to what you specify. If the variable is + MIME types to what you specify. If the variable is unspecified or the list empty (the default), all supported types are processed. Can be redefined for subdirectories. + excludedmimetypes + This list lets you exclude some MIME types from + indexing. Can be redefined for subdirectories. + + + compressedfilemaxkbs Size limit for compressed (.gz or .bz2) files. These need to be decompressed in a temporary @@ -5064,17 +5071,17 @@ skippedPaths = ~/somedir/*.txt &RCL; indexes file names in a special section of the database to allow specific file names searches using wild cards. This parameter decides if - file name indexing is performed only for files with mime + file name indexing is performed only for files with MIME types that would qualify them for full text indexing, or for all files inside the selected subtrees, independently of - mime type. + MIME type. usesystemfilecommand Decide if we use the file system command - as a final step for determining the mime type for a file + as a final step for determining the MIME type for a file (the main procedure uses suffix associations as defined in the mimemap file). This can be useful for files with suffix-less names, but it will also cause @@ -5739,12 +5746,12 @@ x-my-tag = mailmytag The mimemap file mimemap specifies the - file name extension to mime type mappings. + file name extension to MIME type mappings. For file names without an extension, or with an unknown one, the system's file command will be - executed to determine the mime type (this can be switched off + executed to determine the MIME type (this can be switched off inside the main configuration file). The mappings can be specified on a per-subtree basis, @@ -5776,7 +5783,7 @@ x-my-tag = mailmytag The mimeconf file mimeconf specifies how the - different mime types are handled for indexing, and which icons + different MIME types are handled for indexing, and which icons are displayed in the recoll result lists. Changing the parameters in the [index] section is @@ -5813,7 +5820,7 @@ x-my-tag = mailmytag use xdg-open by default). In this case, the xallexcepts top level - variable defines a list of mime type exceptions which + variable defines a list of MIME type exceptions which will be processed according to the local entries instead of being passed to the desktop. This is so that specific &RCL; options such as a page number or a search string can be passed to @@ -5829,7 +5836,7 @@ x-my-tag = mailmytag All viewer definition entries must be placed under a [view] section. - The keys in the file are normally mime types. You can add an + The keys in the file are normally MIME types. You can add an application tag to specialize the choice for an area of the filesystem (using a localfields specification in mimeconf). The syntax for the key is @@ -5837,7 +5844,7 @@ x-my-tag = mailmytag The nouncompforviewmts entry, (placed at the top level, outside of the [view] section), - holds a list of mime types that should not be uncompressed before + holds a list of MIME types that should not be uncompressed before starting the viewer (if they are found compressed, ie: mydoc.doc.gz). @@ -5871,7 +5878,7 @@ x-my-tag = mailmytag %M - Mime type + MIME type %p @@ -5950,7 +5957,7 @@ x-my-tag = mailmytag following line: .blob = application/x-blobapp - Note that the mime type is made up here, and you could + Note that the MIME type is made up here, and you could call it diesel/oil just the same. @@ -5967,7 +5974,7 @@ application/x-blobapp = blobviewer %f If you just wanted to change the application used by - &RCL; to display a mime type which it already knows, you + &RCL; to display a MIME type which it already knows, you would just need to edit mimeview. The entries you add in your personal file override those in the central configuration, which you do not need to @@ -6001,7 +6008,7 @@ application/x-blobapp = exec rclblob /usr/[local/]share/recoll/images. Under the [categories] - section, you should add the mime type where it makes sense + section, you should add the MIME type where it makes sense (you can also create a category). Categories may be used for filtering in advanced search. diff --git a/src/qtgui/respopup.cpp b/src/qtgui/respopup.cpp index da5c24cd..bd3385b1 100644 --- a/src/qtgui/respopup.cpp +++ b/src/qtgui/respopup.cpp @@ -48,7 +48,17 @@ QMenu *create(QWidget *me, int opts, RefCntr source, Rcl::Doc& doc) popup->addAction(me->tr("&Open"), me, SLOT(menuEdit())); } - if (doc.ipath.empty()) { + bool needopenwith = true; + if (!doc.ipath.empty()) + needopenwith = false; + if (needopenwith) { + string backend; + doc.getmeta(Rcl::Doc::keybcknd, &backend); + if (!backend.empty() && backend.compare("FS")) + needopenwith = false; + } + + if (needopenwith) { vector aps; DesktopDb *ddb = DesktopDb::getDb(); if (ddb && ddb->appForMime(doc.mimetype, &aps) && diff --git a/src/sampleconf/recoll.conf.in b/src/sampleconf/recoll.conf.in index b2305fe7..fd87ca86 100644 --- a/src/sampleconf/recoll.conf.in +++ b/src/sampleconf/recoll.conf.in @@ -199,7 +199,12 @@ indexallfilenames = 1 # will be indexed anyway if indexallfilenames is set as by default). Mime # type names should be taken from the mimemap file. # -# indexedmimetypes = text/html application/pdf +# indexedmimetypes = + +# An excluded list of mime types. It can be redefined in subdirectories, +# so can be used to locally exclude some types. +# +# excludededmimetypes = # # Size limit for archive members. This is passed to the filters in the diff --git a/src/utils/smallut.cpp b/src/utils/smallut.cpp index e3bfbb01..40b16354 100644 --- a/src/utils/smallut.cpp +++ b/src/utils/smallut.cpp @@ -291,6 +291,8 @@ template bool stringToStrings >(const string &, vector &,const string&); template bool stringToStrings >(const string &, set &, const string&); +template bool stringToStrings > +(const string &, STD_UNORDERED_SET &, const string&); template void stringsToString(const T &tokens, string &s) { diff --git a/src/utils/smallut.h b/src/utils/smallut.h index 2b749175..bc8c132c 100644 --- a/src/utils/smallut.h +++ b/src/utils/smallut.h @@ -24,12 +24,10 @@ #include #include -#ifndef NO_NAMESPACES using std::string; using std::vector; using std::map; using std::set; -#endif /* NO_NAMESPACES */ // Note these are all ascii routines extern int stringicmp(const string& s1, const string& s2); diff --git a/tests/boolean/boolean.sh b/tests/boolean/boolean.sh index c27b05af..18cf8dcb 100755 --- a/tests/boolean/boolean.sh +++ b/tests/boolean/boolean.sh @@ -5,10 +5,11 @@ topdir=`dirname $0`/.. initvariables $0 -recollq 'boolean_uniqueterm One OR Two -Three' 2> $mystderr | - egrep -v '^Recoll query: ' > $mystdout +( +recollq 'boolean_uniqueterm One OR Two -Three' -diff -w ${myname}.txt 2>> $mystderr | - egrep -v '^Recoll query: ' >> $mystdout +) 2> $mystderr | egrep -v '^Recoll query: ' > $mystdout + +diff -w ${myname}.txt $mystdout > $mydiffs 2>&1 checkresult diff --git a/tests/config/recoll.conf b/tests/config/recoll.conf index c6626ac7..1a284ad4 100644 --- a/tests/config/recoll.conf +++ b/tests/config/recoll.conf @@ -31,3 +31,11 @@ mhmboxquirks = tbird [/home/dockes/projets/fulltext/testrecoll/cjk] localfields= ; keyword = ckjtsthuniique; blabla= "some string" + +[/home/dockes/projets/fulltext/testrecoll/idxtypes] +indexedmimetypes = text/plain + +[/home/dockes/projets/fulltext/testrecoll/excltypes] +excludedmimetypes = text/plain + + diff --git a/tests/dir/dir.sh b/tests/dir/dir.sh index 1b9d8b21..03d0b37f 100755 --- a/tests/dir/dir.sh +++ b/tests/dir/dir.sh @@ -4,9 +4,10 @@ topdir=`dirname $0`/.. . $topdir/shared.sh initvariables $0 + ( # Only - recollq filename:testdirfile dir:testrecoll/dir/d1 OR + recollq filename:testdirfile dir:testrecoll/dir/d1 OR \ dir:testrecoll/dir/d2 -dir:d2 ) 2> $mystderr | egrep -v '^Recoll query: ' > $mystdout diff --git a/tests/incexcl/incexcl.sh b/tests/incexcl/incexcl.sh new file mode 100755 index 00000000..ce34814d --- /dev/null +++ b/tests/incexcl/incexcl.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +thisdir=`dirname $0` +topdir=$thisdir/.. +. $topdir/shared.sh + +initvariables $0 + +( +echo "Should find idxtypes/idxt.txt only" +recollq idxtypesunique +echo + +echo "Should find idxtypes/idxt.html only" +recollq excltypesunique + +) 2> $mystderr | egrep -v '^Recoll query: ' > $mystdout + + +diff -w ${myname}.txt $mystdout > $mydiffs 2>&1 + +checkresult diff --git a/tests/incexcl/incexcl.txt b/tests/incexcl/incexcl.txt new file mode 100644 index 00000000..24923531 --- /dev/null +++ b/tests/incexcl/incexcl.txt @@ -0,0 +1,7 @@ +Should find idxtypes/idxt.txt only +1 results +text/plain [file:///home/dockes/projets/fulltext/testrecoll/idxtypes/idxt.txt] [idxt.txt] 16 bytes + +Should find idxtypes/idxt.html only +1 results +text/html [file:///home/dockes/projets/fulltext/testrecoll/excltypes/idxt.html] [idxt.html] 69 bytes diff --git a/website/download.html b/website/download.html index bbbcadf8..865075e0 100644 --- a/website/download.html +++ b/website/download.html @@ -197,18 +197,8 @@ branch for the current production version.

1.19.9. -1.19.8. -1.19.7. -1.19.5. -1.19.4. -1.19.3. -1.19.2. 1.18.2. 1.17.3. -1.16.2. -1.15.9. -1.14.4. -1.13.04.

diff --git a/website/release-1.19.html b/website/release-1.19.html index f567dbce..c269d039 100644 --- a/website/release-1.19.html +++ b/website/release-1.19.html @@ -64,7 +64,7 @@ Configuration menu.

Minor releases at a glance

  • 1.19.12p2 fulfills an old promise that I had forgotten: have a - double-clik in the result table run an "open file" action. It just + double-click in the result table run an "open file" action. It just had waited for too long...
  • 1.19.12p1 fixes the 1.19.12 install script which did not actually copy the xls filter...