| 3761 | } |
| 3762 | |
| 3763 | void Document::searchText(int searchID, const QString &text, bool fromStart, Qt::CaseSensitivity caseSensitivity, SearchType type, bool moveViewport, const QColor &color) |
| 3764 | { |
| 3765 | d->m_searchCancelled = false; |
| 3766 | |
| 3767 | // safety checks: don't perform searches on empty or unsearchable docs |
| 3768 | if (!d->m_generator || !d->m_generator->hasFeature(Generator::TextExtraction) || d->m_pagesVector.isEmpty()) { |
| 3769 | Q_EMIT searchFinished(searchID, NoMatchFound); |
| 3770 | return; |
| 3771 | } |
| 3772 | |
| 3773 | // if searchID search not recorded, create new descriptor and init params |
| 3774 | auto searchIt = d->m_searches.find(searchID); |
| 3775 | if (searchIt == d->m_searches.end()) { |
| 3776 | RunningSearch *search = new RunningSearch(); |
| 3777 | search->continueOnPage = -1; |
| 3778 | searchIt = d->m_searches.insert(searchID, search); |
| 3779 | } |
| 3780 | RunningSearch *s = *searchIt; |
| 3781 | |
| 3782 | // update search structure |
| 3783 | bool newText = text != s->cachedString; |
| 3784 | s->cachedString = text; |
| 3785 | s->cachedType = type; |
| 3786 | s->cachedCaseSensitivity = caseSensitivity; |
| 3787 | s->cachedViewportMove = moveViewport; |
| 3788 | s->cachedColor = color; |
| 3789 | s->isCurrentlySearching = true; |
| 3790 | |
| 3791 | // global data for search |
| 3792 | QSet<int> *pagesToNotify = new QSet<int>; |
| 3793 | |
| 3794 | // remove highlights from pages and queue them for notifying changes |
| 3795 | *pagesToNotify += s->highlightedPages; |
| 3796 | for (const int pageNumber : std::as_const(s->highlightedPages)) { |
| 3797 | d->m_pagesVector.at(pageNumber)->d->deleteHighlights(searchID); |
| 3798 | } |
| 3799 | s->highlightedPages.clear(); |
| 3800 | |
| 3801 | // set hourglass cursor |
| 3802 | QApplication::setOverrideCursor(Qt::WaitCursor); |
| 3803 | |
| 3804 | // 1. ALLDOC - process all document marking pages |
| 3805 | if (type == AllDocument) { |
| 3806 | QHash<Page *, QList<RegularAreaRect *>> *pageMatches = new QHash<Page *, QList<RegularAreaRect *>>; |
| 3807 | |
| 3808 | // search and highlight 'text' (as a solid phrase) on all pages |
| 3809 | QTimer::singleShot(0, this, [this, pagesToNotify, pageMatches, searchID] { d->doContinueAllDocumentSearch(pagesToNotify, pageMatches, 0, searchID); }); |
| 3810 | } |
| 3811 | // 2. NEXTMATCH - find next matching item (or start from top) |
| 3812 | // 3. PREVMATCH - find previous matching item (or start from bottom) |
| 3813 | else if (type == NextMatch || type == PreviousMatch) { |
| 3814 | // find out from where to start/resume search from |
| 3815 | const bool forward = type == NextMatch; |
| 3816 | const int viewportPage = (*d->m_viewportIterator).pageNumber; |
| 3817 | const int fromStartSearchPage = forward ? 0 : d->m_pagesVector.count() - 1; |
| 3818 | int currentPageNumber = fromStart ? fromStartSearchPage : ((s->continueOnPage != -1) ? s->continueOnPage : viewportPage); |
| 3819 | const Page *lastPage = fromStart ? nullptr : d->m_pagesVector[currentPageNumber]; |
| 3820 | int pagesDone = 0; |