Only create the snippets menu entry if doc has pages. Add code for a snippets window link inside the result list

This commit is contained in:
Jean-Francois Dockes 2012-10-02 10:56:23 +02:00
parent eca84d32cb
commit 2e0cd5bc82
7 changed files with 117 additions and 29 deletions

View file

@ -2022,6 +2022,10 @@ fvwm
</listitem> </listitem>
<listitem><formalpara><title>%D</title><para>Date</para></formalpara> <listitem><formalpara><title>%D</title><para>Date</para></formalpara>
</listitem> </listitem>
<listitem><formalpara><title>%E</title><para>Precooked Snippets
link (will only appear for documents indexed with page
numbers)</para></formalpara>
</listitem>
<listitem><formalpara><title>%I</title><para>Icon image <listitem><formalpara><title>%I</title><para>Icon image
name. This is normally determined from the mime type. The name. This is normally determined from the mime type. The
associations are defined inside the associations are defined inside the
@ -2907,6 +2911,17 @@ application/x-chm = execm rclchm
</sect2> </sect2>
<sect2 id="rcl.program.filters.pages">
<title>Page numbers</title>
<para>The indexer will interpret <literal>^L</literal> characters
in the filter output as indicating page breaks, and will record
them. At query time, this allows starting a viewer on the right
page for a hit or a snippet. Currently, only the PDF filter
generates page breaks (thanks to
<literal>pdftotext</literal>).</para>
</sect2>
</sect1> </sect1>
<sect1 id="rcl.program.fields"> <sect1 id="rcl.program.fields">
@ -4514,27 +4529,42 @@ x-my-tag = mailmytag
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<formalpara><title>%D</title><para>Document date</para></formalpara> <formalpara><title>%D</title>
</listitem> <listitem><formalpara><title>%f</title><para>File <para>Document date</para></formalpara>
name. This may be the name of a temporary file if it was </listitem>
necessary to create one (ie: to extract a subdocument from a
container).</para></formalpara> <listitem><formalpara><title>%f</title>
<para>File name. This may be the name of a temporary file if
it was necessary to create one (ie: to extract a subdocument
from a container).</para></formalpara>
</listitem> </listitem>
<listitem><formalpara><title>%F</title><para>Original file name.
Same as %f except if a temporary file is used.</para></formalpara> <listitem><formalpara><title>%F</title>
<para>Original file name. Same as %f except if a temporary
file is used.</para></formalpara>
</listitem> </listitem>
<listitem><formalpara><title>%i</title><para>Internal path, for
subdocuments of containers. The format depends on the container <listitem><formalpara><title>%i</title>
type. If this appears in the command line, &RCL; will not create <para>Internal path, for subdocuments of containers. The
a temporary file to extract the subdocument, expecting the called format depends on the container type. If this appears in the
application (possibly a script) to be able to handle command line, &RCL; will not create a temporary file to
it.</para></formalpara> extract the subdocument, expecting the called application
(possibly a script) to be able to handle it.</para></formalpara>
</listitem> </listitem>
<listitem><formalpara><title>%M</title><para>Mime
type</para></formalpara> <listitem><formalpara><title>%M</title>
<para>Mime type</para></formalpara>
</listitem> </listitem>
<listitem><formalpara><title>%U, %u</title><para>Url.
</para></formalpara> <listitem><formalpara><title>%p</title>
<para>Page index. Only significant for a subset of document
types, currently only PDF files. Can be used to start the
editor at the right page for a match or
snippet.</para></formalpara>
</listitem>
<listitem><formalpara><title>%U, %u</title>
<para>Url.</para></formalpara>
</listitem> </listitem>
</itemizedlist> </itemizedlist>

View file

@ -510,7 +510,7 @@ bool ResList::getDoc(int docnum, Rcl::Doc &doc)
// Is docnum in current page ? Then all Ok // Is docnum in current page ? Then all Ok
if (docnum >= winfirst && docnum <= winlast) { if (docnum >= winfirst && docnum <= winlast) {
return m_source->getDoc(docnum, doc); return m_pager->getDoc(docnum, doc);
} }
// Else we accept to page down or up but not further // Else we accept to page down or up but not further
@ -522,7 +522,7 @@ bool ResList::getDoc(int docnum, Rcl::Doc &doc)
winfirst = pageFirstDocNum(); winfirst = pageFirstDocNum();
winlast = m_pager->pageLastDocNum(); winlast = m_pager->pageLastDocNum();
if (docnum >= winfirst && docnum <= winlast) { if (docnum >= winfirst && docnum <= winlast) {
return m_source->getDoc(docnum, doc); return m_pager->getDoc(docnum, doc);
} }
return false; return false;
} }
@ -801,6 +801,16 @@ void ResList::mouseDoubleClickEvent(QMouseEvent *event)
#endif #endif
} }
void ResList::newSnippetsW(const Rcl::Doc& doc)
{
SnippetsW *sp = new SnippetsW(doc, m_source);
if (m_parent) {
connect(sp, SIGNAL(startNativeViewer(Rcl::Doc, int)),
m_parent, SLOT(startNativeViewer(Rcl::Doc, int)));
}
sp->show();
}
void ResList::linkWasClicked(const QUrl &url) void ResList::linkWasClicked(const QUrl &url)
{ {
string ascurl = (const char *)url.toString().toAscii();; string ascurl = (const char *)url.toString().toAscii();;
@ -808,9 +818,27 @@ void ResList::linkWasClicked(const QUrl &url)
int what = ascurl[0]; int what = ascurl[0];
switch (what) { switch (what) {
// Open abstract/snippets window
case 'A':
{
if (m_source.isNull())
return;
int i = atoi(ascurl.c_str()+1) - 1;
Rcl::Doc doc;
if (!getDoc(i, doc)) {
LOGERR(("ResList::linkWasClicked: can't get doc for %d\n", i));
return;
}
newSnippetsW(doc);
}
break;
// Show query details
case 'H': case 'H':
emit headerClicked(); emit headerClicked();
break; break;
// Preview and edit
case 'P': case 'P':
case 'E': case 'E':
{ {
@ -826,12 +854,16 @@ void ResList::linkWasClicked(const QUrl &url)
emit docEditClicked(doc); emit docEditClicked(doc);
} }
break; break;
// Next/prev page
case 'n': case 'n':
resultPageNext(); resultPageNext();
break; break;
case 'p': case 'p':
resultPageBack(); resultPageBack();
break; break;
// Spelling: replacement suggestion clicked
case 'S': case 'S':
{ {
QString s = url.toString(); QString s = url.toString();
@ -845,6 +877,7 @@ void ResList::linkWasClicked(const QUrl &url)
} }
} }
break; break;
default: default:
LOGERR(("ResList::linkWasClicked: bad link [%s]\n", ascurl.c_str())); LOGERR(("ResList::linkWasClicked: bad link [%s]\n", ascurl.c_str()));
break;// ?? break;// ??
@ -897,7 +930,7 @@ void ResList::createPopupMenu(const QPoint& pos)
this, SLOT(menuPreviewParent())); this, SLOT(menuPreviewParent()));
popup->addAction(tr("&Open Parent document/folder"), popup->addAction(tr("&Open Parent document/folder"),
this, SLOT(menuOpenParent())); this, SLOT(menuOpenParent()));
if (m_source->snippetsCapable()) if (havedoc && doc.haspages && m_source->snippetsCapable())
popup->addAction(tr("Open &Snippets window"), popup->addAction(tr("Open &Snippets window"),
this, SLOT(menuOpenSnippets())); this, SLOT(menuOpenSnippets()));
popup->popup(mapToGlobal(pos)); popup->popup(mapToGlobal(pos));
@ -956,13 +989,7 @@ void ResList::menuOpenSnippets()
Rcl::Doc doc; Rcl::Doc doc;
if (!getDoc(m_popDoc, doc) || m_source.isNull()) if (!getDoc(m_popDoc, doc) || m_source.isNull())
return; return;
SnippetsW *sp = new SnippetsW(doc, m_source); newSnippetsW(doc);
if (m_parent) {
connect(sp, SIGNAL(startNativeViewer(Rcl::Doc, int)),
m_parent, SLOT(startNativeViewer(Rcl::Doc, int)));
}
sp->show();
} }
void ResList::menuEdit() void ResList::menuEdit()

View file

@ -145,6 +145,7 @@ class ResList : public RESLIST_PARENTCLASS
bool scrollIsAtTop(); bool scrollIsAtTop();
bool scrollIsAtBottom(); bool scrollIsAtBottom();
void setupArrows(); void setupArrows();
void newSnippetsW(const Rcl::Doc &doc);
}; };

View file

