GUI: duplicate reslist popup menu for the restable

This commit is contained in:
Jean-Francois Dockes 2011-03-11 19:04:56 +01:00
parent ae6d758b34
commit 9b5ff141c0
4 changed files with 252 additions and 49 deletions

View File

@ -930,17 +930,18 @@ fvwm
</sect2> </sect2>
<sect2 id="rcl.search.restable"> <sect2 id="rcl.search.restable">
<title>The alternate result table</title> <title>The result table</title>
<para>In &RCL; 1.15 and newer, the results can now be shown in a <para>In &RCL; 1.15 and newer, the results can be displayed in
spreadsheet-like display. You can switch to this presentation by spreadsheet-like fashion. You can switch to this presentation by
clicking the table-like icon in the toolbar (this is a toggle, clicking the table-like icon in the toolbar (this is a toggle,
click again to restore the list).</para> click again to restore the list).</para>
<para>Clicking on the column headers will allow sorting by the <para>Clicking on the column headers will allow sorting by the
values in the column. You can click again to invert the order, and values in the column. You can click again to invert the order, and
use the header right-click menu to reset sorting to the default use the header right-click menu to reset sorting to the default
relevance order.</para> relevance order (you can also use the sort-by-date arrows to do
this).</para>
<para>Both the list and the table display the same underlying <para>Both the list and the table display the same underlying
results. The sort order set from the table is still active if you results. The sort order set from the table is still active if you
@ -957,7 +958,8 @@ fvwm
the row to freeze the display. The bottom area is equivalent to a the row to freeze the display. The bottom area is equivalent to a
classical result list paragraph, with links for classical result list paragraph, with links for
starting a preview or a native application, and an equivalent starting a preview or a native application, and an equivalent
right-click menu.</para> right-click menu. Typing <keycap>Esc</keycap> (the Escape key) will
unfreeze the display.</para>
</sect2> </sect2>

View File

@ -268,6 +268,14 @@ void RclMain::init()
this, SLOT(startNativeViewer(Rcl::Doc))); this, SLOT(startNativeViewer(Rcl::Doc)));
connect(restable, SIGNAL(docPreviewClicked(int, Rcl::Doc, int)), connect(restable, SIGNAL(docPreviewClicked(int, Rcl::Doc, int)),
this, SLOT(startPreview(int, Rcl::Doc, int))); this, SLOT(startPreview(int, Rcl::Doc, int)));
connect(restable, SIGNAL(docEditClicked(Rcl::Doc)),
this, SLOT(startNativeViewer(Rcl::Doc)));
connect(restable, SIGNAL(docExpand(Rcl::Doc)),
this, SLOT(docExpand(Rcl::Doc)));
connect(restable, SIGNAL(docEditClicked(Rcl::Doc)),
this, SLOT(startNativeViewer(Rcl::Doc)));
connect(restable, SIGNAL(editRequested(Rcl::Doc)),
this, SLOT(startNativeViewer(Rcl::Doc)));
connect(this, SIGNAL(docSourceChanged(RefCntr<DocSequence>)), connect(this, SIGNAL(docSourceChanged(RefCntr<DocSequence>)),
reslist, SLOT(setDocSource(RefCntr<DocSequence>))); reslist, SLOT(setDocSource(RefCntr<DocSequence>)));

View File

