diff --git a/src/kde/kioslave/kio_recoll/htmlif.cpp b/src/kde/kioslave/kio_recoll/htmlif.cpp index 083be203..d31cd62c 100644 --- a/src/kde/kioslave/kio_recoll/htmlif.cpp +++ b/src/kde/kioslave/kio_recoll/htmlif.cpp @@ -204,24 +204,32 @@ void RecollProtocol::queryDetails() class PlainToRichKio : public PlainToRich { public: PlainToRichKio(const string& nm) - : PlainToRich() , m_name(nm) + : m_name(nm) { } - virtual ~PlainToRichKio() {} + virtual string header() { if (m_inputhtml) { - return snull; + return cstr_null; } else { - return - string("
" - ""); + return string("" + ""). + append(m_name). + append(" "); } } - virtual string startMatch() {return string("");} - virtual string endMatch() {return string("");} + + virtual string startMatch(unsigned int) + { + return string(""); + } + + virtual string endMatch() + { + return string(""); + } + const string &m_name; }; diff --git a/src/qtgui/preview_w.cpp b/src/qtgui/preview_w.cpp index b0e8ab01..a0105175 100644 --- a/src/qtgui/preview_w.cpp +++ b/src/qtgui/preview_w.cpp @@ -68,54 +68,130 @@ using std::pair; // Subclass plainToRich to adds and anchors to the preview text class PlainToRichQtPreview : public PlainToRich { public: - int lastanchor; - PlainToRichQtPreview() + + PlainToRichQtPreview() + : m_curanchor(1), m_lastanchor(0) { - lastanchor = 0; } - virtual ~PlainToRichQtPreview() {} - virtual string header() { + + bool haveAnchors() + { + return m_lastanchor != 0; + } + + virtual string header() + { if (m_inputhtml) { - return snull; + return cstr_null; } else { if (prefs.previewPlainPre) { m_eolbr = false; return string(" " " "); -// Note we could also use the following for line-folding instead of
s -// This would be possible without recomputing the whole text, much better perfs -// for toggling wrap/no-wrap -// ""); + // Note: we could also use the following for + // line-folding instead of
s This would be + // possible without recomputing the whole text, much + // better perfs for toggling wrap/no-wrap: + //} else { m_eolbr = true; return string(""); } } } - virtual string startMatch() + + virtual string startMatch(unsigned int grpidx) { - return string(""); + LOGDEB2(("startMatch, grpidx %u\n", grpidx)); + grpidx = m_hdata->grpsugidx[grpidx]; + LOGDEB2(("startMatch, ugrpidx %u\n", grpidx)); + m_groupanchors[grpidx].push_back(++m_lastanchor); + m_groupcuranchors[grpidx] = 0; + return string(""). + append(""); } - virtual string endMatch() {return string("");} - virtual string termAnchorName(int i) { + + virtual string endMatch() + { + return string(""); + } + + virtual string termAnchorName(int i) const + { static const char *termAnchorNameBase = "TRM"; char acname[sizeof(termAnchorNameBase) + 20]; sprintf(acname, "%s%d", termAnchorNameBase, i); - if (i > lastanchor) - lastanchor = i; return string(acname); } - virtual string startAnchor(int i) { - return string(""; + virtual string startChunk() + { + return " "; } - virtual string endAnchor() { - return string(""); + + int nextAnchorNum(int grpidx) + { + LOGDEB2(("nextAnchorNum: group %d\n", grpidx)); + map::iterator curit = + m_groupcuranchors.find(grpidx); + map >::iterator vecit = + m_groupanchors.find(grpidx); + if (grpidx == -1 || curit == m_groupcuranchors.end() || + vecit == m_groupanchors.end()) { + if (m_curanchor >= m_lastanchor) + m_curanchor = 1; + else + m_curanchor++; + } else { + if (curit->second >= vecit->second.size() -1) + m_groupcuranchors[grpidx] = 0; + else + m_groupcuranchors[grpidx]++; + m_curanchor = vecit->second[m_groupcuranchors[grpidx]]; + LOGDEB2(("nextAnchorNum: curanchor now %d\n", m_curanchor)); + } + return m_curanchor; } - virtual string startChunk() { return " ";} + + int prevAnchorNum(int grpidx) + { + map::iterator curit = + m_groupcuranchors.find(grpidx); + map >::iterator vecit = + m_groupanchors.find(grpidx); + if (grpidx == -1 || curit == m_groupcuranchors.end() || + vecit == m_groupanchors.end()) { + if (m_curanchor <= 1) + m_curanchor = m_lastanchor; + else + m_curanchor--; + } else { + if (curit->second <= 0) + m_groupcuranchors[grpidx] = vecit->second.size() -1; + else + m_groupcuranchors[grpidx]--; + m_curanchor = vecit->second[m_groupcuranchors[grpidx]]; + } + return m_curanchor; + } + + QString curAnchorName() const + { + return QString::fromUtf8(termAnchorName(m_curanchor).c_str()); + } + +private: + int m_curanchor; + int m_lastanchor; + // Lists of anchor numbers (match locations) for the term (groups) + // in the query (the map key is and index into HighlightData.groups). + map > m_groupanchors; + map m_groupcuranchors; }; void Preview::init() @@ -141,8 +217,24 @@ void Preview::init() QHBoxLayout *layout3 = new QHBoxLayout(0); searchLabel = new QLabel(this); layout3->addWidget(searchLabel); - searchTextLine = new QLineEdit(this); - layout3->addWidget(searchTextLine); + + searchTextCMB = new QComboBox(this); + searchTextCMB->setEditable(true); + searchTextCMB->setInsertPolicy(QComboBox::NoInsert); + searchTextCMB->setDuplicatesEnabled(false); + for (unsigned int i = 0; i < m_hData.ugroups.size(); i++) { + QString s; + for (unsigned int j = 0; j < m_hData.ugroups[i].size(); j++) { + s.append(QString::fromUtf8(m_hData.ugroups[i][j].c_str())); + if (j != m_hData.ugroups[i].size()-1) + s.append(" "); + } + searchTextCMB->addItem(s); + } + searchTextCMB->setEditText(""); + + layout3->addWidget(searchTextCMB); + nextButton = new QPushButton(this); nextButton->setEnabled(TRUE); layout3->addWidget(nextButton); @@ -160,7 +252,7 @@ void Preview::init() resize(QSize(640, 480).expandedTo(minimumSizeHint())); // buddies - searchLabel->setBuddy(searchTextLine); + searchLabel->setBuddy(searchTextCMB); searchLabel->setText(tr("&Search for:")); nextButton->setText(tr("&Next")); @@ -176,26 +268,25 @@ void Preview::init() "RCL.SEARCH.PREVIEW"); // signals and slots connections - connect(searchTextLine, SIGNAL(textChanged(const QString&)), - this, SLOT(searchTextLine_textChanged(const QString&))); + connect(searchTextCMB, SIGNAL(activated(int)), + this, SLOT(searchTextFromIndex(int))); + connect(searchTextCMB, SIGNAL(editTextChanged(const QString&)), + this, SLOT(searchTextChanged(const QString&))); connect(nextButton, SIGNAL(clicked()), this, SLOT(nextPressed())); connect(prevButton, SIGNAL(clicked()), this, SLOT(prevPressed())); - connect(clearPB, SIGNAL(clicked()), searchTextLine, SLOT(clear())); + connect(clearPB, SIGNAL(clicked()), searchTextCMB, SLOT(clearEditText())); connect(pvTab, SIGNAL(currentChanged(QWidget *)), this, SLOT(currentChanged(QWidget *))); connect(bt, SIGNAL(clicked()), this, SLOT(closeCurrentTab())); m_dynSearchActive = false; m_canBeep = true; - m_currentW = 0; if (prefs.pvwidth > 100) { resize(prefs.pvwidth, prefs.pvheight); } m_loading = false; currentChanged(pvTab->currentWidget()); m_justCreated = true; - m_haveAnchors = false; - m_curAnchor = 1; } void Preview::closeEvent(QCloseEvent *e) @@ -273,11 +364,11 @@ bool Preview::eventFilter(QObject *target, QEvent *event) } else if (m_dynSearchActive) { if (keyEvent->key() == Qt::Key_F3) { LOGDEB2(("Preview::eventFilter: got F3\n")); - doSearch(searchTextLine->text(), true, false); + doSearch(searchTextCMB->currentText(), true, false); return true; } - if (target != searchTextLine) - return QApplication::sendEvent(searchTextLine, event); + if (target != searchTextCMB) + return QApplication::sendEvent(searchTextCMB, event); } else { if (edit && (target == edit || target == edit->viewport())) { @@ -285,7 +376,7 @@ bool Preview::eventFilter(QObject *target, QEvent *event) (keyEvent->key() == Qt::Key_F && (keyEvent->modifiers() & Qt::ControlModifier))) { LOGDEB2(("Preview::eventFilter: got / or C-F\n")); - searchTextLine->setFocus(); + searchTextCMB->setFocus(); m_dynSearchActive = true; return true; } else if (keyEvent->key() == Qt::Key_Space) { @@ -307,23 +398,27 @@ bool Preview::eventFilter(QObject *target, QEvent *event) return false; } -void Preview::searchTextLine_textChanged(const QString & text) +void Preview::searchTextChanged(const QString & text) { - LOGDEB2(("search line text changed. text: '%s'\n", text.ascii())); + LOGDEB1(("Search line text changed. text: '%s'\n", + (const char *)text.toAscii())); + m_searchTextFromIndex = -1; if (text.isEmpty()) { m_dynSearchActive = false; - // nextButton->setEnabled(false); - // prevButton->setEnabled(false); clearPB->setEnabled(false); } else { m_dynSearchActive = true; - // nextButton->setEnabled(true); - // prevButton->setEnabled(true); clearPB->setEnabled(true); doSearch(text, false, false); } } +void Preview::searchTextFromIndex(int idx) +{ + LOGDEB1(("search line from index %d\n", idx)); + m_searchTextFromIndex = idx; +} + PreviewTextEdit *Preview::currentEditor() { LOGDEB2(("Preview::currentEditor()\n")); @@ -351,9 +446,9 @@ void Preview::emitSaveDocToFile() void Preview::doSearch(const QString &_text, bool next, bool reverse, bool wordOnly) { - LOGDEB(("Preview::doSearch: text [%s] txtlen %d next %d rev %d word %d\n", - (const char *)_text.toUtf8(), _text.length(), int(next), - int(reverse), int(wordOnly))); + LOGDEB(("Preview::doSearch: text [%s] idx %d next %d rev %d word %d\n", + (const char *)_text.toUtf8(), m_searchTextFromIndex, int(next), + int(reverse), int(wordOnly))); QString text = _text; bool matchCase = matchCheck->isChecked(); @@ -363,25 +458,19 @@ void Preview::doSearch(const QString &_text, bool next, bool reverse, return; } - if (text.isEmpty()) { - if (m_haveAnchors == false) { + if (text.isEmpty() || m_searchTextFromIndex != -1) { + if (!edit->m_plaintorich->haveAnchors()) { LOGDEB(("NO ANCHORS\n")); return; } + // The combobox indices are equal to the search ugroup indices + // in hldata, that's how we built the list. if (reverse) { - if (m_curAnchor == 1) - m_curAnchor = edit->m_plaintorich->lastanchor; - else - m_curAnchor--; + edit->m_plaintorich->prevAnchorNum(m_searchTextFromIndex); } else { - if (m_curAnchor == edit->m_plaintorich->lastanchor) - m_curAnchor = 1; - else - m_curAnchor++; + edit->m_plaintorich->nextAnchorNum(m_searchTextFromIndex); } - LOGDEB(("m_curAnchor: %d\n", m_curAnchor)); - QString aname = - QString::fromUtf8(edit->m_plaintorich->termAnchorName(m_curAnchor).c_str()); + QString aname = edit->m_plaintorich->curAnchorName(); LOGDEB(("Calling scrollToAnchor(%s)\n", (const char *)aname.toUtf8())); edit->scrollToAnchor(aname); // Position the cursor approximately at the anchor (top of @@ -440,14 +529,14 @@ void Preview::doSearch(const QString &_text, bool next, bool reverse, void Preview::nextPressed() { - LOGDEB2(("PreviewTextEdit::nextPressed\n")); - doSearch(searchTextLine->text(), true, false); + LOGDEB2(("Preview::nextPressed\n")); + doSearch(searchTextCMB->currentText(), true, false); } void Preview::prevPressed() { - LOGDEB2(("PreviewTextEdit::prevPressed\n")); - doSearch(searchTextLine->text(), true, true); + LOGDEB2(("Preview::prevPressed\n")); + doSearch(searchTextCMB->currentText(), true, true); } // Called when user clicks on tab @@ -456,7 +545,6 @@ void Preview::currentChanged(QWidget * tw) LOGDEB2(("PreviewTextEdit::currentChanged\n")); PreviewTextEdit *edit = tw->findChild ("pvEdit"); - m_currentW = tw; LOGDEB1(("Preview::currentChanged(). Editor: %p\n", edit)); if (edit == 0) { @@ -470,7 +558,7 @@ void Preview::currentChanged(QWidget * tw) connect(this, SIGNAL(printCurrentPreviewRequest()), edit, SLOT(print())); edit->installEventFilter(this); edit->viewport()->installEventFilter(this); - searchTextLine->installEventFilter(this); + searchTextCMB->installEventFilter(this); emit(previewExposed(this, m_searchId, edit->m_docnum)); } @@ -507,7 +595,7 @@ PreviewTextEdit *Preview::addEditorTab() void Preview::setCurTabProps(const Rcl::Doc &doc, int docnum) { - LOGDEB1(("PreviewTextEdit::setCurTabProps\n")); + LOGDEB1(("Preview::setCurTabProps\n")); QString title; string ctitle; if (doc.getmeta(Rcl::Doc::keytt, &ctitle) && !ctitle.empty()) { @@ -721,8 +809,6 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum) LoadGuard guard(&m_loading); CancelCheck::instance().setCancel(false); - m_haveAnchors = false; - setCurTabProps(idoc, docnum); QString msg = QString("Loading: %1 (size %2 bytes)") @@ -956,23 +1042,20 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum) // Position the editor so that the first search term is visible - m_haveAnchors = editor->m_plaintorich->lastanchor != 0; - if (searchTextLine->text().length() != 0) { + if (searchTextCMB->currentText().length() != 0) { // If there is a current search string, perform the search m_canBeep = true; - doSearch(searchTextLine->text(), true, false); + doSearch(searchTextCMB->currentText(), true, false); } else { // Position to the first query term - if (m_haveAnchors) { - QString aname = - QString::fromUtf8(editor->m_plaintorich->termAnchorName(1).c_str()); + if (editor->m_plaintorich->haveAnchors()) { + QString aname = editor->m_plaintorich->curAnchorName(); LOGDEB2(("Call movetoanchor(%s)\n", (const char *)aname.toUtf8())); editor->scrollToAnchor(aname); // Position the cursor approximately at the anchor (top of // viewport) so that searches start from here QTextCursor cursor = editor->cursorForPosition(QPoint(0, 0)); editor->setTextCursor(cursor); - m_curAnchor = 1; } } @@ -989,14 +1072,15 @@ bool Preview::loadDocInCurrentTab(const Rcl::Doc &idoc, int docnum) return true; } -PreviewTextEdit::PreviewTextEdit(QWidget* parent,const char* name, Preview *pv) - : QTextEdit(parent), m_preview(pv), m_dspflds(false), m_docnum(-1) +PreviewTextEdit::PreviewTextEdit(QWidget* parent, const char* nm, Preview *pv) + : QTextEdit(parent), m_preview(pv), + m_plaintorich(new PlainToRichQtPreview()), + m_dspflds(false), m_docnum(-1) { setContextMenuPolicy(Qt::CustomContextMenu); - setObjectName(name); + setObjectName(nm); connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(createPopupMenu(const QPoint&))); - m_plaintorich = new PlainToRichQtPreview(); } PreviewTextEdit::~PreviewTextEdit() diff --git a/src/qtgui/preview_w.h b/src/qtgui/preview_w.h index f9b1591b..ab479376 100644 --- a/src/qtgui/preview_w.h +++ b/src/qtgui/preview_w.h @@ -58,22 +58,27 @@ protected: void mouseDoubleClickEvent(QMouseEvent *); private: - PlainToRichQtPreview *m_plaintorich; Preview *m_preview; - bool m_dspflds; + PlainToRichQtPreview *m_plaintorich; + + bool m_dspflds; string m_url; // filename for this tab string m_ipath; // Internal doc path inside file int m_docnum; // Index of doc in db search results. + // doc out of internfile (previous fields come from the index) with // main text erased (for space). Rcl::Doc m_fdoc; + // The input doc out of the index/query list Rcl::Doc m_dbdoc; + // Saved rich (or plain actually) text: the textedit seems to // sometimes (but not always) return its text stripped of tags, so // this is needed (for printing for example) QString m_richtxt; Qt::TextFormat m_format; + // Temporary file name (possibly, if displaying image). The // TempFile itself is kept inside main.cpp (because that's where // signal cleanup happens), but we use its name to ask for release @@ -92,14 +97,14 @@ class Preview : public QWidget { Preview(int sid, // Search Id const HighlightData& hdata) // Search terms etc. for highlighting - : QWidget(0), m_searchId(sid), m_hData(hdata) + : QWidget(0), m_searchId(sid), m_searchTextFromIndex(-1), m_hData(hdata) { init(); } - ~Preview(){} virtual void closeEvent(QCloseEvent *e ); virtual bool eventFilter(QObject *target, QEvent *event ); + /** * Arrange for the document to be displayed either by exposing the tab * if already loaded, or by creating a new tab and loading it. @@ -112,7 +117,8 @@ class Preview : public QWidget { friend class PreviewTextEdit; public slots: - virtual void searchTextLine_textChanged(const QString& text); + virtual void searchTextChanged(const QString& text); + virtual void searchTextFromIndex(int); virtual void doSearch(const QString& str, bool next, bool reverse, bool wo = false); virtual void nextPressed(); @@ -138,18 +144,17 @@ private: int m_searchId; bool m_dynSearchActive; + // Index value the search text comes from. -1 if text was edited + int m_searchTextFromIndex; + bool m_canBeep; bool m_loading; - QWidget *m_currentW; HighlightData m_hData; bool m_justCreated; // First tab create is different - bool m_haveAnchors; // Search terms are marked in text - int m_lastAnchor; // Number of last anchor. Then rewind to 1 - int m_curAnchor; QTabWidget* pvTab; QLabel* searchLabel; - QLineEdit* searchTextLine; + QComboBox *searchTextCMB; QPushButton* nextButton; QPushButton* prevButton; QPushButton* clearPB; diff --git a/src/qtgui/reslist.cpp b/src/qtgui/reslist.cpp index c3fc7ddb..491d93cf 100644 --- a/src/qtgui/reslist.cpp +++ b/src/qtgui/reslist.cpp @@ -250,12 +250,22 @@ string QtGuiResListPager::iconUrl(RclConfig *config, Rcl::Doc& doc) class PlainToRichQtReslist : public PlainToRich { public: - virtual ~PlainToRichQtReslist() {} - virtual string startMatch() { + virtual string startMatch(unsigned int idx) + { + if (m_hdata) { + string s1, s2; + stringsToString >(m_hdata->groups[idx], s1); + stringsToString >(m_hdata->ugroups[m_hdata->grpsugidx[idx]], s2); + LOGDEB(("Reslist startmatch: group %s user group %s\n", s1.c_str(), s2.c_str())); + } + return string(""); } - virtual string endMatch() {return string("");} + virtual string endMatch() + { + return string(""); + } }; static PlainToRichQtReslist g_hiliter; diff --git a/src/qtgui/ssearch_w.h b/src/qtgui/ssearch_w.h index f1156f42..16176c39 100644 --- a/src/qtgui/ssearch_w.h +++ b/src/qtgui/ssearch_w.h @@ -38,7 +38,6 @@ public: setupUi(this); init(); } - ~SSearch(){} virtual void init(); virtual void setAnyTermMode(); diff --git a/src/query/plaintorich.cpp b/src/query/plaintorich.cpp index 57e32d18..8cb45ad7 100644 --- a/src/query/plaintorich.cpp +++ b/src/query/plaintorich.cpp @@ -49,13 +49,22 @@ static string vecStringToString(const vector & t) return sterms; } +struct MatchEntry { + pair offs; + unsigned int grpidx; + MatchEntry(int sta, int sto, unsigned int idx) + : offs(sta, sto), grpidx(idx) + { + } +}; + // Text splitter used to take note of the position of query terms // inside the result text. This is then used to insert highlight tags. class TextSplitPTR : public TextSplit { public: // Out: begin and end byte positions of query terms/groups in text - vector > tboffs; + vector tboffs; TextSplitPTR(const HighlightData& hdata) : m_wcount(0), m_hdata(hdata) @@ -67,7 +76,7 @@ class TextSplitPTR : public TextSplit { for (vector >::const_iterator vit = hdata.groups.begin(); vit != hdata.groups.end(); vit++) { if (vit->size() == 1) { - m_terms.insert(vit->front()); + m_terms[vit->front()] = vit - hdata.groups.begin(); } else if (vit->size() > 1) { for (vector ::const_iterator it = vit->begin(); it != vit->end(); it++) { @@ -91,8 +100,9 @@ class TextSplitPTR : public TextSplit { // pos, bts, bte)); // If this word is a search term, remember its byte-offset span. - if (m_terms.find(dumb) != m_terms.end()) { - tboffs.push_back(pair (bts, bte)); + map ::const_iterator it = m_terms.find(dumb); + if (it != m_terms.end()) { + tboffs.push_back(MatchEntry(bts, bte, (*it).second)); } // If word is part of a search group, update its positions list @@ -114,13 +124,13 @@ class TextSplitPTR : public TextSplit { virtual bool matchGroups(); private: - virtual bool matchGroup(const vector & terms, int dist); + virtual bool matchGroup(unsigned int idx); // Word count. Used to call checkCancel from time to time. int m_wcount; // In: user query terms - set m_terms; + map m_terms; // m_gterms holds all the terms in m_groups, as a set for quick lookup set m_gterms; @@ -191,9 +201,12 @@ static bool do_proximity_test(int window, vector * >& plists, return false; } -// Find NEAR matches for the input group of terms, update highlight map -bool TextSplitPTR::matchGroup(const vector & terms, int window) +// Find NEAR matches for one group of terms, update highlight map +bool TextSplitPTR::matchGroup(unsigned int grpidx) { + const vector & terms = m_hdata.groups[grpidx]; + int window = m_hdata.groups[grpidx].size() + m_hdata.slacks[grpidx]; + LOGDEB0(("TextSplitPTR::matchGroup:d %d: %s\n", window, vecStringToString(terms).c_str())); @@ -203,26 +216,23 @@ bool TextSplitPTR::matchGroup(const vector & terms, int window) // A revert plist->term map. This is so that we can find who is who after // sorting the plists by length. map *, string> plistToTerm; - // For traces - vector realgroup; - // Find the position list for each term in the group. Not all - // necessarily exist (esp for NEAR where terms have been - // stem-expanded: we don't know which matched) + // Find the position list for each term in the group. It is + // possible that this particular group was not actually matched by + // the search, so that some terms are not found. for (vector ::const_iterator it = terms.begin(); it != terms.end(); it++) { map >::iterator pl = m_plists.find(*it); if (pl == m_plists.end()) { LOGDEB0(("TextSplitPTR::matchGroup: [%s] not found in m_plists\n", (*it).c_str())); - continue; + return false; } plists.push_back(&(pl->second)); plistToTerm[&(pl->second)] = *it; - realgroup.push_back(*it); } - LOGDEB0(("TextSplitPTR::matchGroup:d %d:real group after expansion %s\n", - window, vecStringToString(realgroup).c_str())); + // I think this can't actually happen, was useful when we used to + // prune the groups, but doesn't hurt. if (plists.size() < 2) { LOGDEB0(("TextSplitPTR::matchGroup: no actual groups found\n")); return false; @@ -261,15 +271,13 @@ bool TextSplitPTR::matchGroup(const vector & terms, int window) SETMINMAX(pos, sta, sto); minpos = sto+1; // Translate the position window into a byte offset window - int bs = 0; map >::iterator i1 = m_gpostobytes.find(sta); map >::iterator i2 = m_gpostobytes.find(sto); if (i1 != m_gpostobytes.end() && i2 != m_gpostobytes.end()) { LOGDEB0(("TextSplitPTR::matchGroup: pushing bpos %d %d\n", i1->second.first, i2->second.second)); - tboffs.push_back(pair (i1->second.first, - i2->second.second)); - bs = i1->second.first; + tboffs.push_back(MatchEntry(i1->second.first, + i2->second.second, grpidx)); } else { LOGDEB(("matchGroup: no bpos found for %d or %d\n", sta, sto)); } @@ -284,22 +292,23 @@ bool TextSplitPTR::matchGroup(const vector & terms, int window) /** Sort integer pairs by increasing first value and decreasing width */ class PairIntCmpFirst { public: - bool operator()(pair a, pair b) { - if (a.first != b.first) - return a.first < b.first; - return a.second > b.second; + bool operator()(const MatchEntry& a, const MatchEntry& b) { + if (a.offs.first != b.offs.first) + return a.offs.first < b.offs.first; + return a.offs.second > b.offs.second; } }; -// Look for matches to PHRASE and NEAR term groups. Actually, we -// handle all groups as NEAR (ignore order). +// Look for matches to PHRASE and NEAR term groups and finalize the +// matched regions list (sort it by increasing start then decreasing +// length) +// Actually, we handle all groups as NEAR (ignore order). bool TextSplitPTR::matchGroups() { for (unsigned int i = 0; i < m_hdata.groups.size(); i++) { if (m_hdata.groups[i].size() <= 1) continue; - matchGroup(m_hdata.groups[i], - m_hdata.groups[i].size() + m_hdata.slacks[i]); + matchGroup(i); } // Sort regions by increasing start and decreasing width. @@ -324,6 +333,7 @@ bool PlainToRich::plaintorich(const string& in, { Chrono chron; + m_hdata = &hdata; // Compute the positions for the query terms. We use the text // splitter to break the text into words, and compare the words to // the search terms, @@ -346,8 +356,8 @@ bool PlainToRich::plaintorich(const string& in, // Iterator for the list of input term positions. We use it to // output highlight tags and to compute term positions in the // output text - vector >::iterator tPosIt = splitter.tboffs.begin(); - vector >::iterator tPosEnd = splitter.tboffs.end(); + vector ::iterator tPosIt = splitter.tboffs.begin(); + vector ::iterator tPosEnd = splitter.tboffs.end(); #if 0 for (vector >::const_iterator it = splitter.tboffs.begin(); @@ -365,8 +375,6 @@ bool PlainToRich::plaintorich(const string& in, int hadcr = 0; int inindent = 1; - // Value for numbered anchors at each term match - int anchoridx = 1; // HTML state bool intag = false, inparamvalue = false; // My tag state @@ -391,22 +399,20 @@ bool PlainToRich::plaintorich(const string& in, // we are at or after a term match, mark. if (tPosIt != tPosEnd) { int ibyteidx = chariter.getBpos(); - if (ibyteidx == tPosIt->first) { + if (ibyteidx == tPosIt->offs.first) { if (!intag && ibyteidx >= (int)headend) { - *olit += startAnchor(anchoridx); - *olit += startMatch(); + *olit += startMatch(tPosIt->grpidx); } - anchoridx++; inrcltag = 1; - } else if (ibyteidx == tPosIt->second) { + } else if (ibyteidx == tPosIt->offs.second) { // Output end of match region tags if (!intag && ibyteidx > (int)headend) { *olit += endMatch(); - *olit += endAnchor(); } // Skip all highlight areas that would overlap this one - int crend = tPosIt->second; - while (tPosIt != splitter.tboffs.end() && tPosIt->first < crend) + int crend = tPosIt->offs.second; + while (tPosIt != splitter.tboffs.end() && + tPosIt->offs.first < crend) tPosIt++; inrcltag = 0; } diff --git a/src/query/plaintorich.h b/src/query/plaintorich.h index 21ddbc98..cbb13d9e 100644 --- a/src/query/plaintorich.h +++ b/src/query/plaintorich.h @@ -21,6 +21,7 @@ #include #include "hldata.h" +#include "cstr.h" /** * A class for highlighting search results. Overridable methods allow @@ -31,7 +32,7 @@ class PlainToRich { public: PlainToRich() - : m_inputhtml(false) + : m_inputhtml(false), m_eolbr(false), m_hdata(0) { } @@ -71,18 +72,35 @@ public: ); /* Overridable output methods for headers, highlighting and marking tags */ - virtual std::string header() {return snull;} - virtual std::string startMatch() {return snull;} - virtual std::string endMatch() {return snull;} - virtual std::string startAnchor(int) {return snull;} - virtual std::string endAnchor() {return snull;} - virtual std::string startChunk() {return snull;} + + virtual std::string header() + { + return cstr_null; + } + + /** Return match prefix (e.g.:
). + @param groupidx the index into hdata.groups */ + virtual std::string startMatch(unsigned int) + { + return cstr_null; + } + + /** Return data for end of match area (e.g.:). */ + virtual std::string endMatch() + { + return cstr_null; + } + + virtual std::string startChunk() + { + return cstr_null; + } protected: - const std::string snull; bool m_inputhtml; // Use
to break plain text lines (else caller has used atag) bool m_eolbr; + const HighlightData *m_hdata; }; #endif /* _PLAINTORICH_H_INCLUDED_ */ diff --git a/src/query/reslistpager.cpp b/src/query/reslistpager.cpp index 7027dd94..9718709f 100644 --- a/src/query/reslistpager.cpp +++ b/src/query/reslistpager.cpp @@ -40,9 +40,14 @@ static const string cstr_hlfontcolor(""); static const string cstr_hlendfont(""); class PlainToRichHtReslist : public PlainToRich { public: - virtual ~PlainToRichHtReslist() {} - virtual string startMatch() {return cstr_hlfontcolor;} - virtual string endMatch() {return cstr_hlendfont;} + virtual string startMatch(unsigned int) + { + return cstr_hlfontcolor; + } + virtual string endMatch() + { + return cstr_hlendfont; + } }; static PlainToRichHtReslist g_hiliter;