sd/source/ui/view/Outliner.cxx | 247 ++++++++++++++++++++++++++++++++++------- 1 file changed, 209 insertions(+), 38 deletions(-)
New commits: commit 894b1a2f412ecc889a9932df3935c69e30852c6f Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Thu May 28 08:07:51 2020 +0200 Commit: Tomaž Vajngerl <qui...@gmail.com> CommitDate: Tue Jun 9 15:22:46 2020 +0200 sd: Search inside PDF document that were inserted as a graphic This implements searching inside PDF documents that were inserted into the Draw/Impress document as a graphics and marks the areas of text that matches the search string. Complex (regex) search is not supported. Change-Id: I55d67772a2fe876ae72b9164998347304025d3e0 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/95348 Tested-by: Tomaž Vajngerl <qui...@gmail.com> Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> (cherry picked from commit 7a84dffb44d4b1fa6e2a3cd3e3dc7d942f3c3e80) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/95923 diff --git a/sd/source/ui/view/Outliner.cxx b/sd/source/ui/view/Outliner.cxx index c2cff89909a7..0d69cf872090 100644 --- a/sd/source/ui/view/Outliner.cxx +++ b/sd/source/ui/view/Outliner.cxx @@ -21,6 +21,7 @@ #include <boost/property_tree/json_parser.hpp> #include <vcl/settings.hxx> #include <vcl/svapp.hxx> +#include <vcl/VectorGraphicSearch.hxx> #include <svl/srchitem.hxx> #include <svl/intitem.hxx> @@ -29,6 +30,7 @@ #include <vcl/weld.hxx> #include <sfx2/dispatch.hxx> #include <svx/svdotext.hxx> +#include <svx/svdograf.hxx> #include <editeng/unolingu.hxx> #include <com/sun/star/linguistic2/XSpellChecker1.hpp> #include <svx/srchdlg.hxx> @@ -96,6 +98,11 @@ public: */ void ReleaseOutlinerView(); + /** Search in vector graphic + */ + bool mbCurrentIsVectorGraphic; + std::unique_ptr<VectorGraphicSearch> mpVectorGraphicSearch; + private: /** Flag that specifies whether we own the outline view pointed to by <member>mpOutlineView</member> and thus have to @@ -685,21 +692,93 @@ bool SdOutliner::SearchAndReplaceAll() return bRet; } +namespace +{ +basegfx::B2DRange b2DRectangleFromRectangle( const ::tools::Rectangle& rRect ) +{ + if (rRect.IsWidthEmpty() && rRect.IsHeightEmpty()) + return basegfx::B2DRange(basegfx::B2DTuple(rRect.Left(), rRect.Top())); + return basegfx::B2DRectangle(rRect.Left(), + rRect.Top(), + rRect.IsWidthEmpty() ? rRect.Left() : rRect.Right(), + rRect.IsHeightEmpty() ? rRect.Top() : rRect.Bottom()); +} + +void getPDFSelections(std::vector<basegfx::B2DRectangle> & rSubSelections, + std::unique_ptr<VectorGraphicSearch> & rVectorGraphicSearch, + SdrObject* pObject) +{ + basegfx::B2DSize aPdfPageSize = rVectorGraphicSearch->pageSize(); + + basegfx::B2DRectangle aObjectB2DRectHMM(b2DRectangleFromRectangle(pObject->GetLogicRect())); + + // Setup coordinate conversion matrix to convert the inner PDF + // coordinates to the page relative coordinates + basegfx::B2DHomMatrix aB2DMatrix; + + aB2DMatrix.scale(aObjectB2DRectHMM.getWidth() / aPdfPageSize.getX(), + aObjectB2DRectHMM.getHeight() / aPdfPageSize.getY()); + + aB2DMatrix.translate(aObjectB2DRectHMM.getMinX(), aObjectB2DRectHMM.getMinY()); + + basegfx::B2DRectangle aCombined; + + for (auto const & rRectangle : rVectorGraphicSearch->getTextRectangles()) + { + basegfx::B2DRectangle aRectangle(rRectangle); + aRectangle *= aB2DMatrix; + if (aCombined.isEmpty()) + aCombined = aRectangle; + else + aCombined.expand(aRectangle); + } + + rSubSelections.push_back(aCombined); +} + +} // end namespace + void SdOutliner::sendLOKSearchResultCallback(std::shared_ptr<sd::ViewShell> & pViewShell, OutlinerView* pOutlinerView, std::vector<sd::SearchSelection>* pSelections) { std::vector<::tools::Rectangle> aLogicRects; - pOutlinerView->GetSelectionRectangles(aLogicRects); + if (mpImpl->mbCurrentIsVectorGraphic) + { + basegfx::B2DSize aPdfPageSize = mpImpl->mpVectorGraphicSearch->pageSize(); + + tools::Rectangle aObjectRectTwip = OutputDevice::LogicToLogic(mpObj->GetLogicRect(), MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip)); + basegfx::B2DRectangle aObjectB2DRectTwip(b2DRectangleFromRectangle(aObjectRectTwip)); + + // Setup coordinate conversion matrix to convert the inner PDF + // coordinates to the page relative coordinates + basegfx::B2DHomMatrix aB2DMatrix; + + aB2DMatrix.scale(aObjectB2DRectTwip.getWidth() / aPdfPageSize.getX(), + aObjectB2DRectTwip.getHeight() / aPdfPageSize.getY()); + + aB2DMatrix.translate(aObjectB2DRectTwip.getMinX(), aObjectB2DRectTwip.getMinY()); - // convert to twips if in 100thmm (seems as if LibreOfficeKit is based on twips?). Do this - // here where we have the only place needing this, *not* in ImpEditView::GetSelectionRectangles - // which makes that method unusable for others - if (pOutlinerView->GetWindow() && MapUnit::Map100thMM == pOutlinerView->GetWindow()->GetMapMode().GetMapUnit()) + for (auto const & rRectangle : mpImpl->mpVectorGraphicSearch->getTextRectangles()) + { + basegfx::B2DRectangle aRectangle(rRectangle); + aRectangle *= aB2DMatrix; + aLogicRects.emplace_back(Point(aRectangle.getMinX(), aRectangle.getMinY()), Size(aRectangle.getWidth(), aRectangle.getHeight())); + } + } + else { - for (tools::Rectangle& rRectangle : aLogicRects) + pOutlinerView->GetSelectionRectangles(aLogicRects); + + // convert to twips if in 100thmm (seems as if LibreOfficeKit is based on twips?). Do this + // here where we have the only place needing this, *not* in ImpEditView::GetSelectionRectangles + // which makes that method unusable for others + if (pOutlinerView->GetWindow() && MapUnit::Map100thMM == pOutlinerView->GetWindow()->GetMapMode().GetMapUnit()) { - rRectangle = OutputDevice::LogicToLogic(rRectangle, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip)); + for (tools::Rectangle& rRectangle : aLogicRects) + { + rRectangle = OutputDevice::LogicToLogic(rRectangle, MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip)); + } } } @@ -735,6 +814,11 @@ void SdOutliner::sendLOKSearchResultCallback(std::shared_ptr<sd::ViewShell> & pV boost::property_tree::write_json(aStream, aTree); aPayload = aStream.str().c_str(); rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_RESULT_SELECTION, aPayload.getStr()); + + if (mpImpl->mbCurrentIsVectorGraphic) + { + rSfxViewShell.libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, sRectangles.getStr()); + } } else { @@ -766,19 +850,40 @@ bool SdOutliner::SearchAndReplaceOnce(std::vector<sd::SearchSelection>* pSelecti if (nullptr != dynamic_cast<const sd::DrawViewShell*>(pViewShell.get())) { - // When replacing we first check if there is a selection - // indicating a match. If there is then replace it. The - // following call to StartSearchAndReplace will then search for - // the next match. - if (meMode == SEARCH - && mpSearchItem->GetCommand() == SvxSearchCmd::REPLACE) - if (pOutlinerView->GetSelection().HasRange()) - pOutlinerView->StartSearchAndReplace(*mpSearchItem); - - // Search for the next match. sal_uLong nMatchCount = 0; - if (mpSearchItem->GetCommand() != SvxSearchCmd::REPLACE_ALL) - nMatchCount = pOutlinerView->StartSearchAndReplace(*mpSearchItem); + + if (mpImpl->mbCurrentIsVectorGraphic) + { + if (mpImpl->mpVectorGraphicSearch->next()) + { + nMatchCount = 1; + + SdrPageView* pPageView = mpView->GetSdrPageView(); + mpView->UnmarkAllObj(pPageView); + + std::vector<basegfx::B2DRectangle> aSubSelections; + getPDFSelections(aSubSelections, mpImpl->mpVectorGraphicSearch, mpObj); + mpView->MarkObj(mpObj, pPageView, false, false, aSubSelections); + } + } + else + { + // When replacing we first check if there is a selection + // indicating a match. If there is then replace it. The + // following call to StartSearchAndReplace will then search for + // the next match. + if (meMode == SEARCH && mpSearchItem->GetCommand() == SvxSearchCmd::REPLACE) + { + if (pOutlinerView->GetSelection().HasRange()) + pOutlinerView->StartSearchAndReplace(*mpSearchItem); + } + + // Search for the next match. + if (mpSearchItem->GetCommand() != SvxSearchCmd::REPLACE_ALL) + { + nMatchCount = pOutlinerView->StartSearchAndReplace(*mpSearchItem); + } + } // Go to the next text object when there have been no matches in // the current object or the whole object has already been @@ -1045,6 +1150,20 @@ bool lclIsValidTextObject(const sd::outliner::IteratorPosition& rPosition) return (pObject != nullptr) && pObject->HasText() && ! pObject->IsEmptyPresObj(); } +bool isValidVectorGraphicObject(const sd::outliner::IteratorPosition& rPosition) +{ + auto* pGraphicObject = dynamic_cast<SdrGrafObj*>(rPosition.mxObject.get()); + if (pGraphicObject) + { + auto const& pVectorGraphicData = pGraphicObject->GetGraphic().getVectorGraphicData(); + if (pVectorGraphicData && VectorGraphicDataType::Pdf == pVectorGraphicData->getVectorGraphicDataType()) + { + return true; + } + } + return false; +} + } // end anonymous namespace @@ -1060,6 +1179,9 @@ void SdOutliner::ProvideNextTextObject() mbEndOfSearch = false; mbFoundObject = false; + // reset the vector search + mpImpl->mpVectorGraphicSearch.reset(); + mpView->UnmarkAllObj (mpView->GetSdrPageView()); try { @@ -1092,35 +1214,83 @@ void SdOutliner::ProvideNextTextObject() // LOK: do not descent to notes or master pages when searching bool bForbiddenPage = comphelper::LibreOfficeKit::isActive() && (maCurrentPosition.mePageKind != PageKind::Standard || maCurrentPosition.meEditMode != EditMode::Page); - // Switch to the current object only if it is a valid text object. - if (!bForbiddenPage && lclIsValidTextObject(maCurrentPosition)) + mpImpl->mbCurrentIsVectorGraphic = false; + + if (!bForbiddenPage) { - // Don't set yet in case of searching: the text object may not match. - if (meMode != SEARCH) - mpObj = SetObject(maCurrentPosition); - else + // Switch to the current object only if it is a valid text object. + if (lclIsValidTextObject(maCurrentPosition)) + { + // Don't set yet in case of searching: the text object may not match. + if (meMode != SEARCH) + mpObj = SetObject(maCurrentPosition); + else + mpObj = maCurrentPosition.mxObject.get(); + } + // Or if the object is a valid graphic object which contains vector graphic + else if (meMode == SEARCH && isValidVectorGraphicObject(maCurrentPosition)) + { mpObj = maCurrentPosition.mxObject.get(); + mpImpl->mbCurrentIsVectorGraphic = true; + } } + + // Advance to the next object ++maObjectIterator; if (mpObj) { - PutTextIntoOutliner(); + if (mpImpl->mbCurrentIsVectorGraphic) + { + // We know here the object is a SdrGrafObj and that it + // contains a vector graphic + auto* pGraphicObject = static_cast<SdrGrafObj*>(mpObj); + OUString const & rString = mpSearchItem->GetSearchString(); + + mpImpl->mpVectorGraphicSearch = std::make_unique<VectorGraphicSearch>(pGraphicObject->GetGraphic()); + if (mpImpl->mpVectorGraphicSearch->search(rString)) + { + bool bResult = mpImpl->mpVectorGraphicSearch->next(); + if (bResult) + { + mpObj = SetObject(maCurrentPosition); + + mbStringFound = true; + mbMatchMayExist = true; + mbFoundObject = true; + + SdrPageView* pPageView = mpView->GetSdrPageView(); + mpView->UnmarkAllObj(pPageView); + + std::vector<basegfx::B2DRectangle> aSubSelections; + getPDFSelections(aSubSelections, mpImpl->mpVectorGraphicSearch, mpObj); + mpView->MarkObj(mpObj, pPageView, false, false, aSubSelections); + + mpDrawDocument->GetDocSh()->SetWaitCursor( false ); + } + } + } + else + { + PutTextIntoOutliner(); - std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); - if (pViewShell != nullptr) - switch (meMode) + std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock()); + if (pViewShell != nullptr) { - case SEARCH: - PrepareSearchAndReplace (); - break; - case SPELL: - PrepareSpellCheck (); - break; - case TEXT_CONVERSION: - PrepareConversion(); - break; + switch (meMode) + { + case SEARCH: + PrepareSearchAndReplace (); + break; + case SPELL: + PrepareSpellCheck (); + break; + case TEXT_CONVERSION: + PrepareConversion(); + break; + } } + } } } else @@ -1742,6 +1912,7 @@ weld::Window* SdOutliner::GetMessageBoxParent() SdOutliner::Implementation::Implementation() : meOriginalEditMode(EditMode::Page), + mbCurrentIsVectorGraphic(false), mbOwnOutlineView(false), mpOutlineView(nullptr) { _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits