From 8da0bf28cc04508ce39150fc675039d0217f175f Mon Sep 17 00:00:00 2001 From: Jean-Francois Dockes Date: Sat, 27 Mar 2021 09:00:28 +0100 Subject: [PATCH] GUI: add popup menu option to copy simple file name. fix typo keytcfn->keyctfn. Change utf8check() parms for easier usage --- src/index/fsindexer.cpp | 5 ++-- src/internfile/txtdcode.cpp | 2 +- src/qtgui/reslist.cpp | 7 +++++ src/qtgui/reslist.h | 1 + src/qtgui/respopup.cpp | 56 ++++++++++++++++++++++++++++--------- src/qtgui/respopup.h | 1 + src/qtgui/restable.cpp | 6 ++++ src/qtgui/restable.h | 1 + src/rcldb/rcldb.cpp | 6 ++-- src/rcldb/rcldoc.cpp | 2 +- src/rcldb/rcldoc.h | 2 +- src/testmains/trpathut.cpp | 24 +++++++++++++--- src/utils/utf8iter.cpp | 8 +++--- src/utils/utf8iter.h | 2 +- 14 files changed, 91 insertions(+), 32 deletions(-) diff --git a/src/index/fsindexer.cpp b/src/index/fsindexer.cpp index 4a2b6e0a..5160e278 100644 --- a/src/index/fsindexer.cpp +++ b/src/index/fsindexer.cpp @@ -800,7 +800,7 @@ FsIndexer::processonefile(RclConfig *config, doc.meta[Rcl::Doc::keyfn] = utf8fn; } // Set container file name for all docs, top or subdoc - doc.meta[Rcl::Doc::keytcfn] = utf8fn; + doc.meta[Rcl::Doc::keyctfn] = utf8fn; doc.pcbytes = lltodecstr(stp->pst_size); // Document signature for up to date checks. All subdocs inherit the @@ -900,8 +900,7 @@ FsIndexer::processonefile(RclConfig *config, fileDoc.onlyxattr = true; } else { fileDoc.fmtime = ascdate; - fileDoc.meta[Rcl::Doc::keyfn] = - fileDoc.meta[Rcl::Doc::keytcfn] = utf8fn; + fileDoc.meta[Rcl::Doc::keyfn] = fileDoc.meta[Rcl::Doc::keyctfn] = utf8fn; fileDoc.haschildren = true; fileDoc.mimetype = mimetype; fileDoc.url = path_pathtofileurl(fn); diff --git a/src/internfile/txtdcode.cpp b/src/internfile/txtdcode.cpp index 01287cd3..a5987513 100644 --- a/src/internfile/txtdcode.cpp +++ b/src/internfile/txtdcode.cpp @@ -121,7 +121,7 @@ bool RecollFilter::txtdcode(const string& who) // utf-8. We check if the text is actually utf-8. This is worth // it, else the conversion from 8-bit is going to succeed if the // text is already utf-8, and produce bogus data. - if (utf8check(itext, otext) >= 0) { + if (utf8check(itext) >= 0) { m_metaData[cstr_dj_keycharset] = cstr_utf8; return true; } diff --git a/src/qtgui/reslist.cpp b/src/qtgui/reslist.cpp index 241bef8e..a3856350 100644 --- a/src/qtgui/reslist.cpp +++ b/src/qtgui/reslist.cpp @@ -1270,6 +1270,13 @@ void ResList::menuCopyFN() ResultPopup::copyFN(doc); } +void ResList::menuCopyPath() +{ + Rcl::Doc doc; + if (getDoc(m_popDoc, doc)) + ResultPopup::copyPath(doc); +} + void ResList::menuCopyText() { Rcl::Doc doc; diff --git a/src/qtgui/reslist.h b/src/qtgui/reslist.h index 5b98119b..dbbce845 100644 --- a/src/qtgui/reslist.h +++ b/src/qtgui/reslist.h @@ -81,6 +81,7 @@ public slots: virtual void menuEdit(); virtual void menuOpenWith(QAction *); virtual void menuCopyFN(); + virtual void menuCopyPath(); virtual void menuCopyURL(); virtual void menuCopyText(); virtual void menuExpand(); diff --git a/src/qtgui/respopup.cpp b/src/qtgui/respopup.cpp index e2528693..1aa0aa56 100644 --- a/src/qtgui/respopup.cpp +++ b/src/qtgui/respopup.cpp @@ -30,6 +30,7 @@ #include "respopup.h" #include "appformime.h" #include "rclmain_w.h" +#include "utf8iter.h" namespace ResultPopup { @@ -95,9 +96,10 @@ QMenu *create(QWidget *me, int opts, std::shared_ptr source, } if (doc.isFsFile()) { - popup->addAction(QWidget::tr("Copy &File Path"), me, SLOT(menuCopyFN())); + popup->addAction(QWidget::tr("Copy &File Path"), me, SLOT(menuCopyPath())); } popup->addAction(QWidget::tr("Copy &URL"), me, SLOT(menuCopyURL())); + popup->addAction(QWidget::tr("Copy File Name"), me, SLOT(menuCopyFN())); popup->addAction(QWidget::tr("Copy Text"), me, SLOT(menuCopyText())); if ((opts&showSaveOne) && !(isFsTop)) @@ -158,24 +160,52 @@ Rcl::Doc getFolder(Rcl::Doc& doc) return pdoc; } +static const std::string twoslash{"//"}; +void copyPath(const Rcl::Doc &doc) +{ + auto pos = doc.url.find(twoslash); + std::string path; + if (pos == std::string::npos) { + path = doc.url; // ?? + } else { + path = doc.url.substr(pos+2); + } + // Problem: setText expects a QString. Passing a (const char*) as + // we used to do causes an implicit conversion from latin1. File + // are binary and the right approach would be no conversion, but + // it's probably better (less worse...) to make a "best effort" + // tentative and try to convert from the locale's charset than + // accept the default conversion. This is unlikely to yield a + // usable path for binary paths in non-utf8 locales though. + QString qpath = path2qs(path); + QApplication::clipboard()->setText(qpath, QClipboard::Selection); + QApplication::clipboard()->setText(qpath, QClipboard::Clipboard); +} + +// This is typically used to add the file name to the query string, so +// we want the values as search terms here, not the binary from the +// url. void copyFN(const Rcl::Doc &doc) { - // Our urls currently always begin with "file://" - // - // Problem: setText expects a QString. Passing a (const char*) - // as we used to do causes an implicit conversion from - // latin1. File are binary and the right approach would be no - // conversion, but it's probably better (less worse...) to - // make a "best effort" tentative and try to convert from the - // locale's charset than accept the default conversion. - QString qfn = path2qs(doc.url.c_str()+7); - QApplication::clipboard()->setText(qfn, QClipboard::Selection); - QApplication::clipboard()->setText(qfn, QClipboard::Clipboard); + std::string fn; + doc.getmeta(Rcl::Doc::keyfn, &fn); + QString qpath = u8s2qs(fn); + QApplication::clipboard()->setText(qpath, QClipboard::Selection); + QApplication::clipboard()->setText(qpath, QClipboard::Clipboard); } void copyURL(const Rcl::Doc &doc) { - QString url = path2qs(doc.url); + QString url; +#ifdef _WIN32 + url = u8s2qs(doc.url); +#else + if (utf8check(doc.url)) { + url = u8s2qs(doc.url); + } else { + url = u8s2qs(url_encode(doc.url)); + } +#endif QApplication::clipboard()->setText(url, QClipboard::Selection); QApplication::clipboard()->setText(url, QClipboard::Clipboard); } diff --git a/src/qtgui/respopup.h b/src/qtgui/respopup.h index 6be65463..88b35f00 100644 --- a/src/qtgui/respopup.h +++ b/src/qtgui/respopup.h @@ -29,6 +29,7 @@ extern Rcl::Doc getParent(std::shared_ptr source, Rcl::Doc& doc); extern Rcl::Doc getFolder(Rcl::Doc& doc); extern void copyFN(const Rcl::Doc &doc); +extern void copyPath(const Rcl::Doc &doc); extern void copyURL(const Rcl::Doc &doc); extern void copyText(Rcl::Doc &doc, RclMain *rclmain=nullptr); }; diff --git a/src/qtgui/restable.cpp b/src/qtgui/restable.cpp index 35680a04..c690fd22 100644 --- a/src/qtgui/restable.cpp +++ b/src/qtgui/restable.cpp @@ -1255,6 +1255,12 @@ void ResTable::menuCopyFN() ResultPopup::copyFN(m_detaildoc); } +void ResTable::menuCopyPath() +{ + if (m_detaildocnum >= 0) + ResultPopup::copyPath(m_detaildoc); +} + void ResTable::menuCopyURL() { if (m_detaildocnum >= 0) diff --git a/src/qtgui/restable.h b/src/qtgui/restable.h index 19415ee8..a1cca9c3 100644 --- a/src/qtgui/restable.h +++ b/src/qtgui/restable.h @@ -169,6 +169,7 @@ public slots: virtual void menuEditAndQuit(); virtual void menuOpenWith(QAction *); virtual void menuCopyFN(); + virtual void menuCopyPath(); virtual void menuCopyURL(); virtual void menuCopyText(); virtual void menuExpand(); diff --git a/src/rcldb/rcldb.cpp b/src/rcldb/rcldb.cpp index b242b801..9676d2a4 100644 --- a/src/rcldb/rcldb.cpp +++ b/src/rcldb/rcldb.cpp @@ -1845,10 +1845,8 @@ bool Db::addOrUpdate(const string &udi, const string &parent_udi, Doc &doc) // purposes. const string *fnp = 0; if (!doc.peekmeta(Rcl::Doc::keyfn, &fnp) || fnp->empty()) { - if (doc.peekmeta(Rcl::Doc::keytcfn, &fnp) && !fnp->empty()) { - string value = - neutchars(truncate_to_word(*fnp, - m_idxMetaStoredLen), cstr_nc); + if (doc.peekmeta(Rcl::Doc::keyctfn, &fnp) && !fnp->empty()) { + string value = neutchars(truncate_to_word(*fnp, m_idxMetaStoredLen), cstr_nc); RECORD_APPEND(record, Rcl::Doc::keyfn, value); } } diff --git a/src/rcldb/rcldoc.cpp b/src/rcldb/rcldoc.cpp index 330ba81d..d622d989 100644 --- a/src/rcldb/rcldoc.cpp +++ b/src/rcldb/rcldoc.cpp @@ -34,7 +34,7 @@ const string Doc::keydmt("dmtime"); const string Doc::keyds("dbytes"); const string Doc::keyfmt("fmtime"); const string Doc::keyfn("filename"); -const string Doc::keytcfn("containerfilename"); +const string Doc::keyctfn("containerfilename"); const string Doc::keyfs("fbytes"); const string Doc::keyipt("ipath"); const string Doc::keykw("keywords"); diff --git a/src/rcldb/rcldoc.h b/src/rcldb/rcldoc.h index f36b66a7..a3b50229 100644 --- a/src/rcldb/rcldoc.h +++ b/src/rcldb/rcldoc.h @@ -233,7 +233,7 @@ public: // given top level container. It is not indexed by default but // stored in the document record keyfn field if this is still // empty when we create it, for display purposes. - static const std::string keytcfn; + static const std::string keyctfn; static const std::string keyipt; // ipath static const std::string keytp; // mime type static const std::string keyfmt; // file mtime diff --git a/src/testmains/trpathut.cpp b/src/testmains/trpathut.cpp index 5b723b42..8d4b4be4 100644 --- a/src/testmains/trpathut.cpp +++ b/src/testmains/trpathut.cpp @@ -13,6 +13,7 @@ static std::map options { {"path_home", 0}, {"path_tildexpand", 0}, {"listdir", 0}, + {"url_encode", 0}, }; static const char *thisprog; @@ -55,19 +56,34 @@ int main(int argc, char **argv) return 1; } string s = argv[optind]; - argc--; + optind++; if (optind != argc) { return 1; } - cout << "path_tildexpand(" << s << ") -> [" << path_tildexpand(s) << - "]\n"; + cout << "path_tildexpand(" << s << ") -> [" << path_tildexpand(s) << "]\n"; + } else if (options["url_encode"]) { + if (optind >= argc) { + cerr << "Usage: trsmallut --url_encode [offs=0]\n"; + return 1; + } + string s = argv[optind]; + optind++; + int offs = 0; + if (optind != argc) { + offs = atoi(argv[optind]); + optind++; + } + if (optind != argc) { + return 1; + } + cout << "url_encode(" << s << ", " << offs << ") -> [" << url_encode(s, offs) << "]\n"; } else if (options["listdir"]) { if (optind >= argc) { cerr << "Usage: trsmallut --listdir \n"; return 1; } std::string path = argv[optind]; - argc--; + optind++; if (optind != argc) { cerr << "Usage: trsmallut --listdir \n"; return 1; diff --git a/src/utils/utf8iter.cpp b/src/utils/utf8iter.cpp index 7d588319..0a5bfeaf 100644 --- a/src/utils/utf8iter.cpp +++ b/src/utils/utf8iter.cpp @@ -94,7 +94,7 @@ size_t utf8len(const string& s) static const std::string replchar{"\xef\xbf\xbd"}; // Check utf-8 encoding, replacing errors with the ? char above -int utf8check(const std::string& in, std::string& out, bool fixit, int maxrepl) +int utf8check(const std::string& in, bool fixit, std::string *out, int maxrepl) { int cnt = 0; Utf8Iter it(in); @@ -103,7 +103,7 @@ int utf8check(const std::string& in, std::string& out, bool fixit, int maxrepl) if (!fixit) { return -1; } - out += replchar; + *out += replchar; ++cnt; for (; cnt < maxrepl; cnt++) { it.retryfurther(); @@ -111,7 +111,7 @@ int utf8check(const std::string& in, std::string& out, bool fixit, int maxrepl) return cnt; if (!it.error()) break; - out += replchar; + *out += replchar; } if (it.error()) { return -1; @@ -119,7 +119,7 @@ int utf8check(const std::string& in, std::string& out, bool fixit, int maxrepl) } // We have reached a good char and eof is false if (fixit) { - it.appendchartostring(out); + it.appendchartostring(*out); } } return cnt; diff --git a/src/utils/utf8iter.h b/src/utils/utf8iter.h index c1c05609..22651787 100644 --- a/src/utils/utf8iter.h +++ b/src/utils/utf8iter.h @@ -305,6 +305,6 @@ size_t utf8len(const std::string& s); * 0 or positive: replacement count. */ int utf8check( - const std::string& in, std::string& out, bool fixit=false, int maxrepl=100); + const std::string& in, bool fixit=false, std::string* out = nullptr, int maxrepl=100); #endif /* _UTF8ITER_H_INCLUDED_ */