GUI: duplicate reslist popup menu for the restable
This commit is contained in:
parent
ae6d758b34
commit
9b5ff141c0
@ -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>
|
||||
|
||||
|
||||
@ -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>)));
|
||||
|
||||
@ -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()));
|
||||
|
||||
@ -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;
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user