@ -232,6 +232,11 @@ void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
linksbuf << "<a href=\"E" << docnumforlinks << "\">" linksbuf << "<a href=\"E" << docnumforlinks << "\">"
<< trans("Open") << "</a>"; << trans("Open") << "</a>";
} }
ostringstream snipsbuf;
if (doc.haspages) {
snipsbuf << "<a href=\"A" << docnumforlinks << "\">"
<< trans("Snippets") << "</a>&nbsp;&nbsp;";
}
// Build the result list paragraph: // Build the result list paragraph:
@ -245,6 +250,7 @@ void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
map<string, string> subs; map<string, string> subs;
subs["A"] = !richabst.empty() ? richabst : ""; subs["A"] = !richabst.empty() ? richabst : "";
subs["D"] = datebuf; subs["D"] = datebuf;
subs["E"] = snipsbuf.rdbuf()->str();
subs["I"] = iconurl; subs["I"] = iconurl;
subs["i"] = doc.ipath; subs["i"] = doc.ipath;
subs["K"] = !doc.meta[Rcl::Doc::keykw].empty() ? subs["K"] = !doc.meta[Rcl::Doc::keykw].empty() ?
@ -279,6 +285,16 @@ void ResListPager::displayDoc(RclConfig *config, int i, Rcl::Doc& doc,
append(chunk.rdbuf()->str(), i, doc); append(chunk.rdbuf()->str(), i, doc);
} }
bool ResListPager::getDoc(int num, Rcl::Doc& doc)
{
if (m_winfirst < 0 || m_respage.size() == 0)
return false;
if (num < m_winfirst || num >= m_winfirst + int(m_respage.size()))
return false;
doc = m_respage[num-m_winfirst].doc;
return true;
}
void ResListPager::displayPage(RclConfig *config) void ResListPager::displayPage(RclConfig *config)
{ {
LOGDEB(("ResListPager::displayPage\n")); LOGDEB(("ResListPager::displayPage\n"));
@ -384,7 +400,7 @@ void ResListPager::displayPage(RclConfig *config)
// Emit data for result entry paragraph. Do it in chunks that make sense // Emit data for result entry paragraph. Do it in chunks that make sense
// html-wise, else our client may get confused // html-wise, else our client may get confused
for (int i = 0; i < (int)m_respage.size(); i++) { for (int i = 0; i < (int)m_respage.size(); i++) {
Rcl::Doc &doc(m_respage[i].doc); Rcl::Doc& doc(m_respage[i].doc);
string& sh(m_respage[i].subHeader); string& sh(m_respage[i].subHeader);
displayDoc(config, i, doc, hdata, sh); displayDoc(config, i, doc, hdata, sh);
} }

View file

@ -90,6 +90,8 @@ public:
string queryDescription() {return m_docSource.isNull() ? "" : string queryDescription() {return m_docSource.isNull() ? "" :
m_docSource->getDescription();} m_docSource->getDescription();}
bool getDoc(int num, Rcl::Doc &doc);
// Things that need to be reimplemented in the subclass: // Things that need to be reimplemented in the subclass:
virtual bool append(const string& data); virtual bool append(const string& data);
virtual bool append(const string& data, int, const Rcl::Doc&) virtual bool append(const string& data, int, const Rcl::Doc&)

View file

@ -112,10 +112,17 @@ class Doc {
// and indexed // and indexed
string text; string text;
/////////////////////////////////////////////////
// Misc stuff
int pc; // relevancy percentage, used by sortseq, convenience int pc; // relevancy percentage, used by sortseq, convenience
unsigned long xdocid; // Opaque: rcldb doc identifier. unsigned long xdocid; // Opaque: rcldb doc identifier.
// Page breaks were stored during indexing.
bool haspages;
/////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////
void erase() { void erase() {
url.erase(); url.erase();
ipath.erase(); ipath.erase();
@ -133,8 +140,12 @@ class Doc {
text.erase(); text.erase();
pc = 0; pc = 0;
xdocid = 0; xdocid = 0;
haspages = false;
}
Doc()
: syntabs(false), pc(0), xdocid(0), haspages(false)
{
} }
/** Get value for named field. If value pointer is 0, just test existence */ /** Get value for named field. If value pointer is 0, just test existence */
bool getmeta(const string& nm, string *value = 0) const bool getmeta(const string& nm, string *value = 0) const
{ {

View file

@ -325,6 +325,7 @@ bool Query::makeDocAbstract(Doc &doc, vector<string>& abstract)
it != vpabs.end(); it++) { it != vpabs.end(); it++) {
string chunk; string chunk;
if (it->first > 0) { if (it->first > 0) {
doc.haspages = true;
ostringstream ss; ostringstream ss;
ss << it->first; ss << it->first;
chunk += string(" [p ") + ss.str() + "] "; chunk += string(" [p ") + ss.str() + "] ";