-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 Hello,
Am 11.01.2015 um 20:36 schrieb Adam Reichold: > Hello, > > Am 11.01.2015 um 20:19 schrieb Albert Astals Cid: >> El Diumenge, 11 de gener de 2015, a les 11:14:12, Adam Reichold >> va escriure: >>> Hello again, >>> >>> Am 11.01.2015 um 00:57 schrieb Albert Astals Cid: >>>> El Diumenge, 11 de gener de 2015, a les 00:37:36, Adam >>>> Reichold va >>>> >>>> escriure: >>>>> Hello, >>>>> >>>>> Am 10.01.2015 um 23:45 schrieb Albert Astals Cid: >>>>>> Maybe you can add some tests to check_search.cpp? >>>>> >>>>> Attached patch with a test case for the four flag >>>>> combinations added to the Qt4 and Qt5 versions of >>>>> "check_search.cpp". >>>>> >>>>> Of course, this very much highlights the ugliness of shoe >>>>> horning the flags into the existing enumeration. But I >>>>> don't think that making "Poppler::Page::search" take an >>>>> "int" instead of "SearchMode" would be ABI compatible >>>>> strictly speaking, since now the compiler is free to choose >>>>> the underlying type for the enumeration. >>>> >>>> Meh, you're right, this is not good either since you're >>>> passing in SearchMode something that is not a SearchMode >>>> (it's the sum of two). >>>> >>>> So yeah it'd be better to go the QFlags way. Maybe you can >>>> leave the old function there, mark it as deprecated and say >>>> that it only obeys the sensitiviness part and add a new >>>> function that accepts the qflags? >>> >>> Ok, attached is the patch which adds a new flags type >>> SearchFlags and corresponding overloads to the Qt4 frontend. I >>> try to factor out as much common code as possible and add a >>> test case as well. I'll add the Qt5 frontend as soon we think >>> the approach is sound. >>> >>> I chose to use a new enumeration SearchFlag instead of >>> SearchMode since the symmetry of SearchMode does not really >>> make sense if there are several non-exclusive flags. > >> Yep, now thinking out loud, would it make sense to merge >> SearchDirection in there too? The three enums are also exclusive >> one another. > > I don't think this would work, since the range of > "SearchDirection" has more than two elements and hence would need > at least two flags but then those would not be exclusive. E.g. I'd > add two flags "NextResult" and "PreviousResult" with "FromTop" as > the default, but then the user could specify "NextResult | > PreviousResult" which does not make sense? > > Best regards, Adam. Attached is the extended the patch also containing the Qt5 part (as I'll be running out of weekend soon). Btw., another reason not to fold SearchDirection into SearchFlags would be that it does not apply to the overload returning a list of results at all. Best regards, Adam. >> But on the other hand it may feel a bit shoehorned. > >> What do you think? > >> Cheer,s Albert > >>> >>> Best regards, Adam. >>> >>>> Cheers, Albert >>>> >>>>> Best regards, Adam. >>>>> >>>>>> Cheers, Albert >>>>>> >>>>>> El Dissabte, 10 de gener de 2015, a les 23:26:01, Adam >>>>>> Reichold va >>>>>> >>>>>> escriure: >>>>>>> Hello again, >>>>>>> >>>>>>> Am 10.01.2015 um 22:25 schrieb Albert Astals Cid: >>>>>>>> El Dissabte, 10 de gener de 2015, a les 17:51:48, >>>>>>>> Adam Reichold va >>>>>>>> >>>>>>>> escriure: >>>>>>>>> Hello, >>>>>>>>> >>>>>>>>> Attach is a patch that would expose Poppler's >>>>>>>>> whole-words search option within the Qt frontends. >>>>>>>>> >>>>>>>>> While the implementation seems straight forward so >>>>>>>>> far, I would like to request comments whether >>>>>>>>> extending the "SearchMode" enumeration to flag >>>>>>>>> definition is considered harmless. The proper way >>>>>>>>> to do it seems to be the introduction of >>>>>>>>> "QFlags<SearchMode>" which would however break >>>>>>>>> compatibility and hence imply the need to have an >>>>>>>>> additional overloads using a separate flag (and >>>>>>>>> enumeration?) definition. >>>>>>>> >>>>>>>> Looks good to me. The qt5/ side would need the >>>>>>>> documentation update too, no? >>>>>>> >>>>>>> patch with fixed Qt5 documentation and "\since" >>>>>>> commands attached. >>>>>>> >>>>>>> Best regards, Adam. >>>>>>> >>>>>>>> Cheers, Albert >>>>>>>> >>>>>>>>> Best regards, Adam. >>>>>>>> >>>>>>>> _______________________________________________ >>>>>>>> poppler mailing list [email protected] >>>>>>>> http://lists.freedesktop.org/mailman/listinfo/poppler >>>>>> >>>>>> >>>>>>>> _______________________________________________ poppler >>>>>> mailing list [email protected] >>>>>> http://lists.freedesktop.org/mailman/listinfo/poppler >>>> >>>> _______________________________________________ poppler >>>> mailing list [email protected] >>>> http://lists.freedesktop.org/mailman/listinfo/poppler > >> _______________________________________________ poppler mailing >> list [email protected] >> http://lists.freedesktop.org/mailman/listinfo/poppler > > _______________________________________________ poppler mailing > list [email protected] > http://lists.freedesktop.org/mailman/listinfo/poppler > -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAEBCAAGBQJUsuCNAAoJEPSSjE3STU34NqYH/041a3cdGf98mYU0AdQfYfof thjU+Ah2dBBRuzgfwpJz4fE8M5njkWqf775ZjIf1LeicAnErzbNgIBwFobxYiDiU L2FL7ZkKjRRBSl8CY/oG3oPTGbRqrZn0nx5I8q+CtguXZhzrblhn0IWTmtTduI9a nQ9GHmHN7x4ZzTjC4nVY8VjS4oE88zimtftvFuF/3B5w/BkPdA+eO7rStfk6y0hP FsXgWRxr+ADQxtQ9EtaCeHRB3qpAZniW0sRiAR7Glp9XiV0CPoUMctEbrB+DeE0v lr14qTa4TzpB5bRz1WLLmPhPtwPdbYyI+oL9fOgQTwMXe6WjX7ukSrDqA5WT/TE= =9pbU -----END PGP SIGNATURE-----
>From f06b9a42a536b2699ddf8100b0fa4af41e91a98f Mon Sep 17 00:00:00 2001 From: Adam Reichold <[email protected]> Date: Sun, 11 Jan 2015 11:08:37 +0100 Subject: [PATCH 1/2] Expose whole-words find option in Qt4 frontend Adds a SearchFlags flag type and corresponding overloads to the Qt4 frontend so that callers can indicate whole-words matching in addition to case sensitivity. --- qt4/src/poppler-page-private.h | 4 +- qt4/src/poppler-page.cc | 112 ++++++++++++++++++++++++++++------------- qt4/src/poppler-qt4.h | 42 +++++++++++++++- qt4/tests/check_search.cpp | 31 ++++++++++++ 4 files changed, 151 insertions(+), 38 deletions(-) diff --git a/qt4/src/poppler-page-private.h b/qt4/src/poppler-page-private.h index 91955e0..ef467e5 100644 --- a/qt4/src/poppler-page-private.h +++ b/qt4/src/poppler-page-private.h @@ -46,7 +46,9 @@ public: static Link* convertLinkActionToLink(::LinkAction * a, DocumentData *parentDoc, const QRectF &linkArea); - TextPage *prepareTextSearch(const QString &text, Page::SearchMode caseSensitive, Page::Rotation rotate, GBool *sCase, QVector<Unicode> *u); + TextPage *prepareTextSearch(const QString &text, Page::Rotation rotate, QVector<Unicode> *u); + GBool performSingleTextSearch(TextPage* textPage, QVector<Unicode> &u, double &sLeft, double &sTop, double &sRight, double &sBottom, Page::SearchDirection direction, GBool sCase, GBool sWords); + QList<QRectF> performMultipleTextSearch(TextPage* textPage, QVector<Unicode> &u, GBool sCase, GBool sWords); }; } diff --git a/qt4/src/poppler-page.cc b/qt4/src/poppler-page.cc index fc928b9..4a0e689 100644 --- a/qt4/src/poppler-page.cc +++ b/qt4/src/poppler-page.cc @@ -215,16 +215,13 @@ Link* PageData::convertLinkActionToLink(::LinkAction * a, DocumentData *parentDo return popplerLink; } -TextPage *PageData::prepareTextSearch(const QString &text, Page::SearchMode caseSensitive, Page::Rotation rotate, GBool *sCase, QVector<Unicode> *u) +inline TextPage *PageData::prepareTextSearch(const QString &text, Page::Rotation rotate, QVector<Unicode> *u) { const QChar * str = text.unicode(); const int len = text.length(); u->resize(len); for (int i = 0; i < len; ++i) (*u)[i] = str[i].unicode(); - if (caseSensitive == Page::CaseSensitive) *sCase = gTrue; - else *sCase = gFalse; - const int rotation = (int)rotate * 90; // fetch ourselves a textpage @@ -234,7 +231,43 @@ TextPage *PageData::prepareTextSearch(const QString &text, Page::SearchMode case TextPage *textPage=td.takeText(); return textPage; -} +} + +inline GBool PageData::performSingleTextSearch(TextPage* textPage, QVector<Unicode> &u, double &sLeft, double &sTop, double &sRight, double &sBottom, Page::SearchDirection direction, GBool sCase, GBool sWords) +{ + if (direction == Page::FromTop) + return textPage->findText( u.data(), u.size(), + gTrue, gTrue, gFalse, gFalse, sCase, gFalse, sWords, &sLeft, &sTop, &sRight, &sBottom ); + else if ( direction == Page::NextResult ) + return textPage->findText( u.data(), u.size(), + gFalse, gTrue, gTrue, gFalse, sCase, gFalse, sWords, &sLeft, &sTop, &sRight, &sBottom ); + else if ( direction == Page::PreviousResult ) + return textPage->findText( u.data(), u.size(), + gFalse, gTrue, gTrue, gFalse, sCase, gTrue, sWords, &sLeft, &sTop, &sRight, &sBottom ); + + return gFalse; +} + +inline QList<QRectF> PageData::performMultipleTextSearch(TextPage* textPage, QVector<Unicode> &u, GBool sCase, GBool sWords) +{ + QList<QRectF> results; + double sLeft = 0.0, sTop = 0.0, sRight = 0.0, sBottom = 0.0; + + while(textPage->findText( u.data(), u.size(), + gFalse, gTrue, gTrue, gFalse, sCase, gFalse, sWords, &sLeft, &sTop, &sRight, &sBottom )) + { + QRectF result; + + result.setLeft(sLeft); + result.setTop(sTop); + result.setRight(sRight); + result.setBottom(sBottom); + + results.append(result); + } + + return results; +} Page::Page(DocumentData *doc, int index) { m_page = new PageData(); @@ -459,20 +492,27 @@ QString Page::text(const QRectF &r) const bool Page::search(const QString &text, double &sLeft, double &sTop, double &sRight, double &sBottom, SearchDirection direction, SearchMode caseSensitive, Rotation rotate) const { - GBool sCase; + const GBool sCase = caseSensitive == Page::CaseSensitive ? gTrue : gFalse; + QVector<Unicode> u; - TextPage *textPage = m_page->prepareTextSearch(text, caseSensitive, rotate, &sCase, &u); - - bool found = false; - if (direction == FromTop) - found = textPage->findText( u.data(), u.size(), - gTrue, gTrue, gFalse, gFalse, sCase, gFalse, gFalse, &sLeft, &sTop, &sRight, &sBottom ); - else if ( direction == NextResult ) - found = textPage->findText( u.data(), u.size(), - gFalse, gTrue, gTrue, gFalse, sCase, gFalse, gFalse, &sLeft, &sTop, &sRight, &sBottom ); - else if ( direction == PreviousResult ) - found = textPage->findText( u.data(), u.size(), - gFalse, gTrue, gTrue, gFalse, sCase, gTrue, gFalse, &sLeft, &sTop, &sRight, &sBottom ); + TextPage *textPage = m_page->prepareTextSearch(text, rotate, &u); + + const bool found = m_page->performSingleTextSearch(textPage, u, sLeft, sTop, sRight, sBottom, direction, sCase, gFalse); + + textPage->decRefCnt(); + + return found; +} + +bool Page::search(const QString &text, double &sLeft, double &sTop, double &sRight, double &sBottom, SearchDirection direction, SearchFlags flags, Rotation rotate) const +{ + const GBool sCase = flags.testFlag(IgnoreCase) ? gFalse : gTrue; + const GBool sWords = flags.testFlag(WholeWorlds) ? gTrue : gFalse; + + QVector<Unicode> u; + TextPage *textPage = m_page->prepareTextSearch(text, rotate, &u); + + const bool found = m_page->performSingleTextSearch(textPage, u, sLeft, sTop, sRight, sBottom, direction, sCase, sWords); textPage->decRefCnt(); @@ -499,31 +539,33 @@ bool Page::search(const QString &text, QRectF &rect, SearchDirection direction, QList<QRectF> Page::search(const QString &text, SearchMode caseSensitive, Rotation rotate) const { - GBool sCase; + const GBool sCase = caseSensitive == Page::CaseSensitive ? gTrue : gFalse; + QVector<Unicode> u; - TextPage *textPage = m_page->prepareTextSearch(text, caseSensitive, rotate, &sCase, &u); + TextPage *textPage = m_page->prepareTextSearch(text, rotate, &u); - QList<QRectF> results; - double sLeft = 0.0, sTop = 0.0, sRight = 0.0, sBottom = 0.0; - - while(textPage->findText( u.data(), u.size(), - gFalse, gTrue, gTrue, gFalse, sCase, gFalse, gFalse, &sLeft, &sTop, &sRight, &sBottom )) - { - QRectF result; - - result.setLeft(sLeft); - result.setTop(sTop); - result.setRight(sRight); - result.setBottom(sBottom); - - results.append(result); - } + const QList<QRectF> results = m_page->performMultipleTextSearch(textPage, u, sCase, gFalse); textPage->decRefCnt(); return results; } +QList<QRectF> Page::search(const QString &text, SearchFlags flags, Rotation rotate) const +{ + const GBool sCase = flags.testFlag(IgnoreCase) ? gFalse : gTrue; + const GBool sWords = flags.testFlag(WholeWorlds) ? gTrue : gFalse; + + QVector<Unicode> u; + TextPage *textPage = m_page->prepareTextSearch(text, rotate, &u); + + const QList<QRectF> results = m_page->performMultipleTextSearch(textPage, u, sCase, sWords); + + textPage->decRefCnt(); + + return results; +} + QList<TextBox*> Page::textList(Rotation rotate) const { TextOutputDev *output_dev; diff --git a/qt4/src/poppler-qt4.h b/qt4/src/poppler-qt4.h index ee7558e..193b043 100644 --- a/qt4/src/poppler-qt4.h +++ b/qt4/src/poppler-qt4.h @@ -579,6 +579,16 @@ delete it; enum SearchMode { CaseSensitive, ///< Case differences cause no match in searching CaseInsensitive ///< Case differences are ignored in matching }; + + /** + Flags to modify the search behaviour \since 0.31 + */ + enum SearchFlag + { + IgnoreCase = 0x00000001, ///< Case differences are ignored + WholeWorlds = 0x00000002 ///< Only whole words are matched + }; + Q_DECLARE_FLAGS( SearchFlags, SearchFlag ) /** Returns true if the specified text was found. @@ -603,7 +613,21 @@ delete it; \param rotate the rotation to apply for the search order \since 0.14 **/ - bool search(const QString &text, double &rectLeft, double &rectTop, double &rectRight, double &rectBottom, SearchDirection direction, SearchMode caseSensitive, Rotation rotate = Rotate0) const; + Q_DECL_DEPRECATED bool search(const QString &text, double &rectLeft, double &rectTop, double &rectRight, double &rectBottom, SearchDirection direction, SearchMode caseSensitive, Rotation rotate = Rotate0) const; + + /** + Returns true if the specified text was found. + + \param text the text the search + \param rectXXX in all directions is used to return where the text was found, for NextResult and PreviousResult + indicates where to continue searching for + \param direction in which direction do the search + \param flags the flags to consider during matching + \param rotate the rotation to apply for the search order + + \since 0.31 + **/ + bool search(const QString &text, double &rectLeft, double &rectTop, double &rectRight, double &rectBottom, SearchDirection direction, SearchFlags flags = 0, Rotation rotate = Rotate0) const; /** Returns a list of all occurrences of the specified text on the page. @@ -616,7 +640,20 @@ delete it; \since 0.22 **/ - QList<QRectF> search(const QString &text, SearchMode caseSensitive, Rotation rotate = Rotate0) const; + Q_DECL_DEPRECATED QList<QRectF> search(const QString &text, SearchMode caseSensitive, Rotation rotate = Rotate0) const; + + /** + Returns a list of all occurrences of the specified text on the page. + + \param text the text to search + \param flags the flags to consider during matching + \param rotate the rotation to apply for the search order + + \warning Do not use the returned QRectF as arguments of another search call because of truncation issues if qreal is defined as float. + + \since 0.31 + **/ + QList<QRectF> search(const QString &text, SearchFlags flags = 0, Rotation rotate = Rotate0) const; /** Returns a list of text of the page @@ -1826,6 +1863,7 @@ height = dummy.height(); } Q_DECLARE_OPERATORS_FOR_FLAGS(Poppler::Page::PainterFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(Poppler::Page::SearchFlags) Q_DECLARE_OPERATORS_FOR_FLAGS(Poppler::Document::RenderHints) Q_DECLARE_OPERATORS_FOR_FLAGS(Poppler::PDFConverter::PDFOptions) Q_DECLARE_OPERATORS_FOR_FLAGS(Poppler::PSConverter::PSOptions) diff --git a/qt4/tests/check_search.cpp b/qt4/tests/check_search.cpp index cabf82d..98a1cec 100644 --- a/qt4/tests/check_search.cpp +++ b/qt4/tests/check_search.cpp @@ -8,6 +8,7 @@ class TestSearch: public QObject private slots: void bug7063(); void testNextAndPrevious(); + void testWholeWordsOnly(); }; void TestSearch::bug7063() @@ -86,6 +87,36 @@ void TestSearch::testNextAndPrevious() delete doc; } +void TestSearch::testWholeWordsOnly() +{ + QScopedPointer< Poppler::Document > document(Poppler::Document::load(TESTDATADIR "/unittestcases/WithActualText.pdf")); + QVERIFY( document ); + + QScopedPointer< Poppler::Page > page(document->page(0)); + QVERIFY( page ); + + const Poppler::Page::SearchDirection direction = Poppler::Page::FromTop; + + const Poppler::Page::SearchFlags mode0 = 0; + const Poppler::Page::SearchFlags mode1 = Poppler::Page::IgnoreCase; + const Poppler::Page::SearchFlags mode2 = Poppler::Page::WholeWorlds; + const Poppler::Page::SearchFlags mode3 = Poppler::Page::IgnoreCase | Poppler::Page::WholeWorlds; + + double left, top, right, bottom; + + QCOMPARE( page->search(QLatin1String("brown"), left, top, right, bottom, direction, mode0), true ); + QCOMPARE( page->search(QLatin1String("brOwn"), left, top, right, bottom, direction, mode0), false ); + + QCOMPARE( page->search(QLatin1String("brOwn"), left, top, right, bottom, direction, mode1), true ); + QCOMPARE( page->search(QLatin1String("brawn"), left, top, right, bottom, direction, mode1), false ); + + QCOMPARE( page->search(QLatin1String("brown"), left, top, right, bottom, direction, mode2), true ); + QCOMPARE( page->search(QLatin1String("own"), left, top, right, bottom, direction, mode2), false ); + + QCOMPARE( page->search(QLatin1String("brOwn"), left, top, right, bottom, direction, mode3), true ); + QCOMPARE( page->search(QLatin1String("Own"), left, top, right, bottom, direction, mode3), false ); +} + QTEST_MAIN(TestSearch) #include "check_search.moc" -- 2.2.1 >From c0ec4eeea97e6d9b74eb6e281b3fa03cc1be6c65 Mon Sep 17 00:00:00 2001 From: Adam Reichold <[email protected]> Date: Sun, 11 Jan 2015 21:37:19 +0100 Subject: [PATCH 2/2] Expose whole-words find option in Qt5 frontend Adds a SearchFlags flag type and corresponding overloads to the Qt5 frontend so that callers can indicate whole-words matching in addition to case sensitivity. --- qt5/src/poppler-page-private.h | 4 +- qt5/src/poppler-page.cc | 114 ++++++++++++++++++++++++++++------------- qt5/src/poppler-qt5.h | 44 ++++++++++++++-- qt5/tests/check_search.cpp | 31 +++++++++++ 4 files changed, 153 insertions(+), 40 deletions(-) diff --git a/qt5/src/poppler-page-private.h b/qt5/src/poppler-page-private.h index 91955e0..ef467e5 100644 --- a/qt5/src/poppler-page-private.h +++ b/qt5/src/poppler-page-private.h @@ -46,7 +46,9 @@ public: static Link* convertLinkActionToLink(::LinkAction * a, DocumentData *parentDoc, const QRectF &linkArea); - TextPage *prepareTextSearch(const QString &text, Page::SearchMode caseSensitive, Page::Rotation rotate, GBool *sCase, QVector<Unicode> *u); + TextPage *prepareTextSearch(const QString &text, Page::Rotation rotate, QVector<Unicode> *u); + GBool performSingleTextSearch(TextPage* textPage, QVector<Unicode> &u, double &sLeft, double &sTop, double &sRight, double &sBottom, Page::SearchDirection direction, GBool sCase, GBool sWords); + QList<QRectF> performMultipleTextSearch(TextPage* textPage, QVector<Unicode> &u, GBool sCase, GBool sWords); }; } diff --git a/qt5/src/poppler-page.cc b/qt5/src/poppler-page.cc index 6eea0d0..b3a453c 100644 --- a/qt5/src/poppler-page.cc +++ b/qt5/src/poppler-page.cc @@ -215,16 +215,13 @@ Link* PageData::convertLinkActionToLink(::LinkAction * a, DocumentData *parentDo return popplerLink; } -TextPage *PageData::prepareTextSearch(const QString &text, Page::SearchMode caseSensitive, Page::Rotation rotate, GBool *sCase, QVector<Unicode> *u) +inline TextPage *PageData::prepareTextSearch(const QString &text, Page::Rotation rotate, QVector<Unicode> *u) { const QChar * str = text.unicode(); const int len = text.length(); u->resize(len); for (int i = 0; i < len; ++i) (*u)[i] = str[i].unicode(); - if (caseSensitive == Page::CaseSensitive) *sCase = gTrue; - else *sCase = gFalse; - const int rotation = (int)rotate * 90; // fetch ourselves a textpage @@ -232,9 +229,45 @@ TextPage *PageData::prepareTextSearch(const QString &text, Page::SearchMode case parentDoc->doc->displayPage( &td, index + 1, 72, 72, rotation, false, true, false, NULL, NULL, NULL, NULL, gTrue); TextPage *textPage=td.takeText(); - + return textPage; -} +} + +inline GBool PageData::performSingleTextSearch(TextPage* textPage, QVector<Unicode> &u, double &sLeft, double &sTop, double &sRight, double &sBottom, Page::SearchDirection direction, GBool sCase, GBool sWords) +{ + if (direction == Page::FromTop) + return textPage->findText( u.data(), u.size(), + gTrue, gTrue, gFalse, gFalse, sCase, gFalse, sWords, &sLeft, &sTop, &sRight, &sBottom ); + else if ( direction == Page::NextResult ) + return textPage->findText( u.data(), u.size(), + gFalse, gTrue, gTrue, gFalse, sCase, gFalse, sWords, &sLeft, &sTop, &sRight, &sBottom ); + else if ( direction == Page::PreviousResult ) + return textPage->findText( u.data(), u.size(), + gFalse, gTrue, gTrue, gFalse, sCase, gTrue, sWords, &sLeft, &sTop, &sRight, &sBottom ); + + return gFalse; +} + +inline QList<QRectF> PageData::performMultipleTextSearch(TextPage* textPage, QVector<Unicode> &u, GBool sCase, GBool sWords) +{ + QList<QRectF> results; + double sLeft = 0.0, sTop = 0.0, sRight = 0.0, sBottom = 0.0; + + while(textPage->findText( u.data(), u.size(), + gFalse, gTrue, gTrue, gFalse, sCase, gFalse, sWords, &sLeft, &sTop, &sRight, &sBottom )) + { + QRectF result; + + result.setLeft(sLeft); + result.setTop(sTop); + result.setRight(sRight); + result.setBottom(sBottom); + + results.append(result); + } + + return results; +} Page::Page(DocumentData *doc, int index) { m_page = new PageData(); @@ -459,20 +492,27 @@ QString Page::text(const QRectF &r) const bool Page::search(const QString &text, double &sLeft, double &sTop, double &sRight, double &sBottom, SearchDirection direction, SearchMode caseSensitive, Rotation rotate) const { - GBool sCase; + const GBool sCase = caseSensitive == Page::CaseSensitive ? gTrue : gFalse; + QVector<Unicode> u; - TextPage *textPage = m_page->prepareTextSearch(text, caseSensitive, rotate, &sCase, &u); - - bool found = false; - if (direction == FromTop) - found = textPage->findText( u.data(), u.size(), - gTrue, gTrue, gFalse, gFalse, sCase, gFalse, gFalse, &sLeft, &sTop, &sRight, &sBottom ); - else if ( direction == NextResult ) - found = textPage->findText( u.data(), u.size(), - gFalse, gTrue, gTrue, gFalse, sCase, gFalse, gFalse, &sLeft, &sTop, &sRight, &sBottom ); - else if ( direction == PreviousResult ) - found = textPage->findText( u.data(), u.size(), - gFalse, gTrue, gTrue, gFalse, sCase, gTrue, gFalse, &sLeft, &sTop, &sRight, &sBottom ); + TextPage *textPage = m_page->prepareTextSearch(text, rotate, &u); + + const bool found = m_page->performSingleTextSearch(textPage, u, sLeft, sTop, sRight, sBottom, direction, sCase, gFalse); + + textPage->decRefCnt(); + + return found; +} + +bool Page::search(const QString &text, double &sLeft, double &sTop, double &sRight, double &sBottom, SearchDirection direction, SearchFlags flags, Rotation rotate) const +{ + const GBool sCase = flags.testFlag(IgnoreCase) ? gFalse : gTrue; + const GBool sWords = flags.testFlag(WholeWorlds) ? gTrue : gFalse; + + QVector<Unicode> u; + TextPage *textPage = m_page->prepareTextSearch(text, rotate, &u); + + const bool found = m_page->performSingleTextSearch(textPage, u, sLeft, sTop, sRight, sBottom, direction, sCase, sWords); textPage->decRefCnt(); @@ -481,31 +521,33 @@ bool Page::search(const QString &text, double &sLeft, double &sTop, double &sRig QList<QRectF> Page::search(const QString &text, SearchMode caseSensitive, Rotation rotate) const { - GBool sCase; + const GBool sCase = caseSensitive == Page::CaseSensitive ? gTrue : gFalse; + QVector<Unicode> u; - TextPage *textPage = m_page->prepareTextSearch(text, caseSensitive, rotate, &sCase, &u); + TextPage *textPage = m_page->prepareTextSearch(text, rotate, &u); - QList<QRectF> results; - double sLeft = 0.0, sTop = 0.0, sRight = 0.0, sBottom = 0.0; - - while(textPage->findText( u.data(), u.size(), - gFalse, gTrue, gTrue, gFalse, sCase, gFalse, gFalse, &sLeft, &sTop, &sRight, &sBottom )) - { - QRectF result; - - result.setLeft(sLeft); - result.setTop(sTop); - result.setRight(sRight); - result.setBottom(sBottom); - - results.append(result); - } + const QList<QRectF> results = m_page->performMultipleTextSearch(textPage, u, sCase, gFalse); textPage->decRefCnt(); return results; } +QList<QRectF> Page::search(const QString &text, SearchFlags flags, Rotation rotate) const +{ + const GBool sCase = flags.testFlag(IgnoreCase) ? gFalse : gTrue; + const GBool sWords = flags.testFlag(WholeWorlds) ? gTrue : gFalse; + + QVector<Unicode> u; + TextPage *textPage = m_page->prepareTextSearch(text, rotate, &u); + + const QList<QRectF> results = m_page->performMultipleTextSearch(textPage, u, sCase, sWords); + + textPage->decRefCnt(); + + return results; +} + QList<TextBox*> Page::textList(Rotation rotate) const { TextOutputDev *output_dev; diff --git a/qt5/src/poppler-qt5.h b/qt5/src/poppler-qt5.h index dee0b19..f0ba399 100644 --- a/qt5/src/poppler-qt5.h +++ b/qt5/src/poppler-qt5.h @@ -580,6 +580,16 @@ delete it; enum SearchMode { CaseSensitive, ///< Case differences cause no match in searching CaseInsensitive ///< Case differences are ignored in matching }; + + /** + Flags to modify the search behaviour \since 0.31 + */ + enum SearchFlag + { + IgnoreCase = 0x00000001, ///< Case differences are ignored + WholeWorlds = 0x00000002 ///< Only whole words are matched + }; + Q_DECLARE_FLAGS( SearchFlags, SearchFlag ) /** Returns true if the specified text was found. @@ -592,8 +602,22 @@ delete it; \param rotate the rotation to apply for the search order \since 0.14 **/ - bool search(const QString &text, double &rectLeft, double &rectTop, double &rectRight, double &rectBottom, SearchDirection direction, SearchMode caseSensitive, Rotation rotate = Rotate0) const; - + Q_DECL_DEPRECATED bool search(const QString &text, double &rectLeft, double &rectTop, double &rectRight, double &rectBottom, SearchDirection direction, SearchMode caseSensitive, Rotation rotate = Rotate0) const; + + /** + Returns true if the specified text was found. + + \param text the text the search + \param rectXXX in all directions is used to return where the text was found, for NextResult and PreviousResult + indicates where to continue searching for + \param direction in which direction do the search + \param flags the flags to consider during matching + \param rotate the rotation to apply for the search order + + \since 0.31 + **/ + bool search(const QString &text, double &rectLeft, double &rectTop, double &rectRight, double &rectBottom, SearchDirection direction, SearchFlags flags = 0, Rotation rotate = Rotate0) const; + /** Returns a list of all occurrences of the specified text on the page. @@ -605,7 +629,20 @@ delete it; \since 0.22 **/ - QList<QRectF> search(const QString &text, SearchMode caseSensitive, Rotation rotate = Rotate0) const; + Q_DECL_DEPRECATED QList<QRectF> search(const QString &text, SearchMode caseSensitive, Rotation rotate = Rotate0) const; + + /** + Returns a list of all occurrences of the specified text on the page. + + \param text the text to search + \param flags the flags to consider during matching + \param rotate the rotation to apply for the search order + + \warning Do not use the returned QRectF as arguments of another search call because of truncation issues if qreal is defined as float. + + \since 0.31 + **/ + QList<QRectF> search(const QString &text, SearchFlags flags = 0, Rotation rotate = Rotate0) const; /** Returns a list of text of the page @@ -1787,6 +1824,7 @@ height = dummy.height(); } Q_DECLARE_OPERATORS_FOR_FLAGS(Poppler::Page::PainterFlags) +Q_DECLARE_OPERATORS_FOR_FLAGS(Poppler::Page::SearchFlags) Q_DECLARE_OPERATORS_FOR_FLAGS(Poppler::Document::RenderHints) Q_DECLARE_OPERATORS_FOR_FLAGS(Poppler::PDFConverter::PDFOptions) Q_DECLARE_OPERATORS_FOR_FLAGS(Poppler::PSConverter::PSOptions) diff --git a/qt5/tests/check_search.cpp b/qt5/tests/check_search.cpp index efb5556..d23b208 100644 --- a/qt5/tests/check_search.cpp +++ b/qt5/tests/check_search.cpp @@ -8,6 +8,7 @@ class TestSearch: public QObject private slots: void bug7063(); void testNextAndPrevious(); + void testWholeWordsOnly(); }; void TestSearch::bug7063() @@ -93,6 +94,36 @@ void TestSearch::testNextAndPrevious() delete doc; } +void TestSearch::testWholeWordsOnly() +{ + QScopedPointer< Poppler::Document > document(Poppler::Document::load(TESTDATADIR "/unittestcases/WithActualText.pdf")); + QVERIFY( document ); + + QScopedPointer< Poppler::Page > page(document->page(0)); + QVERIFY( page ); + + const Poppler::Page::SearchDirection direction = Poppler::Page::FromTop; + + const Poppler::Page::SearchFlags mode0 = 0; + const Poppler::Page::SearchFlags mode1 = Poppler::Page::IgnoreCase; + const Poppler::Page::SearchFlags mode2 = Poppler::Page::WholeWorlds; + const Poppler::Page::SearchFlags mode3 = Poppler::Page::IgnoreCase | Poppler::Page::WholeWorlds; + + double left, top, right, bottom; + + QCOMPARE( page->search(QLatin1String("brown"), left, top, right, bottom, direction, mode0), true ); + QCOMPARE( page->search(QLatin1String("brOwn"), left, top, right, bottom, direction, mode0), false ); + + QCOMPARE( page->search(QLatin1String("brOwn"), left, top, right, bottom, direction, mode1), true ); + QCOMPARE( page->search(QLatin1String("brawn"), left, top, right, bottom, direction, mode1), false ); + + QCOMPARE( page->search(QLatin1String("brown"), left, top, right, bottom, direction, mode2), true ); + QCOMPARE( page->search(QLatin1String("own"), left, top, right, bottom, direction, mode2), false ); + + QCOMPARE( page->search(QLatin1String("brOwn"), left, top, right, bottom, direction, mode3), true ); + QCOMPARE( page->search(QLatin1String("Own"), left, top, right, bottom, direction, mode3), false ); +} + QTEST_MAIN(TestSearch) #include "check_search.moc" -- 2.2.1
_______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
