Let the user type the hyphen if he wants when searching

It happens that sometimes the hypen is actually "part of the word" like
in one-third, so if there's one- at the end of a line
and third at the beginning of the next, we should still match and not
force the user to type onethird, even we will also match onethird since
there's no way to know if "hyphen at end of line" is supposed to be part
of the word or not

BUGS: 418520
remotes/origin/work/aacid/use_mimes_open_dialog
Albert Astals Cid 6 years ago
parent 054f8930ab
commit 9694113a96
  1. 16
      autotests/searchtest.cpp
  2. 243
      core/textpage.cpp

@ -288,6 +288,22 @@ void SearchTest::testHyphenAtEndOfLineWithoutYOverlap()
QCOMPARE(*result, expected); QCOMPARE(*result, expected);
delete result; delete result;
result = tp->findText(0, QStringLiteral("supercalifragilisticexpialidocious"),
Okular::FromBottom, Qt::CaseSensitive, nullptr);
QVERIFY(result);
QCOMPARE(*result, expected);
delete result;
// If the user is looking for the text explicitely with the hyphen also find it
result = tp->findText(0, QStringLiteral("super-cali-fragilistic"), Okular::FromTop, Qt::CaseSensitive, nullptr);
QVERIFY(result);
delete result;
// If the user is looking for the text explicitely with the hyphen also find it
result = tp->findText(0, QStringLiteral("super-cali-fragilistic"), Okular::FromBottom, Qt::CaseSensitive, nullptr);
QVERIFY(result);
delete result;
delete page; delete page;
} }

@ -54,11 +54,17 @@ class SearchPoint
static bool CaseInsensitiveCmpFn( const QStringRef & from, const QStringRef & to ) static bool CaseInsensitiveCmpFn( const QStringRef & from, const QStringRef & to )
{ {
#ifdef DEBUG_TEXTPAGE
qDebug(OkularCoreDebug) << from << ":" << to << "(case insensitive)";
#endif
return from.compare( to, Qt::CaseInsensitive ) == 0; return from.compare( to, Qt::CaseInsensitive ) == 0;
} }
static bool CaseSensitiveCmpFn( const QStringRef & from, const QStringRef & to ) static bool CaseSensitiveCmpFn( const QStringRef & from, const QStringRef & to )
{ {
#ifdef DEBUG_TEXTPAGE
qDebug(OkularCoreDebug) << from << ":" << to << "(case sensitive)";
#endif
return from.compare( to, Qt::CaseSensitive ) == 0; return from.compare( to, Qt::CaseSensitive ) == 0;
} }
@ -780,7 +786,7 @@ RegularAreaRect* TextPage::findText( int searchID, const QString &query, SearchD
// if the '-' is the last entry // if the '-' is the last entry
static int stringLengthAdaptedWithHyphen(const QString &str, const TextList::ConstIterator &it, const TextList::ConstIterator &textListEnd) static int stringLengthAdaptedWithHyphen(const QString &str, const TextList::ConstIterator &it, const TextList::ConstIterator &textListEnd)
{ {
int len = str.length(); const int len = str.length();
// hyphenated '-' must be at the end of a word, so hyphenation means // hyphenated '-' must be at the end of a word, so hyphenation means
// we have a '-' just followed by a '\n' character // we have a '-' just followed by a '\n' character
@ -795,26 +801,24 @@ static int stringLengthAdaptedWithHyphen(const QString &str, const TextList::Con
const QString &lookahedStr = (*(it+1))->text(); const QString &lookahedStr = (*(it+1))->text();
if (lookahedStr.startsWith(QLatin1Char('\n'))) if (lookahedStr.startsWith(QLatin1Char('\n')))
{ {
len -= 1; return len - 1;
} }
else
{
// 2. if the next word is in a different line or not
const NormalizedRect& hyphenArea = (*it)->area;
const NormalizedRect& lookaheadArea = (*(it + 1))->area;
// lookahead to check whether both the '-' rect and next character rect overlap // 2. if the next word is in a different line or not
if( !doesConsumeY( hyphenArea, lookaheadArea, 70 ) ) const NormalizedRect& hyphenArea = (*it)->area;
{ const NormalizedRect& lookaheadArea = (*(it + 1))->area;
len -= 1;
} // lookahead to check whether both the '-' rect and next character rect overlap
if( !doesConsumeY( hyphenArea, lookaheadArea, 70 ) )
{
return len - 1;
} }
} }
} }
// else if it is the second last entry - for example in pdf format // else if it is the second last entry - for example in pdf format
else if (str.endsWith(QLatin1String("-\n"))) else if (str.endsWith(QLatin1String("-\n")))
{ {
len -= 2; return len - 2;
} }
return len; return len;
@ -850,8 +854,7 @@ RegularAreaRect* TextPagePrivate::findTextInternalForward( int searchID, const Q
const QString query = _query.normalized(QString::NormalizationForm_KC); const QString query = _query.normalized(QString::NormalizationForm_KC);
// j is the current position in our query // j is the current position in our query
// len is the length of the string in TextEntity // queryLeft is the length of the query we have left to match
// queryLeft is the length of the query we have left
int j=0, queryLeft=query.length(); int j=0, queryLeft=query.length();
TextList::ConstIterator it = start; TextList::ConstIterator it = start;
@ -864,9 +867,11 @@ RegularAreaRect* TextPagePrivate::findTextInternalForward( int searchID, const Q
{ {
const TinyTextEntity* curEntity = *it; const TinyTextEntity* curEntity = *it;
const QString& str = curEntity->text(); const QString& str = curEntity->text();
int len = stringLengthAdaptedWithHyphen(str, it, m_words.constEnd()); const int strLen = str.length();
const int adjustedLen = stringLengthAdaptedWithHyphen(str, it, m_words.constEnd());
// adjustedLen <= strLen
if (offset >= len) if (offset >= strLen)
{ {
it++; it++;
offset = 0; offset = 0;
@ -879,62 +884,67 @@ RegularAreaRect* TextPagePrivate::findTextInternalForward( int searchID, const Q
offset_begin = offset; offset_begin = offset;
} }
int min=qMin(queryLeft,len-offset); // Let the user write the hyphen or not when searching for text
int matchedLen = -1;
for (int matchingLen = strLen; matchingLen >= adjustedLen; matchingLen--)
{ {
#ifdef DEBUG_TEXTPAGE // we have equal (or less than) area of the query left as the length of the current
qCDebug(OkularCoreDebug) << str.midRef(offset, min) << ":" << _query.midRef(j, min);
#endif
// we have equal (or less than) area of the query left as the length of the current
// entity // entity
const int min = qMin(queryLeft, matchingLen - offset);
if ( !comparer( str.midRef( offset, min ), query.midRef( j, min ) ) ) if ( comparer( str.midRef( offset, min ), query.midRef( j, min ) ) )
{ {
// we have not matched matchedLen = min;
// this means we do not have a complete match break;
// we need to get back to query start }
// and continue the search from this place }
if ( matchedLen == -1 )
{
// we have not matched
// this means we do not have a complete match
// we need to get back to query start
// and continue the search from this place
#ifdef DEBUG_TEXTPAGE #ifdef DEBUG_TEXTPAGE
qCDebug(OkularCoreDebug) << "\tnot matched"; qCDebug(OkularCoreDebug) << "\tnot matched";
#endif #endif
j = 0; j = 0;
queryLeft=query.length(); queryLeft=query.length();
it = it_begin; it = it_begin;
offset = offset_begin+1; offset = offset_begin+1;
it_begin = TextList::ConstIterator(); it_begin = TextList::ConstIterator();
} }
else else
{ {
// we have a match // we have a match
// move the current position in the query // move the current position in the query
// to the position after the length of this string // to the position after the length of this string
// we matched // we matched
// subtract the length of the current entity from // subtract the length of the current entity from
// the left length of the query // the left length of the query
#ifdef DEBUG_TEXTPAGE #ifdef DEBUG_TEXTPAGE
qCDebug(OkularCoreDebug) << "\tmatched"; qCDebug(OkularCoreDebug) << "\tmatched" << matchedLen;
#endif #endif
j += min; j += matchedLen;
queryLeft -= min; queryLeft -= matchedLen;
if (queryLeft==0) if (queryLeft==0)
{ {
// save or update the search point for the current searchID // save or update the search point for the current searchID
QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID ); QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID );
if ( sIt == m_searchPoints.end() ) if ( sIt == m_searchPoints.end() )
{ {
sIt = m_searchPoints.insert( searchID, new SearchPoint ); sIt = m_searchPoints.insert( searchID, new SearchPoint );
} }
SearchPoint* sp = *sIt; SearchPoint* sp = *sIt;
sp->it_begin = it_begin; sp->it_begin = it_begin;
sp->it_end = it; sp->it_end = it;
sp->offset_begin = offset_begin; sp->offset_begin = offset_begin;
sp->offset_end = offset + min; sp->offset_end = offset + matchedLen;
return searchPointToArea(sp); return searchPointToArea(sp);
}
it++;
offset = 0;
} }
it++;
offset = 0;
} }
} }
// end of loop - it means that we've ended the textentities // end of loop - it means that we've ended the textentities
@ -982,11 +992,13 @@ RegularAreaRect* TextPagePrivate::findTextInternalBackward( int searchID, const
const TinyTextEntity* curEntity = *it; const TinyTextEntity* curEntity = *it;
const QString& str = curEntity->text(); const QString& str = curEntity->text();
int len = stringLengthAdaptedWithHyphen(str, it, m_words.constEnd()); const int strLen = str.length();
const int adjustedLen = stringLengthAdaptedWithHyphen(str, it, m_words.constEnd());
// adjustedLen <= strLen
if (offset <= 0) if (offset <= 0)
{ {
offset = len; offset = strLen;
} }
if ( it_begin == TextList::ConstIterator() ) if ( it_begin == TextList::ConstIterator() )
@ -995,66 +1007,69 @@ RegularAreaRect* TextPagePrivate::findTextInternalBackward( int searchID, const
offset_begin = offset; offset_begin = offset;
} }
int min=qMin(queryLeft,offset); // Let the user write the hyphen or not when searching for text
int matchedLen = -1;
// we have equal (or less than) area of the query left as the length of the current
// entity
for (int matchingLen = strLen; matchingLen >= adjustedLen; matchingLen--)
{ {
#ifdef DEBUG_TEXTPAGE const int hyphenOffset = (strLen - matchingLen);
qCDebug(OkularCoreDebug) << str.midRef(offset-min, min) << " : " << _query.midRef(j-min, min); const int min = qMin(queryLeft + hyphenOffset, offset);
#endif if ( comparer( str.midRef( offset - min, min - hyphenOffset ), query.midRef( j - min + hyphenOffset, min - hyphenOffset ) ) )
// we have equal (or less than) area of the query left as the length of the current
// entity
// Note len is not str.length() so we can't use rightRef here
if ( !comparer( str.midRef(offset-min, min ), query.midRef( j - min, min ) ) )
{ {
// we have not matched matchedLen = min - hyphenOffset;
// this means we do not have a complete match break;
// we need to get back to query start }
// and continue the search from this place }
if ( matchedLen == -1 )
{
// we have not matched
// this means we do not have a complete match
// we need to get back to query start
// and continue the search from this place
#ifdef DEBUG_TEXTPAGE #ifdef DEBUG_TEXTPAGE
qCDebug(OkularCoreDebug) << "\tnot matched"; qCDebug(OkularCoreDebug) << "\tnot matched";
#endif #endif
j = query.length(); j = query.length();
queryLeft = query.length(); queryLeft = query.length();
it = it_begin; it = it_begin;
offset = offset_begin-1; offset = offset_begin-1;
it_begin = TextList::ConstIterator(); it_begin = TextList::ConstIterator();
} }
else else
{ {
// we have a match // we have a match
// move the current position in the query // move the current position in the query
// to the position after the length of this string // to the position after the length of this string
// we matched // we matched
// subtract the length of the current entity from // subtract the length of the current entity from
// the left length of the query // the left length of the query
#ifdef DEBUG_TEXTPAGE #ifdef DEBUG_TEXTPAGE
qCDebug(OkularCoreDebug) << "\tmatched"; qCDebug(OkularCoreDebug) << "\tmatched";
#endif #endif
j -= min; j -= matchedLen;
queryLeft -= min; queryLeft -= matchedLen;
if ( queryLeft == 0 ) if ( queryLeft == 0 )
{ {
// save or update the search point for the current searchID // save or update the search point for the current searchID
QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID ); QMap< int, SearchPoint* >::iterator sIt = m_searchPoints.find( searchID );
if ( sIt == m_searchPoints.end() ) if ( sIt == m_searchPoints.end() )
{ {
sIt = m_searchPoints.insert( searchID, new SearchPoint ); sIt = m_searchPoints.insert( searchID, new SearchPoint );
} }
SearchPoint* sp = *sIt; SearchPoint* sp = *sIt;
sp->it_begin = it; sp->it_begin = it;
sp->it_end = it_begin; sp->it_end = it_begin;
sp->offset_begin = offset - min; sp->offset_begin = offset - matchedLen;
sp->offset_end = offset_begin; sp->offset_end = offset_begin;
return searchPointToArea(sp); return searchPointToArea(sp);
}
offset = 0;
} }
offset = 0;
} }
} }
// end of loop - it means that we've ended the textentities // end of loop - it means that we've ended the textentities

Loading…
Cancel
Save