diff --git a/autotests/searchtest.cpp b/autotests/searchtest.cpp
--- a/autotests/searchtest.cpp
+++ b/autotests/searchtest.cpp
@@ -80,7 +80,7 @@
#define TEST_NEXT_PREV(searchType, expectedStatus) \
{ \
- Okular::RegularAreaRect* result = tp->findText(0, searchString, searchType, Qt::CaseSensitive, NULL); \
+ Okular::RegularAreaRect* result = tp->findText(0, searchString, searchType, Qt::CaseSensitive, NULL, false); \
QCOMPARE(!!result, expectedStatus); \
delete result; \
}
@@ -178,7 +178,7 @@
d.openDocument(testFile, QUrl(), mime);
const int searchId = 0;
- d.searchText(searchId, QStringLiteral(" i "), true, Qt::CaseSensitive, Okular::Document::NextMatch, false, QColor());
+ d.searchText(searchId, QStringLiteral(" i "), true, Qt::CaseSensitive, Okular::Document::NextMatch, false, QColor(), false);
QTRY_COMPARE(spy.count(), 1);
QCOMPARE(receiver.m_id, searchId);
QCOMPARE(receiver.m_status, Okular::Document::MatchFound);
@@ -200,7 +200,7 @@
CREATE_PAGE;
- Okular::RegularAreaRect* result = tp->findText(0, QStringLiteral("a"), Okular::FromBottom, Qt::CaseSensitive, nullptr);
+ Okular::RegularAreaRect* result = tp->findText(0, QStringLiteral("a"), Okular::FromBottom, Qt::CaseSensitive, nullptr, false);
QVERIFY(result);
delete result;
@@ -219,7 +219,7 @@
CREATE_PAGE;
- Okular::RegularAreaRect* result = tp->findText(0, QStringLiteral("ab"), Okular::FromTop, Qt::CaseSensitive, nullptr);
+ Okular::RegularAreaRect* result = tp->findText(0, QStringLiteral("ab"), Okular::FromTop, Qt::CaseSensitive, nullptr, false);
QVERIFY(result);
Okular::RegularAreaRect expected;
expected.append(rect[1]);
@@ -250,7 +250,7 @@
CREATE_PAGE;
- Okular::RegularAreaRect* result = tp->findText(0, QString::fromUtf8("İ"), Okular::FromTop, Qt::CaseInsensitive, nullptr);
+ Okular::RegularAreaRect* result = tp->findText(0, QString::fromUtf8("İ"), Okular::FromTop, Qt::CaseInsensitive, nullptr, false);
QVERIFY(result);
delete result;
@@ -276,7 +276,7 @@
CREATE_PAGE;
Okular::RegularAreaRect* result = tp->findText(0, QStringLiteral("supercalifragilisticexpialidocious"),
- Okular::FromTop, Qt::CaseSensitive, nullptr);
+ Okular::FromTop, Qt::CaseSensitive, nullptr, false);
QVERIFY(result);
Okular::RegularAreaRect expected;
for (int i = 0; i < text.size(); i++) {
@@ -294,7 +294,7 @@
CREATE_PAGE; \
\
Okular::RegularAreaRect* result = tp->findText(0, QStringLiteral(searchString), \
- Okular::FromTop, Qt::CaseSensitive, NULL); \
+ Okular::FromTop, Qt::CaseSensitive, NULL, false); \
\
QCOMPARE(!!result, matchExpected); \
\
@@ -349,14 +349,14 @@
{
Okular::RegularAreaRect* result = tp->findText(0, QStringLiteral("a"),
- Okular::FromTop, Qt::CaseSensitive, nullptr);
+ Okular::FromTop, Qt::CaseSensitive, nullptr, false);
QVERIFY(result);
delete result;
}
{
Okular::RegularAreaRect* result = tp->findText(0, QStringLiteral("a"),
- Okular::FromBottom, Qt::CaseSensitive, nullptr);
+ Okular::FromBottom, Qt::CaseSensitive, nullptr, false);
QVERIFY(result);
delete result;
}
@@ -388,7 +388,7 @@
CREATE_PAGE;
Okular::RegularAreaRect* result = tp->findText(0, QStringLiteral("Only one column"),
- Okular::FromTop, Qt::CaseSensitive, nullptr);
+ Okular::FromTop, Qt::CaseSensitive, nullptr, false);
QVERIFY(result);
delete result;
@@ -416,7 +416,7 @@
CREATE_PAGE;
Okular::RegularAreaRect* result = tp->findText(0, QStringLiteral("This text in"),
- Okular::FromTop, Qt::CaseSensitive, nullptr);
+ Okular::FromTop, Qt::CaseSensitive, nullptr, false);
QVERIFY(!result);
delete result;
diff --git a/conf/okular.kcfg b/conf/okular.kcfg
--- a/conf/okular.kcfg
+++ b/conf/okular.kcfg
@@ -306,6 +306,9 @@
true
+
+ false
+
diff --git a/core/document.h b/core/document.h
--- a/core/document.h
+++ b/core/document.h
@@ -636,9 +636,10 @@
* @param type The type of the search. @ref SearchType
* @param moveViewport Whether the viewport shall be moved to the position of the matches.
* @param color The highlighting color of the matches.
+ * @param wholeWords Whether the search should only find whole words or not.
*/
void searchText( int searchID, const QString & text, bool fromStart, Qt::CaseSensitivity caseSensitivity,
- SearchType type, bool moveViewport, const QColor & color );
+ SearchType type, bool moveViewport, const QColor & color, bool wholeWords );
/**
* Continues the search for the given @p searchID.
diff --git a/core/document.cpp b/core/document.cpp
--- a/core/document.cpp
+++ b/core/document.cpp
@@ -135,6 +135,7 @@
Document::SearchType cachedType;
Qt::CaseSensitivity cachedCaseSensitivity;
bool cachedViewportMove : 1;
+ bool cachedWholeWords;
bool isCurrentlySearching : 1;
QColor cachedColor;
int pagesDone;
@@ -1669,7 +1670,7 @@
m_parent->requestTextPage( page->number() );
// if found a match on the current page, end the loop
- searchStruct->match = page->findText( searchStruct->searchID, search->cachedString, forward ? FromTop : FromBottom, search->cachedCaseSensitivity );
+ searchStruct->match = page->findText( searchStruct->searchID, search->cachedString, forward ? FromTop : FromBottom, search->cachedCaseSensitivity, nullptr, search->cachedWholeWords );
if ( !searchStruct->match )
{
if (forward) searchStruct->currentPage++;
@@ -3770,7 +3771,7 @@
}
void Document::searchText( int searchID, const QString & text, bool fromStart, Qt::CaseSensitivity caseSensitivity,
- SearchType type, bool moveViewport, const QColor & color )
+ SearchType type, bool moveViewport, const QColor & color, bool wholeWords )
{
d->m_searchCancelled = false;
@@ -3798,6 +3799,7 @@
s->cachedCaseSensitivity = caseSensitivity;
s->cachedViewportMove = moveViewport;
s->cachedColor = color;
+ s->cachedWholeWords = wholeWords;
s->isCurrentlySearching = true;
// global data for search
@@ -3837,9 +3839,9 @@
if ( lastPage && lastPage->number() == s->continueOnPage )
{
if ( newText )
- match = lastPage->findText( searchID, text, forward ? FromTop : FromBottom, caseSensitivity );
+ match = lastPage->findText( searchID, text, forward ? FromTop : FromBottom, caseSensitivity, nullptr, wholeWords );
else
- match = lastPage->findText( searchID, text, forward ? NextResult : PreviousResult, caseSensitivity, &s->continueOnMatch );
+ match = lastPage->findText( searchID, text, forward ? NextResult : PreviousResult, caseSensitivity, &s->continueOnMatch, wholeWords );
if ( !match )
{
if (forward) currentPage++;
@@ -3883,7 +3885,7 @@
RunningSearch * p = *it;
if ( !p->isCurrentlySearching )
searchText( searchID, p->cachedString, false, p->cachedCaseSensitivity,
- p->cachedType, p->cachedViewportMove, p->cachedColor );
+ p->cachedType, p->cachedViewportMove, p->cachedColor, p->cachedWholeWords );
}
void Document::continueSearch( int searchID, SearchType type )
@@ -3900,7 +3902,7 @@
RunningSearch * p = *it;
if ( !p->isCurrentlySearching )
searchText( searchID, p->cachedString, false, p->cachedCaseSensitivity,
- type, p->cachedViewportMove, p->cachedColor );
+ type, p->cachedViewportMove, p->cachedColor, p->cachedWholeWords );
}
void Document::resetSearch( int searchID )
diff --git a/core/page.h b/core/page.h
--- a/core/page.h
+++ b/core/page.h
@@ -186,7 +186,8 @@
* right/below the coordinates of the given rect.
*/
RegularAreaRect* findText( int id, const QString & text, SearchDirection direction,
- Qt::CaseSensitivity caseSensitivity, const RegularAreaRect * lastRect=nullptr) const;
+ Qt::CaseSensitivity caseSensitivity, const RegularAreaRect * lastRect=nullptr,
+ const bool wholeWords=0) const;
/**
* Returns the page text (or part of it).
diff --git a/core/page.cpp b/core/page.cpp
--- a/core/page.cpp
+++ b/core/page.cpp
@@ -301,13 +301,13 @@
}
RegularAreaRect * Page::findText( int id, const QString & text, SearchDirection direction,
- Qt::CaseSensitivity caseSensitivity, const RegularAreaRect *lastRect ) const
+ Qt::CaseSensitivity caseSensitivity, const RegularAreaRect *lastRect,
+ const bool wholeWords ) const
{
RegularAreaRect* rect = nullptr;
if ( text.isEmpty() || !d->m_text )
return rect;
-
- rect = d->m_text->findText( id, text, direction, caseSensitivity, lastRect );
+ rect = d->m_text->findText( id, text, direction, caseSensitivity, lastRect, wholeWords );
return rect;
}
diff --git a/core/textpage.h b/core/textpage.h
--- a/core/textpage.h
+++ b/core/textpage.h
@@ -137,9 +137,11 @@
* the search is case insensitive.
* @param lastRect If 0 the search starts at the beginning of the page, otherwise
* right/below the coordinates of the given rect.
+ * @param wholeWords If true, it will search for whole words only
*/
RegularAreaRect* findText( int id, const QString &text, SearchDirection direction,
- Qt::CaseSensitivity caseSensitivity, const RegularAreaRect *lastRect );
+ Qt::CaseSensitivity caseSensitivity, const RegularAreaRect *lastRect,
+ const bool wholeWords );
/**
* Text extraction function.
diff --git a/core/textpage.cpp b/core/textpage.cpp
--- a/core/textpage.cpp
+++ b/core/textpage.cpp
@@ -714,7 +714,8 @@
RegularAreaRect* TextPage::findText( int searchID, const QString &query, SearchDirection direct,
- Qt::CaseSensitivity caseSensitivity, const RegularAreaRect *area )
+ Qt::CaseSensitivity caseSensitivity, const RegularAreaRect *area,
+ const bool wholeWords )
{
SearchDirection dir=direct;
// invalid search request
@@ -764,11 +765,11 @@
? CaseSensitiveCmpFn : CaseInsensitiveCmpFn;
if ( forward )
{
- ret = d->findTextInternalForward( searchID, query, cmpFn, start, start_offset, end );
+ ret = d->findTextInternalForward( searchID, query, cmpFn, start, start_offset, end, wholeWords );
}
else
{
- ret = d->findTextInternalBackward( searchID, query, cmpFn, start, start_offset, end );
+ ret = d->findTextInternalBackward( searchID, query, cmpFn, start, start_offset, end, wholeWords );
}
return ret;
}
@@ -839,11 +840,64 @@
return ret;
}
+// Checks if the word searched is whole
+
+bool TextPagePrivate::isWholeWord( const TextList::ConstIterator &start,
+ const TextList::ConstIterator &end)
+{
+
+ // Divided in two parts, after the word and before
+ bool part1 = false, part2 = false;
+
+ // If I'm at the beggining/end of the text, I don't need to check after/before
+ if( start == m_words.constBegin() )
+ part1 = true;
+ else
+ {
+ // Else I check if the text before is a number or letter, if it isn't, a word begins here
+ TextList::ConstIterator before = start;
+ before--;
+ const TinyTextEntity* curEntity = *before;
+ const QString& str = curEntity->text();
+ int len = stringLengthAdaptedWithHyphen( str, before, m_words.constEnd() );
+ if( !str[len-1].isLetterOrNumber() ) part1 = true;
+ }
+
+ if( end == m_words.constEnd() )
+ part2 = true;
+ else
+ {
+
+ // For the end is a bit more complicated, some text entities can end at a \n,
+ // and checking the next would get the first char in the next phrase.
+ // So I'm checking this right here.
+ TextList::ConstIterator after = end;
+ const TinyTextEntity* endEntity = *after;
+ const QString& endStr = endEntity->text();
+
+ if( endStr.endsWith( QStringLiteral("\n") ))
+ part2 = true;
+
+ // If it doesn't end in \n, I check the next char, as done in before.
+ else
+ {
+ after++;
+ const TinyTextEntity* curEntity = *after;
+ const QString& str = curEntity->text();
+ int len = stringLengthAdaptedWithHyphen( str, after, m_words.constEnd() );
+ if( !str[0].isLetterOrNumber() ) part2 = true;
+ }
+ }
+
+ return part1 && part2;
+}
+
RegularAreaRect* TextPagePrivate::findTextInternalForward( int searchID, const QString &_query,
TextComparisonFunction comparer,
const TextList::ConstIterator &start,
int start_offset,
- const TextList::ConstIterator &end)
+ const TextList::ConstIterator &end,
+ bool wholeWords )
{
// normalize query search all unicode (including glyphs)
const QString query = _query.normalized(QString::NormalizationForm_KC);
@@ -917,18 +971,32 @@
if (queryLeft==0)
{
- // save or update the search point for the current searchID
- QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID );
- if ( sIt == m_searchPoints.end() )
+ //If it's looking for whole words and this is not a whole word
+ if(wholeWords && !isWholeWord(it_begin, it))
{
- sIt = m_searchPoints.insert( searchID, new SearchPoint );
+ j = 0;
+ queryLeft=query.length();
+ it = it_begin;
+ offset = offset_begin+1;
+ it_begin = TextList::ConstIterator();
}
- SearchPoint* sp = *sIt;
- sp->it_begin = it_begin;
- sp->it_end = it;
- sp->offset_begin = offset_begin;
- sp->offset_end = offset + min;
- return searchPointToArea(sp);
+
+ else
+ {
+ // save or update the search point for the current searchID
+ QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID );
+ if ( sIt == m_searchPoints.end() )
+ {
+ sIt = m_searchPoints.insert( searchID, new SearchPoint );
+ }
+ SearchPoint* sp = *sIt;
+ sp->it_begin = it_begin;
+ sp->it_end = it;
+ sp->offset_begin = offset_begin;
+ sp->offset_end = offset + min;
+ return searchPointToArea(sp);
+ }
+
}
it++;
@@ -952,7 +1020,8 @@
TextComparisonFunction comparer,
const TextList::ConstIterator &start,
int start_offset,
- const TextList::ConstIterator &end)
+ const TextList::ConstIterator &end,
+ bool wholeWords )
{
// normalize query to search all unicode (including glyphs)
const QString query = _query.normalized(QString::NormalizationForm_KC);
@@ -1035,18 +1104,31 @@
if ( queryLeft == 0 )
{
- // save or update the search point for the current searchID
- QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID );
- if ( sIt == m_searchPoints.end() )
+
+ //If it's looking for whole words and this is not a whole word
+ if(wholeWords && !isWholeWord(it, it_begin))
+ {
+ j = 0;
+ queryLeft=query.length();
+ it = it_begin;
+ offset = offset_begin+1;
+ it_begin = TextList::ConstIterator();
+ }
+ else
{
- sIt = m_searchPoints.insert( searchID, new SearchPoint );
+ // save or update the search point for the current searchID
+ QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID );
+ if ( sIt == m_searchPoints.end() )
+ {
+ sIt = m_searchPoints.insert( searchID, new SearchPoint );
+ }
+ SearchPoint* sp = *sIt;
+ sp->it_begin = it;
+ sp->it_end = it_begin;
+ sp->offset_begin = offset - min;
+ sp->offset_end = offset_begin;
+ return searchPointToArea(sp);
}
- SearchPoint* sp = *sIt;
- sp->it_begin = it;
- sp->it_end = it_begin;
- sp->offset_begin = offset - min;
- sp->offset_end = offset_begin;
- return searchPointToArea(sp);
}
offset = 0;
diff --git a/core/textpage_p.h b/core/textpage_p.h
--- a/core/textpage_p.h
+++ b/core/textpage_p.h
@@ -47,18 +47,24 @@
TextComparisonFunction comparer,
const TextList::ConstIterator &start,
int start_offset,
- const TextList::ConstIterator &end);
+ const TextList::ConstIterator &end,
+ bool wholeWords );
RegularAreaRect * findTextInternalBackward( int searchID, const QString &query,
TextComparisonFunction comparer,
const TextList::ConstIterator &start,
int start_offset,
- const TextList::ConstIterator &end );
+ const TextList::ConstIterator &end,
+ bool wholeWords );
/**
* Copy a TextList to m_words, the pointers of list are adopted
*/
void setWordList(const TextList &list);
+
+ bool isWholeWord( const TextList::ConstIterator &start,
+ const TextList::ConstIterator &end);
+
/**
* Make necessary modifications in the TextList to make the text order correct, so
* that textselection works fine
diff --git a/mobile/components/documentitem.cpp b/mobile/components/documentitem.cpp
--- a/mobile/components/documentitem.cpp
+++ b/mobile/components/documentitem.cpp
@@ -181,7 +181,7 @@
m_document->cancelSearch();
m_document->resetSearch(PAGEVIEW_SEARCH_ID);
m_document->searchText(PAGEVIEW_SEARCH_ID, text, 1, Qt::CaseInsensitive,
- Okular::Document::AllDocument, true, QColor(100,100,200,40));
+ Okular::Document::AllDocument, true, QColor(100,100,200,40), false);
if (!m_searchInProgress) {
m_searchInProgress = true;
diff --git a/ui/findbar.h b/ui/findbar.h
--- a/ui/findbar.h
+++ b/ui/findbar.h
@@ -46,6 +46,7 @@
private Q_SLOTS:
void caseSensitivityChanged();
+ void findWholeWordsChanged();
void fromCurrentPageChanged();
void findAsYouTypeChanged();
void closeAndStopSearch();
@@ -55,6 +56,7 @@
QAction * m_caseSensitiveAct;
QAction * m_fromCurrentPageAct;
QAction * m_findAsYouTypeAct;
+ QAction * m_findWholeWords;
bool eventFilter( QObject *target, QEvent *event ) override;
bool m_active;
};
diff --git a/ui/findbar.cpp b/ui/findbar.cpp
--- a/ui/findbar.cpp
+++ b/ui/findbar.cpp
@@ -71,6 +71,9 @@
m_fromCurrentPageAct->setCheckable( true );
m_findAsYouTypeAct = optionsMenu->addAction( i18n( "Find as you type" ) );
m_findAsYouTypeAct->setCheckable( true );
+ m_findWholeWords = optionsMenu->addAction( i18n( "Find whole words only" ) );
+ m_findWholeWords->setCheckable( true );
+
optionsBtn->setMenu( optionsMenu );
lay->addWidget( optionsBtn );
@@ -80,10 +83,12 @@
connect( m_caseSensitiveAct, &QAction::toggled, this, &FindBar::caseSensitivityChanged );
connect( m_fromCurrentPageAct, &QAction::toggled, this, &FindBar::fromCurrentPageChanged );
connect( m_findAsYouTypeAct, &QAction::toggled, this, &FindBar::findAsYouTypeChanged );
+ connect( m_findWholeWords, &QAction::toggled, this, &FindBar::findWholeWordsChanged );
m_caseSensitiveAct->setChecked( Okular::Settings::searchCaseSensitive() );
m_fromCurrentPageAct->setChecked( Okular::Settings::searchFromCurrentPage() );
m_findAsYouTypeAct->setChecked( Okular::Settings::findAsYouType() );
+ m_findWholeWords->setChecked( Okular::Settings::findWholeWords() );
hide();
@@ -169,6 +174,16 @@
m_search->lineEdit()->restartSearch();
}
+void FindBar::findWholeWordsChanged()
+{
+ m_search->lineEdit()->setWholeWords( m_findWholeWords->isChecked() );
+ if( !m_active )
+ return;
+ Okular::Settings::setFindWholeWords( m_findWholeWords->isChecked() );
+ Okular::Settings::self()->save();
+ m_search->lineEdit()->restartSearch();
+}
+
void FindBar::fromCurrentPageChanged()
{
m_search->lineEdit()->setSearchFromStart( !m_fromCurrentPageAct->isChecked() );
diff --git a/ui/searchlineedit.h b/ui/searchlineedit.h
--- a/ui/searchlineedit.h
+++ b/ui/searchlineedit.h
@@ -30,6 +30,7 @@
void clearText();
void setSearchCaseSensitivity( Qt::CaseSensitivity cs );
+ void setWholeWords( bool wholeWords );
void setSearchMinimumLength( int length );
void setSearchType( Okular::Document::SearchType type );
void setSearchId( int id );
@@ -62,6 +63,7 @@
int m_id;
QColor m_color;
bool m_moveViewport;
+ bool m_wholeWords;
bool m_changed;
bool m_fromStart;
bool m_findAsYouType;
diff --git a/ui/searchlineedit.cpp b/ui/searchlineedit.cpp
--- a/ui/searchlineedit.cpp
+++ b/ui/searchlineedit.cpp
@@ -54,6 +54,13 @@
m_changed = true;
}
+
+void SearchLineEdit::setWholeWords( bool wholeWords )
+{
+ m_wholeWords = wholeWords;
+ m_changed = true;
+}
+
void SearchLineEdit::setSearchMinimumLength( int length )
{
m_minLength = length;
@@ -242,7 +249,7 @@
emit searchStarted();
m_searchRunning = true;
m_document->searchText( m_id, thistext, m_fromStart, m_caseSensitivity,
- m_searchType, m_moveViewport, m_color );
+ m_searchType, m_moveViewport, m_color, m_wholeWords );
}
else
m_document->resetSearch( m_id );