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 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
spreadsheet-like display. You can switch to this presentation by
<para>In &RCL; 1.15 and newer, the results can be displayed in
spreadsheet-like fashion. You can switch to this presentation by
clicking the table-like icon in the toolbar (this is a toggle,
click again to restore the list).</para>
<para>Clicking on the column headers will allow sorting by the
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
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
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
classical result list paragraph, with links for
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>

View File

@ -268,6 +268,14 @@ void RclMain::init()
this, SLOT(startNativeViewer(Rcl::Doc)));
connect(restable, SIGNAL(docPreviewClicked(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>)),
reslist, SLOT(setDocSource(RefCntr<DocSequence>)));

View File

@ -30,6 +30,8 @@
#include <QStyledItemDelegate>
#include <QTextDocument>
#include <QPainter>
#include <QSplitter>
#include <QClipboard>
#include "recoll.h"
#include "refcntr.h"
@ -47,8 +49,22 @@
static const int ROWHEIGHTPAD = 2;
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
///
class ResTablePager : public ResListPager {
@ -64,28 +80,12 @@ private:
ResTable *m_parent;
};
//////////////////////////
// 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&)
bool ResTablePager::append(const string& data, int, const Rcl::Doc&)
{
m_parent->textBrowser->moveCursor(QTextCursor::End,
m_parent->m_detail->moveCursor(QTextCursor::End,
QTextCursor::MoveAnchor);
m_parent->textBrowser->textCursor().insertBlock();
m_parent->textBrowser->insertHtml(QString::fromUtf8(data.c_str()));
m_parent->m_detaildocnum = docnum;
m_parent->m_detail->textCursor().insertBlock();
m_parent->m_detail->insertHtml(QString::fromUtf8(data.c_str()));
return true;
}
@ -106,7 +106,39 @@ string ResTablePager::iconPath(const string& mtype)
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
////
@ -403,6 +435,9 @@ void ResTable::init()
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
tableView->setSelectionMode(QAbstractItemView::SingleSelection);
tableView->setItemDelegate(new ResTableDelegate(this));
tableView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(tableView, SIGNAL(customContextMenuRequested(const QPoint&)),
this, SLOT(createPopupMenu(const QPoint&)));
QHeaderView *header = tableView->horizontalHeader();
if (header) {
@ -446,13 +481,16 @@ void ResTable::init()
splitter->setSizes(sizes);
}
textBrowser->setReadOnly(TRUE);
textBrowser->setUndoRedoEnabled(FALSE);
textBrowser->setOpenLinks(FALSE);
delete textBrowser;
m_detail = new ResTableDetailArea(this);
m_detail->setReadOnly(TRUE);
m_detail->setUndoRedoEnabled(FALSE);
m_detail->setOpenLinks(FALSE);
// signals and slots connections
connect(textBrowser, SIGNAL(anchorClicked(const QUrl &)),
connect(m_detail, SIGNAL(anchorClicked(const QUrl &)),
this, SLOT(linkWasClicked(const QUrl &)));
splitter->addWidget(m_detail);
splitter->setOrientation(Qt::Vertical);
}
// This is called by rclmain_w prior to exiting
@ -494,9 +532,12 @@ void ResTable::onTableView_currentChanged(const QModelIndex& index)
return;
Rcl::Doc doc;
if (m_model->getDocSource()->getDoc(index.row(), doc)) {
textBrowser->clear();
m_detail->clear();
m_detaildocnum = index.row();
m_detaildoc = doc;
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);
if (m_pager)
m_pager->setDocSource(nsource, 0);
if (textBrowser)
textBrowser->clear();
if (m_detail)
m_detail->clear();
m_detaildocnum = -1;
}
void ResTable::resetSource()
@ -569,13 +611,15 @@ void ResTable::readDocSource(bool resetPos)
tableView->verticalScrollBar()->setSliderPosition(0);
m_model->readDocSource();
textBrowser->clear();
m_detail->clear();
m_detaildocnum = -1;
}
void ResTable::linkWasClicked(const QUrl &url)
{
if (!m_model || m_model->getDocSource().isNull())
if (m_detaildocnum < 0) {
return;
}
QString s = url.toString();
const char *ascurl = s.toAscii();
LOGDEB(("ResTable::linkWasClicked: [%s]\n", ascurl));
@ -586,23 +630,137 @@ void ResTable::linkWasClicked(const QUrl &url)
case 'P':
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')
emit docPreviewClicked(i, doc, 0);
emit docPreviewClicked(i, m_detaildoc, 0);
else
emit docEditClicked(doc);
emit docEditClicked(m_detaildoc);
}
break;
default:
LOGERR(("ResList::linkWasClicked: bad link [%s]\n", ascurl));
LOGERR(("ResTable::linkWasClicked: bad link [%s]\n", ascurl));
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)
{
LOGDEB(("ResTable::createHeaderPopupMenu(%d, %d)\n", pos.x(), pos.y()));

View File

@ -78,6 +78,23 @@ private:
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 QUrl;
@ -88,7 +105,7 @@ class ResTable : public QWidget, public Ui::ResTable
public:
ResTable(QWidget* parent = 0)
: 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);
init();
@ -96,7 +113,7 @@ public:
virtual ~ResTable() {}
virtual RecollModel *getModel() {return m_model;}
virtual ResTableDetailArea* getDetailArea() {return m_detail;}
public slots:
virtual void onTableView_currentChanged(const QModelIndex&);
virtual void on_tableView_entered(const QModelIndex& index);
@ -105,21 +122,39 @@ public slots:
virtual void resetSource();
virtual void readDocSource(bool resetPos = true);
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 deleteColumn();
virtual void addColumn();
virtual void resetSort(); // Revert to natural (relevance) order
virtual void linkWasClicked(const QUrl&);
signals:
void docPreviewClicked(int, Rcl::Doc, int);
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 ResTableDetailArea;
private:
void init();
RecollModel *m_model;
ResTablePager *m_pager;
ResTableDetailArea *m_detail;
int m_detaildocnum;
Rcl::Doc m_detaildoc;
int m_popcolumn;
};