GUI: create separate popup menu entries for open parent and open folder

This commit is contained in:
Jean-Francois Dockes 2020-07-16 10:25:26 +02:00
parent b4306b71c0
commit 3948f9bd33
9 changed files with 160 additions and 132 deletions

View File

@ -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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -545,19 +545,18 @@ pair<int,int> ResList::parnumfromdocnum(int docnum)
LOGDEB("parnumfromdocnum: docnum " << docnum << "\n"); LOGDEB("parnumfromdocnum: docnum " << docnum << "\n");
if (m_pager->pageNumber() < 0) { if (m_pager->pageNumber() < 0) {
LOGDEB("parnumfromdocnum: no page return -1,-1\n"); LOGDEB("parnumfromdocnum: no page return -1,-1\n");
return pair<int,int>(-1,-1); return {-1, -1};
} }
int winfirst = pageFirstDocNum(); int winfirst = pageFirstDocNum();
if (docnum - winfirst < 0) { if (docnum - winfirst < 0) {
LOGDEB("parnumfromdocnum: docnum " << docnum << " < winfirst " << LOGDEB("parnumfromdocnum: docnum " << docnum << " < winfirst " <<
winfirst << " return -1,-1\n"); winfirst << " return -1,-1\n");
return pair<int,int>(-1,-1); return {-1, -1};
} }
docnum -= winfirst; docnum -= winfirst;
for (std::map<int,int>::iterator it = m_pageParaToReldocnums.begin(); for (const auto& entry : m_pageParaToReldocnums.begin()) {
it != m_pageParaToReldocnums.end(); it++) { if (docnum == entry.second) {
if (docnum == it->second) { int first = entry.first;
int first = it->first;
int last = first+1; int last = first+1;
std::map<int,int>::iterator it1; std::map<int,int>::iterator it1;
while ((it1 = m_pageParaToReldocnums.find(last)) != while ((it1 = m_pageParaToReldocnums.find(last)) !=
@ -565,11 +564,11 @@ pair<int,int> ResList::parnumfromdocnum(int docnum)
last++; last++;
} }
LOGDEB("parnumfromdocnum: return " << first << "," << last << "\n"); LOGDEB("parnumfromdocnum: return " << first << "," << last << "\n");
return pair<int,int>(first, last); return {first, last};
} }
} }
LOGDEB("parnumfromdocnum: not found return -1,-1\n"); LOGDEB("parnumfromdocnum: not found return -1,-1\n");
return pair<int,int>(-1,-1); return {-1,-1};
} }
#endif // TEXTBROWSER #endif // TEXTBROWSER
@ -1180,8 +1179,23 @@ void ResList::menuPreviewParent()
void ResList::menuOpenParent() void ResList::menuOpenParent()
{ {
Rcl::Doc doc; Rcl::Doc doc;
if (getDoc(m_popDoc, doc) && m_source) if (getDoc(m_popDoc, doc) && m_source) {
emit editRequested(ResultPopup::getParent(m_source, doc)); 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() void ResList::menuShowSnippets()

View File

@ -85,6 +85,7 @@ public slots:
virtual void menuExpand(); virtual void menuExpand();
virtual void menuPreviewParent(); virtual void menuPreviewParent();
virtual void menuOpenParent(); virtual void menuOpenParent();
virtual void menuOpenFolder();
virtual void menuShowSnippets(); virtual void menuShowSnippets();
virtual void menuShowSubDocs(); virtual void menuShowSubDocs();
virtual void previewExposed(int); virtual void previewExposed(int);

View File

@ -1,4 +1,5 @@
/* /* Copyright (C) 2005-2020 J.F.Dockes
*
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -43,34 +44,25 @@ QMenu *create(QWidget *me, int opts, std::shared_ptr<DocSequence> source,
string apptag; string apptag;
doc.getmeta(Rcl::Doc::keyapptg, &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())); popup->addAction(QWidget::tr("&Preview"), me, SLOT(menuPreview()));
if (!theconfig->getMimeViewerDef(doc.mimetype, apptag, 0).empty()) { if (!theconfig->getMimeViewerDef(doc.mimetype, apptag, 0).empty()) {
popup->addAction(QWidget::tr("&Open"), me, SLOT(menuEdit())); popup->addAction(QWidget::tr("&Open"), me, SLOT(menuEdit()));
} }
bool needopenwith = true; if (isFsTop) {
if (!doc.ipath.empty()) // Openable by regular program. Add "open with" entry.
needopenwith = false; vector<DesktopDb::AppDef> apps;
if (needopenwith) {
string backend;
doc.getmeta(Rcl::Doc::keybcknd, &backend);
if (!backend.empty() && backend.compare("FS"))
needopenwith = false;
}
if (needopenwith) {
vector<DesktopDb::AppDef> aps;
DesktopDb *ddb = DesktopDb::getDb(); DesktopDb *ddb = DesktopDb::getDb();
if (ddb && ddb->appForMime(doc.mimetype, &aps) && if (ddb && ddb->appForMime(doc.mimetype, &apps) && !apps.empty()) {
!aps.empty()) {
QMenu *sub = popup->addMenu(QWidget::tr("Open With")); QMenu *sub = popup->addMenu(QWidget::tr("Open With"));
if (sub) { if (sub) {
for (vector<DesktopDb::AppDef>::const_iterator it = aps.begin(); for (const auto& app : apps) {
it != aps.end(); it++) { QAction *act = new QAction(u8s2qs(app.name), me);
QAction *act = new QVariant v(u8s2qs(app.command));
QAction(QString::fromUtf8(it->name.c_str()), me);
QVariant v(QString::fromUtf8(it->command.c_str()));
act->setData(v); act->setData(v);
sub->addAction(act); sub->addAction(act);
} }
@ -81,16 +73,14 @@ QMenu *create(QWidget *me, int opts, std::shared_ptr<DocSequence> source,
// See if there are any desktop files in $RECOLL_CONFDIR/scripts // See if there are any desktop files in $RECOLL_CONFDIR/scripts
// and possibly create a "run script" menu. // and possibly create a "run script" menu.
aps.clear(); apps.clear();
ddb = new DesktopDb(path_cat(theconfig->getConfDir(), "scripts")); 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")); QMenu *sub = popup->addMenu(QWidget::tr("Run Script"));
if (sub) { if (sub) {
for (vector<DesktopDb::AppDef>::const_iterator it = aps.begin(); for (const auto& app : apps) {
it != aps.end(); it++) { QAction *act = new QAction(u8s2qs(app.name), me);
QAction *act = new QVariant v(u8s2qs(app.command));
QAction(QString::fromUtf8(it->name.c_str()), me);
QVariant v(QString::fromUtf8(it->command.c_str()));
act->setData(v); act->setData(v);
sub->addAction(act); sub->addAction(act);
} }
@ -101,10 +91,12 @@ QMenu *create(QWidget *me, int opts, std::shared_ptr<DocSequence> source,
delete ddb; delete ddb;
} }
if (doc.isFsFile()) {
popup->addAction(QWidget::tr("Copy &File Name"), me, SLOT(menuCopyFN())); popup->addAction(QWidget::tr("Copy &File Name"), me, SLOT(menuCopyFN()));
}
popup->addAction(QWidget::tr("Copy &URL"), me, SLOT(menuCopyURL())); popup->addAction(QWidget::tr("Copy &URL"), me, SLOT(menuCopyURL()));
if ((opts&showSaveOne) && (!doc.isFsFile() || !doc.ipath.empty())) if ((opts&showSaveOne) && !(isFsTop))
popup->addAction(QWidget::tr("&Write to File"), me, popup->addAction(QWidget::tr("&Write to File"), me,
SLOT(menuSaveToFile())); SLOT(menuSaveToFile()));
@ -112,16 +104,21 @@ QMenu *create(QWidget *me, int opts, std::shared_ptr<DocSequence> source,
popup->addAction(QWidget::tr("Save selection to files"), popup->addAction(QWidget::tr("Save selection to files"),
me, SLOT(menuSaveSelection())); 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; 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"), popup->addAction(QWidget::tr("Preview P&arent document/folder"),
me, SLOT(menuPreviewParent())); me, SLOT(menuPreviewParent()));
} popup->addAction(QWidget::tr("&Open Parent document"),
// 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"),
me, SLOT(menuOpenParent())); me, SLOT(menuOpenParent()));
}
if (doc.isFsFile())
popup->addAction(QWidget::tr("&Open Parent Folder"),
me, SLOT(menuOpenFolder()));
if (opts & showExpand) if (opts & showExpand)
popup->addAction(QWidget::tr("Find &similar documents"), popup->addAction(QWidget::tr("Find &similar documents"),
@ -141,14 +138,19 @@ QMenu *create(QWidget *me, int opts, std::shared_ptr<DocSequence> source,
Rcl::Doc getParent(std::shared_ptr<DocSequence> source, Rcl::Doc& doc) Rcl::Doc getParent(std::shared_ptr<DocSequence> source, Rcl::Doc& doc)
{ {
Rcl::Doc pdoc; Rcl::Doc pdoc;
if (!source || !source->getEnclosing(doc, pdoc)) { if (source) {
// No parent doc: show enclosing folder with app configured for source->getEnclosing(doc, pdoc);
// directories }
return pdoc;
}
Rcl::Doc getFolder(std::shared_ptr<DocSequence>, Rcl::Doc& doc)
{
Rcl::Doc pdoc;
pdoc.url = url_parentfolder(doc.url); pdoc.url = url_parentfolder(doc.url);
pdoc.meta[Rcl::Doc::keychildurl] = doc.url; pdoc.meta[Rcl::Doc::keychildurl] = doc.url;
pdoc.meta[Rcl::Doc::keyapptg] = "parentopen"; pdoc.meta[Rcl::Doc::keyapptg] = "parentopen";
pdoc.mimetype = "inode/directory"; pdoc.mimetype = "inode/directory";
}
return pdoc; return pdoc;
} }

View File

@ -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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -26,6 +26,8 @@ namespace ResultPopup {
Rcl::Doc& doc); Rcl::Doc& doc);
extern Rcl::Doc getParent(std::shared_ptr<DocSequence> source, extern Rcl::Doc getParent(std::shared_ptr<DocSequence> source,
Rcl::Doc& doc); Rcl::Doc& doc);
extern Rcl::Doc getFolder(std::shared_ptr<DocSequence> source,
Rcl::Doc& doc);
extern void copyFN(const Rcl::Doc &doc); extern void copyFN(const Rcl::Doc &doc);
extern void copyURL(const Rcl::Doc &doc); extern void copyURL(const Rcl::Doc &doc);
}; };

View File

@ -1,4 +1,4 @@
/* /* Copyright (C) 2005-2020 J.F.Dockes
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * 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 // could be protected to be done only once, but it's no real
// problem // problem
if (theconfig) { if (theconfig) {
const set<string>& stored = theconfig->getStoredFields(); const auto& stored = theconfig->getStoredFields();
for (set<string>::const_iterator it = stored.begin(); for (const auto& field : stored) {
it != stored.end(); it++) { if (o_displayableFields.find(field) == o_displayableFields.end()) {
if (o_displayableFields.find(*it) == o_displayableFields.end()) { o_displayableFields[field] = u8s2qs(field);
o_displayableFields[*it] = QString::fromUtf8(it->c_str());
} }
} }
} }
@ -1003,9 +1002,24 @@ void ResTable::menuPreviewParent()
void ResTable::menuOpenParent() void ResTable::menuOpenParent()
{ {
if (m_detaildocnum >= 0 && m_model && m_model->getDocSource()) if (m_detaildocnum >= 0 && m_model && m_model->getDocSource()) {
emit editRequested( Rcl::Doc pdoc =
ResultPopup::getParent(m_model->getDocSource(), m_detaildoc)); 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() void ResTable::menuEdit()
@ -1085,12 +1099,11 @@ void ResTable::createHeaderPopupMenu(const QPoint& pos)
popup->addSeparator(); popup->addSeparator();
QAction *act; QAction *act;
for (map<string, QString>::const_iterator it = allfields.begin(); for (const auto& field : allfields) {
it != allfields.end(); it++) { if (std::find(fields.begin(), fields.end(), field.first) != fields.end())
if (std::find(fields.begin(), fields.end(), it->first) != fields.end())
continue; continue;
act = new QAction(tr("Add \"%1\" column").arg(it->second), popup); act = new QAction(tr("Add \"%1\" column").arg(field.second), popup);
act->setData(QString::fromUtf8(it->first.c_str())); act->setData(u8s2qs(field.first));
connect(act, SIGNAL(triggered(bool)), this , SLOT(addColumn())); connect(act, SIGNAL(triggered(bool)), this , SLOT(addColumn()));
popup->addAction(act); popup->addAction(act);
} }

View File

@ -148,6 +148,7 @@ public slots:
virtual void menuExpand(); virtual void menuExpand();
virtual void menuPreviewParent(); virtual void menuPreviewParent();
virtual void menuOpenParent(); virtual void menuOpenParent();
virtual void menuOpenFolder();
virtual void menuShowSnippets(); virtual void menuShowSnippets();
virtual void menuShowSubDocs(); virtual void menuShowSubDocs();
virtual void createHeaderPopupMenu(const QPoint&); virtual void createHeaderPopupMenu(const QPoint&);

View File

@ -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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -127,5 +127,3 @@ bool DocSource::setSortSpec(const DocSeqSortSpec &s)
buildStack(); buildStack();
return true; return true;
} }

View File

@ -114,20 +114,21 @@ public:
return false; 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&); virtual bool getEnclosing(Rcl::Doc&, Rcl::Doc&);
/** Get estimated total count in results */ /** Get estimated total count in results */
virtual int getResCnt() = 0; virtual int getResCnt() = 0;
/** Get title for result list */ /** Get title for result list */
virtual std::string title() virtual std::string title() {
{
return m_title; return m_title;
} }
/** Can do snippets ? */ /** Can do snippets ? */
virtual bool snippetsCapable() virtual bool snippetsCapable() {
{
return false; return false;
} }
/** Get description for underlying query */ /** Get description for underlying query */
@ -135,16 +136,13 @@ public:
/** Get search terms (for highlighting abstracts). Some sequences /** Get search terms (for highlighting abstracts). Some sequences
* may have no associated search terms. Implement this for them. */ * may have no associated search terms. Implement this for them. */
virtual void getTerms(HighlightData& hld) virtual void getTerms(HighlightData& hld) {
{
hld.clear(); hld.clear();
} }
virtual std::list<std::string> expand(Rcl::Doc &) virtual std::list<std::string> expand(Rcl::Doc &) {
{
return std::list<std::string>(); return std::list<std::string>();
} }
virtual std::string getReason() virtual std::string getReason() {
{
return m_reason; return m_reason;
} }
/** Optional functionality. */ /** Optional functionality. */

View File

@ -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 * 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 * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -205,9 +205,8 @@ public:
return true; return true;
} }
/* Is this document stored as a regular filesystem file ? /* Is this document stored in a regular filesystem file ?
* (as opposed to e.g. a webcache file), not a subdoc, * (as opposed to e.g. a webcache file). */
*/
bool isFsFile() { bool isFsFile() {
std::string backend; std::string backend;
getmeta(keybcknd, &backend); getmeta(keybcknd, &backend);