diff --git a/src/qtgui/reslist.cpp b/src/qtgui/reslist.cpp index 70faf119..916da284 100644 --- a/src/qtgui/reslist.cpp +++ b/src/qtgui/reslist.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 J.F.Dockes +/* Copyright (C) 2005-2020 J.F.Dockes * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -545,19 +545,18 @@ pair ResList::parnumfromdocnum(int docnum) LOGDEB("parnumfromdocnum: docnum " << docnum << "\n"); if (m_pager->pageNumber() < 0) { LOGDEB("parnumfromdocnum: no page return -1,-1\n"); - return pair(-1,-1); + return {-1, -1}; } int winfirst = pageFirstDocNum(); if (docnum - winfirst < 0) { LOGDEB("parnumfromdocnum: docnum " << docnum << " < winfirst " << winfirst << " return -1,-1\n"); - return pair(-1,-1); + return {-1, -1}; } docnum -= winfirst; - for (std::map::iterator it = m_pageParaToReldocnums.begin(); - it != m_pageParaToReldocnums.end(); it++) { - if (docnum == it->second) { - int first = it->first; + for (const auto& entry : m_pageParaToReldocnums.begin()) { + if (docnum == entry.second) { + int first = entry.first; int last = first+1; std::map::iterator it1; while ((it1 = m_pageParaToReldocnums.find(last)) != @@ -565,11 +564,11 @@ pair ResList::parnumfromdocnum(int docnum) last++; } LOGDEB("parnumfromdocnum: return " << first << "," << last << "\n"); - return pair(first, last); + return {first, last}; } } LOGDEB("parnumfromdocnum: not found return -1,-1\n"); - return pair(-1,-1); + return {-1,-1}; } #endif // TEXTBROWSER @@ -1180,8 +1179,23 @@ void ResList::menuPreviewParent() void ResList::menuOpenParent() { Rcl::Doc doc; - if (getDoc(m_popDoc, doc) && m_source) - emit editRequested(ResultPopup::getParent(m_source, doc)); + if (getDoc(m_popDoc, doc) && m_source) { + Rcl::Doc pdoc = ResultPopup::getParent(m_source, doc); + if (!pdoc.url.empty()) { + emit editRequested(pdoc); + } + } +} + +void ResList::menuOpenFolder() +{ + Rcl::Doc doc; + if (getDoc(m_popDoc, doc) && m_source) { + Rcl::Doc pdoc = ResultPopup::getFolder(m_source, doc); + if (!pdoc.url.empty()) { + emit editRequested(pdoc); + } + } } void ResList::menuShowSnippets() diff --git a/src/qtgui/reslist.h b/src/qtgui/reslist.h index 5c02c88f..ece5efda 100644 --- a/src/qtgui/reslist.h +++ b/src/qtgui/reslist.h @@ -85,6 +85,7 @@ public slots: virtual void menuExpand(); virtual void menuPreviewParent(); virtual void menuOpenParent(); + virtual void menuOpenFolder(); virtual void menuShowSnippets(); virtual void menuShowSubDocs(); virtual void previewExposed(int); diff --git a/src/qtgui/respopup.cpp b/src/qtgui/respopup.cpp index 7feb93f1..817edf34 100644 --- a/src/qtgui/respopup.cpp +++ b/src/qtgui/respopup.cpp @@ -1,4 +1,5 @@ -/* +/* Copyright (C) 2005-2020 J.F.Dockes + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -43,34 +44,25 @@ QMenu *create(QWidget *me, int opts, std::shared_ptr source, string apptag; doc.getmeta(Rcl::Doc::keyapptg, &apptag); + // Is this a top level file system file (accessible by regular utilities)? + bool isFsTop = doc.ipath.empty() && doc.isFsFile(); + popup->addAction(QWidget::tr("&Preview"), me, SLOT(menuPreview())); if (!theconfig->getMimeViewerDef(doc.mimetype, apptag, 0).empty()) { popup->addAction(QWidget::tr("&Open"), me, SLOT(menuEdit())); } - 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; + if (isFsTop) { + // Openable by regular program. Add "open with" entry. + vector apps; DesktopDb *ddb = DesktopDb::getDb(); - if (ddb && ddb->appForMime(doc.mimetype, &aps) && - !aps.empty()) { + if (ddb && ddb->appForMime(doc.mimetype, &apps) && !apps.empty()) { QMenu *sub = popup->addMenu(QWidget::tr("Open With")); if (sub) { - for (vector::const_iterator it = aps.begin(); - it != aps.end(); it++) { - QAction *act = new - QAction(QString::fromUtf8(it->name.c_str()), me); - QVariant v(QString::fromUtf8(it->command.c_str())); + for (const auto& app : apps) { + QAction *act = new QAction(u8s2qs(app.name), me); + QVariant v(u8s2qs(app.command)); act->setData(v); sub->addAction(act); } @@ -81,16 +73,14 @@ QMenu *create(QWidget *me, int opts, std::shared_ptr source, // See if there are any desktop files in $RECOLL_CONFDIR/scripts // and possibly create a "run script" menu. - aps.clear(); + apps.clear(); ddb = new DesktopDb(path_cat(theconfig->getConfDir(), "scripts")); - if (ddb && ddb->allApps(&aps) && !aps.empty()) { + if (ddb && ddb->allApps(&apps) && !apps.empty()) { QMenu *sub = popup->addMenu(QWidget::tr("Run Script")); if (sub) { - for (vector::const_iterator it = aps.begin(); - it != aps.end(); it++) { - QAction *act = new - QAction(QString::fromUtf8(it->name.c_str()), me); - QVariant v(QString::fromUtf8(it->command.c_str())); + for (const auto& app : apps) { + QAction *act = new QAction(u8s2qs(app.name), me); + QVariant v(u8s2qs(app.command)); act->setData(v); sub->addAction(act); } @@ -101,27 +91,34 @@ QMenu *create(QWidget *me, int opts, std::shared_ptr source, delete ddb; } - popup->addAction(QWidget::tr("Copy &File Name"), me, SLOT(menuCopyFN())); + if (doc.isFsFile()) { + popup->addAction(QWidget::tr("Copy &File Name"), me, SLOT(menuCopyFN())); + } popup->addAction(QWidget::tr("Copy &URL"), me, SLOT(menuCopyURL())); - if ((opts&showSaveOne) && (!doc.isFsFile() || !doc.ipath.empty())) - popup->addAction(QWidget::tr("&Write to File"), me, + if ((opts&showSaveOne) && !(isFsTop)) + popup->addAction(QWidget::tr("&Write to File"), me, SLOT(menuSaveToFile())); if ((opts&showSaveSel)) popup->addAction(QWidget::tr("Save selection to files"), me, SLOT(menuSaveSelection())); + + // We now separate preview/open parent, which only makes sense for + // an embedded doc, and open folder (which was previously done if + // the doc was a top level file and was not accessible else). Rcl::Doc pdoc; - if (source && source->getEnclosing(doc, pdoc)) { + bool isEnclosed = source && source->getEnclosing(doc, pdoc); + if (isEnclosed) { popup->addAction(QWidget::tr("Preview P&arent document/folder"), me, SLOT(menuPreviewParent())); - } - // Open parent is useful even if there is no parent because we open - // the enclosing folder. - if (doc.isFsFile()) - popup->addAction(QWidget::tr("&Open Parent document/folder"), + popup->addAction(QWidget::tr("&Open Parent document"), me, SLOT(menuOpenParent())); + } + if (doc.isFsFile()) + popup->addAction(QWidget::tr("&Open Parent Folder"), + me, SLOT(menuOpenFolder())); if (opts & showExpand) popup->addAction(QWidget::tr("Find &similar documents"), @@ -141,17 +138,22 @@ QMenu *create(QWidget *me, int opts, std::shared_ptr source, Rcl::Doc getParent(std::shared_ptr source, Rcl::Doc& doc) { Rcl::Doc pdoc; - if (!source || !source->getEnclosing(doc, pdoc)) { - // No parent doc: show enclosing folder with app configured for - // directories - pdoc.url = url_parentfolder(doc.url); - pdoc.meta[Rcl::Doc::keychildurl] = doc.url; - pdoc.meta[Rcl::Doc::keyapptg] = "parentopen"; - pdoc.mimetype = "inode/directory"; + if (source) { + source->getEnclosing(doc, pdoc); } return pdoc; } +Rcl::Doc getFolder(std::shared_ptr, Rcl::Doc& doc) +{ + Rcl::Doc pdoc; + pdoc.url = url_parentfolder(doc.url); + pdoc.meta[Rcl::Doc::keychildurl] = doc.url; + pdoc.meta[Rcl::Doc::keyapptg] = "parentopen"; + pdoc.mimetype = "inode/directory"; + return pdoc; +} + void copyFN(const Rcl::Doc &doc) { // Our urls currently always begin with "file://" diff --git a/src/qtgui/respopup.h b/src/qtgui/respopup.h index d7976f0d..6757cd93 100644 --- a/src/qtgui/respopup.h +++ b/src/qtgui/respopup.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 J.F.Dockes +/* Copyright (C) 2006-2020 J.F.Dockes * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -19,15 +19,17 @@ #include "autoconfig.h" namespace ResultPopup { - enum Options {showExpand = 0x1, showSubs = 0x2, isMain = 0x3, - showSaveOne = 0x4, showSaveSel = 0x8}; - extern QMenu *create(QWidget *me, int opts, - std::shared_ptr source, - Rcl::Doc& doc); - extern Rcl::Doc getParent(std::shared_ptr source, - Rcl::Doc& doc); - extern void copyFN(const Rcl::Doc &doc); - extern void copyURL(const Rcl::Doc &doc); +enum Options {showExpand = 0x1, showSubs = 0x2, isMain = 0x3, + showSaveOne = 0x4, showSaveSel = 0x8}; +extern QMenu *create(QWidget *me, int opts, + std::shared_ptr source, + Rcl::Doc& doc); +extern Rcl::Doc getParent(std::shared_ptr source, + Rcl::Doc& doc); +extern Rcl::Doc getFolder(std::shared_ptr source, + Rcl::Doc& doc); +extern void copyFN(const Rcl::Doc &doc); +extern void copyURL(const Rcl::Doc &doc); }; #endif /* _RESPOPUP_H_INCLUDED_ */ diff --git a/src/qtgui/restable.cpp b/src/qtgui/restable.cpp index 0a6f8400..00840b09 100644 --- a/src/qtgui/restable.cpp +++ b/src/qtgui/restable.cpp @@ -1,4 +1,4 @@ -/* +/* Copyright (C) 2005-2020 J.F.Dockes * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -247,11 +247,10 @@ RecollModel::RecollModel(const QStringList fields, ResTable *tb, // could be protected to be done only once, but it's no real // problem if (theconfig) { - const set& stored = theconfig->getStoredFields(); - for (set::const_iterator it = stored.begin(); - it != stored.end(); it++) { - if (o_displayableFields.find(*it) == o_displayableFields.end()) { - o_displayableFields[*it] = QString::fromUtf8(it->c_str()); + const auto& stored = theconfig->getStoredFields(); + for (const auto& field : stored) { + if (o_displayableFields.find(field) == o_displayableFields.end()) { + o_displayableFields[field] = u8s2qs(field); } } } @@ -1003,9 +1002,24 @@ void ResTable::menuPreviewParent() void ResTable::menuOpenParent() { - if (m_detaildocnum >= 0 && m_model && m_model->getDocSource()) - emit editRequested( - ResultPopup::getParent(m_model->getDocSource(), m_detaildoc)); + if (m_detaildocnum >= 0 && m_model && m_model->getDocSource()) { + Rcl::Doc pdoc = + ResultPopup::getParent(m_model->getDocSource(), m_detaildoc); + if (!pdoc.url.empty()) { + emit editRequested(pdoc); + } + } +} + +void ResTable::menuOpenFolder() +{ + if (m_detaildocnum >= 0 && m_model && m_model->getDocSource()) { + Rcl::Doc pdoc = + ResultPopup::getFolder(m_model->getDocSource(), m_detaildoc); + if (!pdoc.url.empty()) { + emit editRequested(pdoc); + } + } } void ResTable::menuEdit() @@ -1085,12 +1099,11 @@ void ResTable::createHeaderPopupMenu(const QPoint& pos) popup->addSeparator(); QAction *act; - for (map::const_iterator it = allfields.begin(); - it != allfields.end(); it++) { - if (std::find(fields.begin(), fields.end(), it->first) != fields.end()) + for (const auto& field : allfields) { + if (std::find(fields.begin(), fields.end(), field.first) != fields.end()) continue; - act = new QAction(tr("Add \"%1\" column").arg(it->second), popup); - act->setData(QString::fromUtf8(it->first.c_str())); + act = new QAction(tr("Add \"%1\" column").arg(field.second), popup); + act->setData(u8s2qs(field.first)); connect(act, SIGNAL(triggered(bool)), this , SLOT(addColumn())); popup->addAction(act); } diff --git a/src/qtgui/restable.h b/src/qtgui/restable.h index 481546f2..2623bff8 100644 --- a/src/qtgui/restable.h +++ b/src/qtgui/restable.h @@ -148,6 +148,7 @@ public slots: virtual void menuExpand(); virtual void menuPreviewParent(); virtual void menuOpenParent(); + virtual void menuOpenFolder(); virtual void menuShowSnippets(); virtual void menuShowSubDocs(); virtual void createHeaderPopupMenu(const QPoint&); diff --git a/src/query/docseq.cpp b/src/query/docseq.cpp index ee5f389b..81aa688e 100644 --- a/src/query/docseq.cpp +++ b/src/query/docseq.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 J.F.Dockes +/* Copyright (C) 2005-2020 J.F.Dockes * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -30,11 +30,11 @@ int DocSequence::getSeqSlice(int offs, int cnt, vector& result) { int ret = 0; for (int num = offs; num < offs + cnt; num++, ret++) { - result.push_back(ResListEntry()); - if (!getDoc(num, result.back().doc, &result.back().subHeader)) { - result.pop_back(); - return ret; - } + result.push_back(ResListEntry()); + if (!getDoc(num, result.back().doc, &result.back().subHeader)) { + result.pop_back(); + return ret; + } } return ret; } @@ -43,8 +43,8 @@ bool DocSequence::getEnclosing(Rcl::Doc& doc, Rcl::Doc& pdoc) { std::shared_ptr db = getDb(); if (!db) { - LOGERR("DocSequence::getEnclosing: no db\n" ); - return false; + LOGERR("DocSequence::getEnclosing: no db\n" ); + return false; } std::unique_lock locker(o_dblock); string udi; @@ -59,9 +59,9 @@ bool DocSequence::getEnclosing(Rcl::Doc& doc, Rcl::Doc& pdoc) void DocSource::stripStack() { if (!m_seq) - return; + return; while (m_seq->getSourceSeq()) { - m_seq = m_seq->getSourceSeq(); + m_seq = m_seq->getSourceSeq(); } } @@ -71,29 +71,29 @@ bool DocSource::buildStack() stripStack(); if (!m_seq) - return false; + return false; // Filtering must be done before sorting, (which may // truncates the original list) if (m_seq->canFilter()) { - if (!m_seq->setFiltSpec(m_fspec)) { - LOGERR("DocSource::buildStack: setfiltspec failed\n" ); - } + if (!m_seq->setFiltSpec(m_fspec)) { + LOGERR("DocSource::buildStack: setfiltspec failed\n" ); + } } else { - if (m_fspec.isNotNull()) { - m_seq = - std::shared_ptr(new DocSeqFiltered(m_config, m_seq, m_fspec)); - } + if (m_fspec.isNotNull()) { + m_seq = + std::shared_ptr(new DocSeqFiltered(m_config, m_seq, m_fspec)); + } } if (m_seq->canSort()) { - if (!m_seq->setSortSpec(m_sspec)) { - LOGERR("DocSource::buildStack: setsortspec failed\n" ); - } + if (!m_seq->setSortSpec(m_sspec)) { + LOGERR("DocSource::buildStack: setsortspec failed\n" ); + } } else { - if (m_sspec.isNotNull()) { - m_seq = std::shared_ptr(new DocSeqSorted(m_seq, m_sspec)); - } + if (m_sspec.isNotNull()) { + m_seq = std::shared_ptr(new DocSeqSorted(m_seq, m_sspec)); + } } return true; } @@ -101,14 +101,14 @@ bool DocSource::buildStack() string DocSource::title() { if (!m_seq) - return string(); + return string(); string qual; if (m_fspec.isNotNull() && !m_sspec.isNotNull()) - qual = string(" (") + o_filt_trans + string(")"); + qual = string(" (") + o_filt_trans + string(")"); else if (!m_fspec.isNotNull() && m_sspec.isNotNull()) - qual = string(" (") + o_sort_trans + string(")"); + qual = string(" (") + o_sort_trans + string(")"); else if (m_fspec.isNotNull() && m_sspec.isNotNull()) - qual = string(" (") + o_sort_trans + string(",") + o_filt_trans + string(")"); + qual = string(" (") + o_sort_trans + string(",") + o_filt_trans + string(")"); return m_seq->title() + qual; } @@ -127,5 +127,3 @@ bool DocSource::setSortSpec(const DocSeqSortSpec &s) buildStack(); return true; } - - diff --git a/src/query/docseq.h b/src/query/docseq.h index 1bcdc225..dd998456 100644 --- a/src/query/docseq.h +++ b/src/query/docseq.h @@ -114,39 +114,37 @@ public: return false; } + /** For an embedded document: get the immediately enclosing doc + * (e.g., for an attachment, the message it is attached to. Only + * makes sense is ipath is not empty. */ virtual bool getEnclosing(Rcl::Doc&, Rcl::Doc&); /** Get estimated total count in results */ virtual int getResCnt() = 0; /** Get title for result list */ - virtual std::string title() - { - return m_title; - } + virtual std::string title() { + return m_title; + } /** Can do snippets ? */ - virtual bool snippetsCapable() - { - return false; - } + virtual bool snippetsCapable() { + return false; + } /** Get description for underlying query */ virtual std::string getDescription() = 0; /** Get search terms (for highlighting abstracts). Some sequences * may have no associated search terms. Implement this for them. */ - virtual void getTerms(HighlightData& hld) - { - hld.clear(); - } - virtual std::list expand(Rcl::Doc &) - { - return std::list(); - } - virtual std::string getReason() - { - return m_reason; - } + virtual void getTerms(HighlightData& hld) { + hld.clear(); + } + virtual std::list expand(Rcl::Doc &) { + return std::list(); + } + virtual std::string getReason() { + return m_reason; + } /** Optional functionality. */ virtual bool canFilter() {return false;} virtual bool canSort() {return false;} diff --git a/src/rcldb/rcldoc.h b/src/rcldb/rcldoc.h index 4f7325f0..d6f56fc2 100644 --- a/src/rcldb/rcldoc.h +++ b/src/rcldb/rcldoc.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2006 J.F.Dockes +/* Copyright (C) 2006-2020 J.F.Dockes * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -205,9 +205,8 @@ public: return true; } - /* Is this document stored as a regular filesystem file ? - * (as opposed to e.g. a webcache file), not a subdoc, - */ + /* Is this document stored in a regular filesystem file ? + * (as opposed to e.g. a webcache file). */ bool isFsFile() { std::string backend; getmeta(keybcknd, &backend);