From 96dba3a3eef86eeb2d183dbd48db11eefa752339 Mon Sep 17 00:00:00 2001 From: dockes Date: Fri, 6 Nov 2009 11:33:32 +0000 Subject: [PATCH] allow opening parent/enclosing doc with native editor in reslist --- src/internfile/internfile.cpp | 6 ++- src/internfile/internfile.h | 2 +- src/qtgui/rclmain_w.cpp | 4 +- src/qtgui/reslist.cpp | 69 +++++++++++++++++++++++------------ src/qtgui/reslist.h | 3 +- src/query/docseq.h | 2 + src/query/docseqdb.cpp | 10 +++++ src/query/docseqdb.h | 1 + src/query/docseqhist.cpp | 10 +++++ src/query/docseqhist.h | 1 + src/utils/fileudi.h | 5 +-- src/utils/pathut.cpp | 36 ++++++++++++++---- src/utils/pathut.h | 7 +++- 13 files changed, 116 insertions(+), 40 deletions(-) diff --git a/src/internfile/internfile.cpp b/src/internfile/internfile.cpp index f931e9b6..602c4092 100644 --- a/src/internfile/internfile.cpp +++ b/src/internfile/internfile.cpp @@ -44,6 +44,8 @@ using namespace std; #include "wipedir.h" #include "rclconfig.h" #include "mh_html.h" +#include "fileudi.h" + #ifdef RCL_USE_XATTR #include "pxattr.h" #endif // RCL_USE_XATTR @@ -85,7 +87,7 @@ void FileInterner::reapXAttrs(const string& path) // This is used when the user wants to retrieve a search result doc's parent // (ie message having a given attachment) bool FileInterner::getEnclosing(const string &url, const string &ipath, - string &eurl, string &eipath) + string &eurl, string &eipath, string& udi) { eurl = url; eipath = ipath; @@ -98,6 +100,8 @@ bool FileInterner::getEnclosing(const string &url, const string &ipath, } else { eipath.erase(); } + make_udi(url_gpath(eurl), eipath, udi); + LOGDEB(("FileInterner::getEnclosing() after: [%s]\n", eipath.c_str())); return true; } diff --git a/src/internfile/internfile.h b/src/internfile/internfile.h index e09c9d68..98e3a912 100644 --- a/src/internfile/internfile.h +++ b/src/internfile/internfile.h @@ -53,7 +53,7 @@ class FileInterner { * with Rcl::Db::addOrUpdate(). The latter is generally the enclosing file. */ static bool getEnclosing(const string &url, const string &ipath, - string &eurl, string &eipath); + string &eurl, string &eipath, string& udi); /** * Identify and possibly decompress file, create adequate * handler. The mtype parameter is only set when the object is diff --git a/src/qtgui/rclmain_w.cpp b/src/qtgui/rclmain_w.cpp index 52966c1c..2b8b50ed 100644 --- a/src/qtgui/rclmain_w.cpp +++ b/src/qtgui/rclmain_w.cpp @@ -929,8 +929,8 @@ void RclMain::startNativeViewer(Rcl::Doc doc) if (cmd.length() == 0) { QMessageBox::warning(0, "Recoll", - tr("No external viewer configured for mime type ") - + doc.mimetype.c_str()); + tr("No external viewer configured for mime type [") + + doc.mimetype.c_str() + "]"); return; } diff --git a/src/qtgui/reslist.cpp b/src/qtgui/reslist.cpp index cf01b66a..fa9deeb8 100644 --- a/src/qtgui/reslist.cpp +++ b/src/qtgui/reslist.cpp @@ -91,6 +91,22 @@ ResList::ResList(QWidget* parent, const char* name) ResList::~ResList() { + // These have to exist somewhere for translations to work +#ifdef __GNUC__ + __attribute__((unused)) +#endif + static const char* strings[] = { + QT_TR_NOOP("

No results found
"), + QT_TR_NOOP("Documents %d-%d out of at least %d for "), + QT_TR_NOOP("Documents %d-%d for "), + QT_TR_NOOP("Previous"), + QT_TR_NOOP("Next"), + QT_TR_NOOP("Unavailable document"), + QT_TR_NOOP("Preview"), + QT_TR_NOOP("Open"), + QT_TR_NOOP("(show query)"), + }; + } int ResList::newListId() @@ -346,18 +362,6 @@ void ResList::resultPageFirst() void ResList::append(const QString &text) { - // These has to go somewhere for translations to work - static const char* strings[] = { - QT_TR_NOOP("

No results found
"), - QT_TR_NOOP("Documents %d-%d out of at least %d for "), - QT_TR_NOOP("Documents %d-%d for "), - QT_TR_NOOP("Previous"), - QT_TR_NOOP("Next"), - QT_TR_NOOP("Unavailable document"), - QT_TR_NOOP("Preview"), - QT_TR_NOOP("Open"), - QT_TR_NOOP("(show query)"), - }; QTEXTBROWSER::append(text); #if 0 { @@ -565,12 +569,14 @@ RCLPOPUP *ResList::createPopupMenu(const QPoint& pos) popup->insertItem(tr("Copy &URL"), this, SLOT(menuCopyURL())); Rcl::Doc doc; if (getDoc(m_popDoc, doc) && !doc.ipath.empty()) { - popup->insertItem(tr("Save to File"), this, SLOT(menuSaveToFile())); + popup->insertItem(tr("&Write to File"), this, SLOT(menuSaveToFile())); } popup->insertItem(tr("Find &similar documents"), this, SLOT(menuExpand())); - popup->insertItem(tr("P&arent document/folder"), - this, SLOT(menuSeeParent())); + popup->insertItem(tr("Preview P&arent document/folder"), + this, SLOT(menuPreviewParent())); + popup->insertItem(tr("&Open Parent document/folder"), + this, SLOT(menuOpenParent())); return popup; } @@ -583,20 +589,37 @@ void ResList::menuSaveToFile() emit docSaveToFileClicked(m_popDoc); } -void ResList::menuSeeParent() +void ResList::menuPreviewParent() { Rcl::Doc doc; - if (!getDoc(m_popDoc, doc)) + if (!getDoc(m_popDoc, doc) || m_baseDocSource.isNull()) return; - Rcl::Doc doc1; - if (FileInterner::getEnclosing(doc.url, doc.ipath, doc1.url, doc1.ipath)) { - emit previewRequested(doc1); + Rcl::Doc pdoc; + if (m_baseDocSource->getEnclosing(doc, pdoc)) { + emit previewRequested(pdoc); } else { // No parent doc: show enclosing folder with app configured for // directories - doc1.url = path_getfather(doc.url); - doc1.mimetype = "application/x-fsdirectory"; - emit editRequested(doc1); + pdoc.url = path_getfather(doc.url); + pdoc.mimetype = "application/x-fsdirectory"; + emit editRequested(pdoc); + } +} + +void ResList::menuOpenParent() +{ + Rcl::Doc doc; + if (!getDoc(m_popDoc, doc) || m_baseDocSource.isNull()) + return; + Rcl::Doc pdoc; + if (m_baseDocSource->getEnclosing(doc, pdoc)) { + emit editRequested(pdoc); + } else { + // No parent doc: show enclosing folder with app configured for + // directories + pdoc.url = path_getfather(doc.url); + pdoc.mimetype = "application/x-fsdirectory"; + emit editRequested(pdoc); } } diff --git a/src/qtgui/reslist.h b/src/qtgui/reslist.h index 941ba001..63bbce6c 100644 --- a/src/qtgui/reslist.h +++ b/src/qtgui/reslist.h @@ -95,7 +95,8 @@ class ResList : public QTEXTBROWSER virtual void menuCopyFN(); virtual void menuCopyURL(); virtual void menuExpand(); - virtual void menuSeeParent(); + virtual void menuPreviewParent(); + virtual void menuOpenParent(); virtual void previewExposed(int); virtual void append(const QString &text); // Only used for qt ver >=4 but seems we cant undef it diff --git a/src/query/docseq.h b/src/query/docseq.h index 167c70b3..3d2ed475 100644 --- a/src/query/docseq.h +++ b/src/query/docseq.h @@ -104,6 +104,8 @@ class DocSequence { return doc.meta[Rcl::Doc::keyabs]; } + virtual bool getEnclosing(Rcl::Doc&, Rcl::Doc&) {return false;} + /** Get estimated total count in results */ virtual int getResCnt() = 0; diff --git a/src/query/docseqdb.cpp b/src/query/docseqdb.cpp index 2512fa82..e36dd385 100644 --- a/src/query/docseqdb.cpp +++ b/src/query/docseqdb.cpp @@ -23,6 +23,7 @@ static char rcsid[] = "@(#$Id: docseqdb.cpp,v 1.9 2008-11-13 10:57:46 dockes Exp #include "docseqdb.h" #include "rcldb.h" #include "debuglog.h" +#include "internfile.h" DocSequenceDb::DocSequenceDb(RefCntr q, const string &t, RefCntr sdata) @@ -78,6 +79,15 @@ string DocSequenceDb::getAbstract(Rcl::Doc &doc) return abstract.empty() ? doc.meta[Rcl::Doc::keyabs] : abstract; } +bool DocSequenceDb::getEnclosing(Rcl::Doc& doc, Rcl::Doc& pdoc) +{ + string udi; + if (!FileInterner::getEnclosing(doc.url, doc.ipath, pdoc.url, pdoc.ipath, + udi)) + return false; + return m_q->whatDb()->getDoc(udi, pdoc); +} + list DocSequenceDb::expand(Rcl::Doc &doc) { return m_q->expand(doc); diff --git a/src/query/docseqdb.h b/src/query/docseqdb.h index d7fa224e..ba733620 100644 --- a/src/query/docseqdb.h +++ b/src/query/docseqdb.h @@ -36,6 +36,7 @@ class DocSequenceDb : public DocSequence { vector >& groups, vector& gslks); virtual string getAbstract(Rcl::Doc &doc); + virtual bool getEnclosing(Rcl::Doc& doc, Rcl::Doc& pdoc); virtual string getDescription(); virtual list expand(Rcl::Doc &doc); virtual bool canFilter() {return true;} diff --git a/src/query/docseqhist.cpp b/src/query/docseqhist.cpp index 56094bb5..d661ddb6 100644 --- a/src/query/docseqhist.cpp +++ b/src/query/docseqhist.cpp @@ -24,6 +24,7 @@ static char rcsid[] = "@(#$Id: docseqhist.cpp,v 1.4 2008-09-29 08:59:20 dockes E #include "docseqhist.h" #include "rcldb.h" #include "fileudi.h" +#include "internfile.h" bool DocSequenceHistory::getDoc(int num, Rcl::Doc &doc, string *sh) { @@ -66,6 +67,15 @@ bool DocSequenceHistory::getDoc(int num, Rcl::Doc &doc, string *sh) return ret; } +bool DocSequenceHistory::getEnclosing(Rcl::Doc& doc, Rcl::Doc& pdoc) +{ + string udi; + if (!FileInterner::getEnclosing(doc.url, doc.ipath, pdoc.url, pdoc.ipath, + udi)) + return false; + return m_db->getDoc(udi, pdoc); +} + int DocSequenceHistory::getResCnt() { if (m_hlist.empty()) diff --git a/src/query/docseqhist.h b/src/query/docseqhist.h index a9ea8f63..c3ee72ce 100644 --- a/src/query/docseqhist.h +++ b/src/query/docseqhist.h @@ -35,6 +35,7 @@ class DocSequenceHistory : public DocSequence { virtual ~DocSequenceHistory() {} virtual bool getDoc(int num, Rcl::Doc &doc, string *sh = 0); + virtual bool getEnclosing(Rcl::Doc& doc, Rcl::Doc& pdoc); virtual int getResCnt(); virtual string getDescription() {return m_description;} void setDescription(const string& desc) {m_description = desc;} diff --git a/src/utils/fileudi.h b/src/utils/fileudi.h index 368ae1d5..bcfcbaac 100644 --- a/src/utils/fileudi.h +++ b/src/utils/fileudi.h @@ -24,9 +24,8 @@ using std::string; // indexer). Document Ids are built from a concatenation of the file // path and the internal path (ie: email number inside // folder/attachment number/etc.) As the size of Xapian terms is -// limited, the path is truncated to a maximum length, and completed -// by a hash of the remainder. So the unique id looks like: -// /some/truncated/paHASHVALUE|ipath +// limited, the Id path is truncated to a maximum length, and completed +// by a hash of the remainder (including the ipath) extern void make_udi(const string& fn, const string& ipath, string &udi); diff --git a/src/utils/pathut.cpp b/src/utils/pathut.cpp index b13935ec..5613a492 100644 --- a/src/utils/pathut.cpp +++ b/src/utils/pathut.cpp @@ -176,13 +176,13 @@ TempFileInternal::~TempFileInternal() } -void path_catslash(std::string &s) { +void path_catslash(string &s) { if (s.empty() || s[s.length() - 1] != '/') s += '/'; } -std::string path_cat(const std::string &s1, const std::string &s2) { - std::string res = s1; +string path_cat(const string &s1, const string &s2) { + string res = s1; path_catslash(res); res += s2; return res; @@ -274,7 +274,7 @@ extern string path_tildexpand(const string &s) return o; } -extern std::string path_absolute(const std::string &is) +extern string path_absolute(const string &is) { if (is.length() == 0) return is; @@ -290,7 +290,7 @@ extern std::string path_absolute(const std::string &is) } #include -extern std::string path_canon(const std::string &is) +extern string path_canon(const string &is) { if (is.length() == 0) return is; @@ -330,8 +330,8 @@ extern std::string path_canon(const std::string &is) #include #include -list path_dirglob(const std::string &dir, - const std::string pattern) +list path_dirglob(const string &dir, + const string pattern) { list res; glob_t mglob; @@ -356,7 +356,7 @@ bool path_isdir(const string& path) return false; } -std::string url_encode(const std::string url, string::size_type offs) +string url_encode(const string& url, string::size_type offs) { string out = url.substr(0, offs); const char *cp = url.c_str(); @@ -392,6 +392,26 @@ std::string url_encode(const std::string url, string::size_type offs) return out; } +string url_gpath(const string& url) +{ + // Remove the access schema part (or whatever it's called) + string::size_type colon = url.find_first_of(":"); + if (colon == string::npos || colon == url.size() - 1) + return url; + // If there are non-alphanum chars before the ':', then there + // probably is no scheme. Whatever... + for (string::size_type i = 0; i < colon; i++) { + if (!isalnum(url.at(i))) + return url; + } + + // In addition we canonize the path to remove empty host parts + // (for compatibility with older versions of recoll where file:// + // was hardcoded, but the local path was used for doc + // identification. + return path_canon(url.substr(colon+1)); +} + // Printable url: this is used to transcode from the system charset // into either utf-8 if transcoding succeeds, or url-encoded bool printableUrl(const string &fcharset, const string &in, string &out) diff --git a/src/utils/pathut.h b/src/utils/pathut.h index ef602ee1..abd5e7a7 100644 --- a/src/utils/pathut.h +++ b/src/utils/pathut.h @@ -50,11 +50,16 @@ extern string path_canon(const string &s); extern list path_dirglob(const string &dir, const string pattern); /// Encode according to rfc 1738 -extern string url_encode(const string url, +extern string url_encode(const string& url, string::size_type offs = 0); +/// Transcode to utf-8 if possible or url encoding, for display. extern bool printableUrl(const string &fcharset, const string &in, string &out); +/// Return the host+path part of an url. This is not a general +/// routine, it does the right thing only in the recoll context +extern string url_gpath(const string& url); + /// Stat parameter and check if it's a directory extern bool path_isdir(const string& path);