summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2020-05-28 08:07:51 +0200
committerTomaž Vajngerl <tomaz.vajngerl@collabora.co.uk>2020-07-30 14:52:45 +0200
commite17d264a2bf73bf3a0ce125e9d373d2a08023f0e (patch)
tree38b9c08427ce07b2d87f01903090790db0139c16
parent7000e87fa207612f590ee72062a92fb0d805bf34 (diff)
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. Reviewed-on: https://gerrit.libreoffice.org/c/core/+/95348 Tested-by: Tomaž Vajngerl <quikee@gmail.com> Reviewed-by: Tomaž Vajngerl <quikee@gmail.com> (cherry picked from commit 7a84dffb44d4b1fa6e2a3cd3e3dc7d942f3c3e80) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/95923 (cherry picked from commit 894b1a2f412ecc889a9932df3935c69e30852c6f) Change-Id: I55d67772a2fe876ae72b9164998347304025d3e0
-rw-r--r--sd/source/ui/view/Outliner.cxx247
1 files changed, 209 insertions, 38 deletions
diff --git a/sd/source/ui/view/Outliner.cxx b/sd/source/ui/view/Outliner.cxx
index ef8204ad5b80..7d8ba3eb9e13 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/wrkwin.hxx>
#include <vcl/settings.hxx>
+#include <vcl/VectorGraphicSearch.hxx>
#include <svl/srchitem.hxx>
#include <editeng/colritem.hxx>
@@ -35,6 +36,7 @@
#include <svx/svxerr.hxx>
#include <svx/svdotext.hxx>
#include <svx/svdotable.hxx>
+#include <svx/svdograf.hxx>
#include <editeng/unolingu.hxx>
#include <svx/svditer.hxx>
#include <com/sun/star/linguistic2/XSpellChecker1.hpp>
@@ -111,6 +113,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
@@ -702,21 +709,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));
+ }
}
}
@@ -752,6 +831,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
{
@@ -783,19 +867,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
@@ -1062,6 +1167,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
@@ -1077,6 +1196,9 @@ void SdOutliner::ProvideNextTextObject()
mbEndOfSearch = false;
mbFoundObject = false;
+ // reset the vector search
+ mpImpl->mpVectorGraphicSearch.reset();
+
mpView->UnmarkAllObj (mpView->GetSdrPageView());
try
{
@@ -1109,35 +1231,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);
- std::shared_ptr<sd::ViewShell> pViewShell (mpWeakViewShell.lock());
- if (pViewShell != nullptr)
- switch (meMode)
+ 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)
{
- 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
@@ -1751,6 +1921,7 @@ VclPtr<vcl::Window> SdOutliner::GetMessageBoxParent()
SdOutliner::Implementation::Implementation()
: meOriginalEditMode(EditMode::Page),
+ mbCurrentIsVectorGraphic(false),
mbOwnOutlineView(false),
mpOutlineView(nullptr)
{