@ -30,6 +30,8 @@
#include <QStyledItemDelegate> #include <QStyledItemDelegate>
#include <QTextDocument> #include <QTextDocument>
#include <QPainter> #include <QPainter>
#include <QSplitter>
#include <QClipboard>
#include "recoll.h" #include "recoll.h"
#include "refcntr.h" #include "refcntr.h"
@ -47,8 +49,22 @@
static const int ROWHEIGHTPAD = 2; static const int ROWHEIGHTPAD = 2;
static const int TEXTINCELLVTRANS = -4; static const int TEXTINCELLVTRANS = -4;
////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Restable "pager". We use it to display a single doc details in the // Restable hiliter: to highlight search term in the table. This is actually
// the same as reslist's, could be shared.
class PlainToRichQtReslist : public PlainToRich {
public:
virtual ~PlainToRichQtReslist() {}
virtual string startMatch() {
return string("<span style='color: ")
+ string((const char *)prefs.qtermcolor.toAscii()) + string("'>");
}
virtual string endMatch() {return string("</span>");}
};
static PlainToRichQtReslist g_hiliter;
//////////////////////////////////////////////////////////////////////////
// Restable "pager". We use it to print details for a document in the
// detail area // detail area
/// ///
class ResTablePager : public ResListPager { class ResTablePager : public ResListPager {
@ -64,28 +80,12 @@ private:
ResTable *m_parent; ResTable *m_parent;
}; };
////////////////////////// bool ResTablePager::append(const string& data, int, const Rcl::Doc&)
// Restable hiliter: to highlight search term in the table. This is actually
// the same as reslist's, could be shared.
class PlainToRichQtReslist : public PlainToRich {
public:
virtual ~PlainToRichQtReslist() {}
virtual string startMatch() {
return string("<span style='color: ")
+ string((const char *)prefs.qtermcolor.toAscii()) + string("'>");
}
virtual string endMatch() {return string("</span>");}
};
static PlainToRichQtReslist g_hiliter;
/////////////////////////////////////
bool ResTablePager::append(const string& data, int docnum, const Rcl::Doc&)
{ {
m_parent->textBrowser->moveCursor(QTextCursor::End, m_parent->m_detail->moveCursor(QTextCursor::End,
QTextCursor::MoveAnchor); QTextCursor::MoveAnchor);
m_parent->textBrowser->textCursor().insertBlock(); m_parent->m_detail->textCursor().insertBlock();
m_parent->textBrowser->insertHtml(QString::fromUtf8(data.c_str())); m_parent->m_detail->insertHtml(QString::fromUtf8(data.c_str()));
m_parent->m_detaildocnum = docnum;
return true; return true;
} }
@ -106,7 +106,39 @@ string ResTablePager::iconPath(const string& mtype)
return iconpath; return iconpath;
} }
////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/// Detail text area methods
ResTableDetailArea::ResTableDetailArea(ResTable* parent)
: QTextBrowser(parent), m_table(parent)
{
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, SIGNAL(customContextMenuRequested(const QPoint&)),
this, SLOT(createPopupMenu(const QPoint&)));
}
void ResTableDetailArea::createPopupMenu(const QPoint& pos)
{
if (!m_table || m_table->m_detaildocnum < 0) {
LOGDEB(("ResTableDetailArea::createPopupMenu: no table/detaildoc\n"));
return;
}
QMenu *popup = new QMenu(this);
popup->addAction(tr("&Preview"), m_table, SLOT(menuPreview()));
popup->addAction(tr("&Open"), m_table, SLOT(menuEdit()));
popup->addAction(tr("Copy &File Name"), m_table, SLOT(menuCopyFN()));
popup->addAction(tr("Copy &URL"), m_table, SLOT(menuCopyURL()));
if (!m_table->m_detaildoc.ipath.empty())
popup->addAction(tr("&Write to File"), m_table, SLOT(menuSaveToFile()));
popup->addAction(tr("Find &similar documents"), m_table, SLOT(menuExpand()));
popup->addAction(tr("Preview P&arent document/folder"),
m_table, SLOT(menuPreviewParent()));
popup->addAction(tr("&Open Parent document/folder"),
m_table, SLOT(menuOpenParent()));
popup->popup(mapToGlobal(pos));
}
//////////////////////////////////////////////////////////////////////////////
//// Data model methods //// Data model methods
//// ////
@ -403,6 +435,9 @@ void ResTable::init()
tableView->setSelectionBehavior(QAbstractItemView::SelectRows); tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
tableView->setSelectionMode(QAbstractItemView::SingleSelection); tableView->setSelectionMode(QAbstractItemView::SingleSelection);
tableView->setItemDelegate(new ResTableDelegate(this)); tableView->setItemDelegate(new ResTableDelegate(this));
tableView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(tableView, SIGNAL(customContextMenuRequested(const QPoint&)),
this, SLOT(createPopupMenu(const QPoint&)));
QHeaderView *header = tableView->horizontalHeader(); QHeaderView *header = tableView->horizontalHeader();
if (header) { if (header) {
@ -446,13 +481,16 @@ void ResTable::init()
splitter->setSizes(sizes); splitter->setSizes(sizes);
} }
textBrowser->setReadOnly(TRUE); delete textBrowser;
textBrowser->setUndoRedoEnabled(FALSE); m_detail = new ResTableDetailArea(this);
textBrowser->setOpenLinks(FALSE); m_detail->setReadOnly(TRUE);
m_detail->setUndoRedoEnabled(FALSE);
m_detail->setOpenLinks(FALSE);
// signals and slots connections // signals and slots connections
connect(textBrowser, SIGNAL(anchorClicked(const QUrl &)), connect(m_detail, SIGNAL(anchorClicked(const QUrl &)),
this, SLOT(linkWasClicked(const QUrl &))); this, SLOT(linkWasClicked(const QUrl &)));
splitter->addWidget(m_detail);
splitter->setOrientation(Qt::Vertical);
} }
// This is called by rclmain_w prior to exiting // This is called by rclmain_w prior to exiting
@ -494,9 +532,12 @@ void ResTable::onTableView_currentChanged(const QModelIndex& index)
return; return;
Rcl::Doc doc; Rcl::Doc doc;
if (m_model->getDocSource()->getDoc(index.row(), doc)) { if (m_model->getDocSource()->getDoc(index.row(), doc)) {
textBrowser->clear(); m_detail->clear();
m_detaildocnum = index.row(); m_detaildocnum = index.row();
m_detaildoc = doc;
m_pager->displayDoc(rclconfig, index.row(), doc, m_model->m_hdata); m_pager->displayDoc(rclconfig, index.row(), doc, m_model->m_hdata);
} else {
m_detaildocnum = -1;
} }
} }
@ -515,8 +556,9 @@ void ResTable::setDocSource(RefCntr<DocSequence> nsource)
m_model->setDocSource(nsource); m_model->setDocSource(nsource);
if (m_pager) if (m_pager)
m_pager->setDocSource(nsource, 0); m_pager->setDocSource(nsource, 0);
if (textBrowser) if (m_detail)
textBrowser->clear(); m_detail->clear();
m_detaildocnum = -1;
} }
void ResTable::resetSource() void ResTable::resetSource()
@ -569,13 +611,15 @@ void ResTable::readDocSource(bool resetPos)
tableView->verticalScrollBar()->setSliderPosition(0); tableView->verticalScrollBar()->setSliderPosition(0);
m_model->readDocSource(); m_model->readDocSource();
textBrowser->clear(); m_detail->clear();
m_detaildocnum = -1;
} }
void ResTable::linkWasClicked(const QUrl &url) void ResTable::linkWasClicked(const QUrl &url)
{ {
if (!m_model || m_model->getDocSource().isNull()) if (m_detaildocnum < 0) {
return; return;
}
QString s = url.toString(); QString s = url.toString();
const char *ascurl = s.toAscii(); const char *ascurl = s.toAscii();
LOGDEB(("ResTable::linkWasClicked: [%s]\n", ascurl)); LOGDEB(("ResTable::linkWasClicked: [%s]\n", ascurl));
@ -586,23 +630,137 @@ void ResTable::linkWasClicked(const QUrl &url)
case 'P': case 'P':
case 'E': case 'E':
{ {
Rcl::Doc doc;
if (!m_model->getDocSource()->getDoc(i, doc)) {
LOGERR(("ResTable::linkWasClicked: can't get doc for %d\n", i));
return;
}
if (what == 'P') if (what == 'P')
emit docPreviewClicked(i, doc, 0); emit docPreviewClicked(i, m_detaildoc, 0);
else else
emit docEditClicked(doc); emit docEditClicked(m_detaildoc);
} }
break; break;
default: default:
LOGERR(("ResList::linkWasClicked: bad link [%s]\n", ascurl)); LOGERR(("ResTable::linkWasClicked: bad link [%s]\n", ascurl));
break;// ?? break;// ??
} }
} }
void ResTable::createPopupMenu(const QPoint& pos)
{
LOGDEB(("ResTable::createPopupMenu: m_detaildocnum %d\n", m_detaildocnum));
if (m_detaildocnum < 0)
return;
QMenu *popup = new QMenu(this);
popup->addAction(tr("&Preview"), this, SLOT(menuPreview()));
popup->addAction(tr("&Open"), this, SLOT(menuEdit()));
popup->addAction(tr("Copy &File Name"), this, SLOT(menuCopyFN()));
popup->addAction(tr("Copy &URL"), this, SLOT(menuCopyURL()));
if (m_detaildoc.ipath.empty())
popup->addAction(tr("&Write to File"), this, SLOT(menuSaveToFile()));
popup->addAction(tr("Find &similar documents"), this, SLOT(menuExpand()));
popup->addAction(tr("Preview P&arent document/folder"),
this, SLOT(menuPreviewParent()));
popup->addAction(tr("&Open Parent document/folder"),
this, SLOT(menuOpenParent()));
popup->popup(mapToGlobal(pos));
}
void ResTable::menuPreview()
{
if (m_detaildocnum < 0)
return;
emit docPreviewClicked(m_detaildocnum, m_detaildoc, 0);
}
void ResTable::menuSaveToFile()
{
if (m_detaildocnum < 0)
return;
emit docSaveToFileClicked(m_detaildoc);
}
void ResTable::menuPreviewParent()
{
if (!m_model || m_detaildocnum < 0)
return;
RefCntr<DocSequence> source = m_model->getDocSource();
if (source.isNull())
return;
Rcl::Doc& doc = m_detaildoc;
Rcl::Doc pdoc;
if (source->getEnclosing(doc, pdoc)) {
emit previewRequested(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);
}
}
void ResTable::menuOpenParent()
{
if (!m_model || m_detaildocnum < 0)
return;
RefCntr<DocSequence> source = m_model->getDocSource();
if (source.isNull())
return;
Rcl::Doc& doc = m_detaildoc;
Rcl::Doc pdoc;
if (source->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);
}
}
void ResTable::menuEdit()
{
if (m_detaildocnum < 0)
return;
emit docEditClicked(m_detaildoc);
}
void ResTable::menuCopyFN()
{
if (m_detaildocnum < 0)
return;
Rcl::Doc &doc = m_detaildoc;
// 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 = QString::fromLocal8Bit(doc.url.c_str()+7);
QApplication::clipboard()->setText(qfn, QClipboard::Selection);
QApplication::clipboard()->setText(qfn, QClipboard::Clipboard);
}
void ResTable::menuCopyURL()
{
if (m_detaildocnum < 0)
return;
Rcl::Doc &doc = m_detaildoc;
string url = url_encode(doc.url, 7);
QApplication::clipboard()->setText(url.c_str(),
QClipboard::Selection);
QApplication::clipboard()->setText(url.c_str(),
QClipboard::Clipboard);
}
void ResTable::menuExpand()
{
if (m_detaildocnum < 0)
return;
emit docExpand(m_detaildoc);
}
void ResTable::createHeaderPopupMenu(const QPoint& pos) void ResTable::createHeaderPopupMenu(const QPoint& pos)
{ {
LOGDEB(("ResTable::createHeaderPopupMenu(%d, %d)\n", pos.x(), pos.y())); LOGDEB(("ResTable::createHeaderPopupMenu(%d, %d)\n", pos.x(), pos.y()));

View File

@ -78,6 +78,23 @@ private:
HiliteData m_hdata; HiliteData m_hdata;
}; };
class ResTable;
// Modified textBrowser for the detail area
class ResTableDetailArea : public QTextBrowser {
Q_OBJECT;
public:
ResTableDetailArea(ResTable* parent = 0);
public slots:
virtual void createPopupMenu(const QPoint& pos);
private:
ResTable *m_table;
};
class ResTablePager; class ResTablePager;
class QUrl; class QUrl;
@ -88,7 +105,7 @@ class ResTable : public QWidget, public Ui::ResTable
public: public:
ResTable(QWidget* parent = 0) ResTable(QWidget* parent = 0)
: QWidget(parent), : QWidget(parent),
m_model(0), m_pager(0), m_detaildocnum(-1) m_model(0), m_pager(0), m_detail(0), m_detaildocnum(-1)
{ {
setupUi(this); setupUi(this);
init(); init();
@ -96,7 +113,7 @@ public:
virtual ~ResTable() {} virtual ~ResTable() {}
virtual RecollModel *getModel() {return m_model;} virtual RecollModel *getModel() {return m_model;}
virtual ResTableDetailArea* getDetailArea() {return m_detail;}
public slots: public slots:
virtual void onTableView_currentChanged(const QModelIndex&); virtual void onTableView_currentChanged(const QModelIndex&);
virtual void on_tableView_entered(const QModelIndex& index); virtual void on_tableView_entered(const QModelIndex& index);
@ -105,21 +122,39 @@ public slots:
virtual void resetSource(); virtual void resetSource();
virtual void readDocSource(bool resetPos = true); virtual void readDocSource(bool resetPos = true);
virtual void onSortDataChanged(DocSeqSortSpec); virtual void onSortDataChanged(DocSeqSortSpec);
virtual void linkWasClicked(const QUrl&); virtual void createPopupMenu(const QPoint& pos);
virtual void menuPreview();
virtual void menuSaveToFile();
virtual void menuEdit();
virtual void menuCopyFN();
virtual void menuCopyURL();
virtual void menuExpand();
virtual void menuPreviewParent();
virtual void menuOpenParent();
virtual void createHeaderPopupMenu(const QPoint&); virtual void createHeaderPopupMenu(const QPoint&);
virtual void deleteColumn(); virtual void deleteColumn();
virtual void addColumn(); virtual void addColumn();
virtual void resetSort(); // Revert to natural (relevance) order virtual void resetSort(); // Revert to natural (relevance) order
virtual void linkWasClicked(const QUrl&);
signals: signals:
void docPreviewClicked(int, Rcl::Doc, int); void docPreviewClicked(int, Rcl::Doc, int);
void docEditClicked(Rcl::Doc); void docEditClicked(Rcl::Doc);
void docSaveToFileClicked(Rcl::Doc);
void previewRequested(Rcl::Doc);
void editRequested(Rcl::Doc);
void headerClicked();
void docExpand(Rcl::Doc);
friend class ResTablePager; friend class ResTablePager;
friend class ResTableDetailArea;
private: private:
void init(); void init();
RecollModel *m_model; RecollModel *m_model;
ResTablePager *m_pager; ResTablePager *m_pager;
ResTableDetailArea *m_detail;
int m_detaildocnum; int m_detaildocnum;
Rcl::Doc m_detaildoc;
int m_popcolumn; int m_popcolumn;
}; };