diff options
-rw-r--r-- | drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx | 23 | ||||
-rw-r--r-- | drawinglayer/source/processor2d/hittestprocessor2d.cxx | 9 | ||||
-rw-r--r-- | drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx | 12 | ||||
-rw-r--r-- | include/drawinglayer/primitive2d/texthierarchyprimitive2d.hxx | 10 | ||||
-rw-r--r-- | include/drawinglayer/processor2d/hittestprocessor2d.hxx | 15 | ||||
-rw-r--r-- | include/svx/sdrhittesthelper.hxx | 9 | ||||
-rw-r--r-- | svx/source/svdraw/sdrhittesthelper.cxx | 22 | ||||
-rw-r--r-- | svx/source/svdraw/svdotextdecomposition.cxx | 13 | ||||
-rw-r--r-- | svx/source/svdraw/svdview.cxx | 92 |
9 files changed, 152 insertions, 53 deletions
diff --git a/drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx b/drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx index 86883e43b6cb..45fa8531bee3 100644 --- a/drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx +++ b/drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx @@ -95,11 +95,28 @@ namespace drawinglayer TextHierarchyFieldPrimitive2D::TextHierarchyFieldPrimitive2D( const Primitive2DContainer& rChildren, const FieldType& rFieldType, - const OUString& rString) + const std::vector< std::pair< OUString, OUString>>* pNameValue) : GroupPrimitive2D(rChildren), meType(rFieldType), - maString(rString) + meNameValue() { + if (nullptr != pNameValue) + { + meNameValue = *pNameValue; + } + } + + OUString TextHierarchyFieldPrimitive2D::getValue(const OUString& rName) const + { + for (const std::pair< OUString, OUString >& candidate : meNameValue) + { + if (candidate.first.equals(rName)) + { + return candidate.second; + } + } + + return OUString(); } bool TextHierarchyFieldPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const @@ -109,7 +126,7 @@ namespace drawinglayer const TextHierarchyFieldPrimitive2D& rCompare = static_cast<const TextHierarchyFieldPrimitive2D&>(rPrimitive); return (getType() == rCompare.getType() - && getString() == rCompare.getString()); + && getNameValue() == rCompare.getNameValue()); } return false; diff --git a/drawinglayer/source/processor2d/hittestprocessor2d.cxx b/drawinglayer/source/processor2d/hittestprocessor2d.cxx index 82ccfd00b7fe..cae95d7e6a51 100644 --- a/drawinglayer/source/processor2d/hittestprocessor2d.cxx +++ b/drawinglayer/source/processor2d/hittestprocessor2d.cxx @@ -45,6 +45,8 @@ namespace drawinglayer : BaseProcessor2D(rViewInformation), maDiscreteHitPosition(), mfDiscreteHitTolerance(0.0), + maHitStack(), + mbCollectHitStack(false), mbHit(false), mbHitTextOnly(bHitTextOnly) { @@ -536,6 +538,13 @@ namespace drawinglayer break; } } + + if (getHit() && getCollectHitStack()) + { + /// push candidate to HitStack to create it. This only happens when a hit is found and + /// creating the HitStack was requested (see collectHitStack) + maHitStack.append(primitive2d::Primitive2DReference(const_cast< primitive2d::BasePrimitive2D* >(&rCandidate))); + } } } // end of namespace processor2d diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx index efe3342b7cf9..c8ec56088085 100644 --- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx +++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx @@ -977,6 +977,7 @@ namespace drawinglayer const OString aCommentStringCommon("FIELD_SEQ_BEGIN"); const OString aCommentStringPage("FIELD_SEQ_BEGIN;PageField"); const OString aCommentStringEnd("FIELD_SEQ_END"); + OUString aURL; switch(rFieldPrimitive.getType()) { @@ -992,8 +993,13 @@ namespace drawinglayer } case drawinglayer::primitive2d::FIELD_TYPE_URL : { - const OUString& rURL = rFieldPrimitive.getString(); - mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast< const sal_uInt8* >(rURL.getStr()), 2 * rURL.getLength())); + aURL = rFieldPrimitive.getValue("URL"); + + if (!aURL.isEmpty()) + { + mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast<const sal_uInt8*>(aURL.getStr()), 2 * aURL.getLength())); + } + break; } } @@ -1015,7 +1021,7 @@ namespace drawinglayer (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY())); vcl::PDFExtOutDevBookmarkEntry aBookmark; aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic); - aBookmark.aBookmark = rFieldPrimitive.getString(); + aBookmark.aBookmark = aURL; std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks(); rBookmarks.push_back( aBookmark ); } diff --git a/include/drawinglayer/primitive2d/texthierarchyprimitive2d.hxx b/include/drawinglayer/primitive2d/texthierarchyprimitive2d.hxx index 093ccce65fa3..5234081584a3 100644 --- a/include/drawinglayer/primitive2d/texthierarchyprimitive2d.hxx +++ b/include/drawinglayer/primitive2d/texthierarchyprimitive2d.hxx @@ -148,19 +148,23 @@ namespace drawinglayer class DRAWINGLAYER_DLLPUBLIC TextHierarchyFieldPrimitive2D : public GroupPrimitive2D { private: + /// field type definition FieldType meType; - OUString maString; + + /// field data as name/value pairs (dependent of field type definition) + std::vector< std::pair< OUString, OUString>> meNameValue; public: /// constructor TextHierarchyFieldPrimitive2D( const Primitive2DContainer& rChildren, const FieldType& rFieldType, - const OUString& rString); + const std::vector< std::pair< OUString, OUString>>* pNameValue = nullptr); /// data read access FieldType getType() const { return meType; } - const OUString& getString() const { return maString; } + const std::vector< std::pair< OUString, OUString>>& getNameValue() const { return meNameValue; } + OUString getValue(const OUString& rName) const; /// compare operator virtual bool operator==(const BasePrimitive2D& rPrimitive) const override; diff --git a/include/drawinglayer/processor2d/hittestprocessor2d.hxx b/include/drawinglayer/processor2d/hittestprocessor2d.hxx index 466bb948df49..e5002cb6cf2f 100644 --- a/include/drawinglayer/processor2d/hittestprocessor2d.hxx +++ b/include/drawinglayer/processor2d/hittestprocessor2d.hxx @@ -46,6 +46,13 @@ namespace drawinglayer /// discrete HitTolerance double mfDiscreteHitTolerance; + /// stack of HitPrimitives, taken care of during HitTest run + primitive2d::Primitive2DContainer maHitStack; + + /// flag if HitStack shall be collected as part of the result, default is false + bool mbCollectHitStack : 1; + + /// Boolean to flag if a hit was found. If yes, fast exit is taken bool mbHit : 1; /// flag to concentrate on text hits only @@ -69,9 +76,17 @@ namespace drawinglayer bool bHitTextOnly); virtual ~HitTestProcessor2D() override; + /// switch on collecting primitives for a found hit on maHitStack, default is off + void collectHitStack(bool bCollect) { mbCollectHitStack = bCollect; } + + /// get HitStack of primitives, first is the one that created the hit, last is the + /// top-most + const primitive2d::Primitive2DContainer& getHitStack() const { return maHitStack; } + /// data read access const basegfx::B2DPoint& getDiscreteHitPosition() const { return maDiscreteHitPosition; } double getDiscreteHitTolerance() const { return mfDiscreteHitTolerance; } + bool getCollectHitStack() const { return mbCollectHitStack; } bool getHit() const { return mbHit; } bool getHitTextOnly() const { return mbHitTextOnly; } }; diff --git a/include/svx/sdrhittesthelper.hxx b/include/svx/sdrhittesthelper.hxx index b8da54c7d839..17a36c4b1477 100644 --- a/include/svx/sdrhittesthelper.hxx +++ b/include/svx/sdrhittesthelper.hxx @@ -32,6 +32,7 @@ class SdrLayerIDSet; class SdrObjList; namespace sdr { namespace contact { class ViewObjectContact; }} namespace basegfx { class B2DPoint; } +namespace drawinglayer { namespace primitive2d { class Primitive2DContainer; }} // Wrappers for classic Sdr* Mode/View classes @@ -42,7 +43,9 @@ SVX_DLLPUBLIC SdrObject* SdrObjectPrimitiveHit( sal_uInt16 nTol, const SdrPageView& rSdrPageView, const SdrLayerIDSet* pVisiLayer, - bool bTextOnly); + bool bTextOnly, + /// allow getting back an evtl. resulting primitive stack which lead to a hit + drawinglayer::primitive2d::Primitive2DContainer* pHitContainer = nullptr); SVX_DLLPUBLIC SdrObject* SdrObjListPrimitiveHit( const SdrObjList& rList, @@ -59,7 +62,9 @@ SVX_DLLPUBLIC bool ViewObjectContactPrimitiveHit( const sdr::contact::ViewObjectContact& rVOC, const basegfx::B2DPoint& rHitPosition, double fLogicHitTolerance, - bool bTextOnly); + bool bTextOnly, + /// allow to get back the stack of primitives that lead to the hit + drawinglayer::primitive2d::Primitive2DContainer* pHitContainer = nullptr); #endif // INCLUDED_SVX_SDRHITTESTHELPER_HXX diff --git a/svx/source/svdraw/sdrhittesthelper.cxx b/svx/source/svdraw/sdrhittesthelper.cxx index a1bdb47f8879..cf9191c8428e 100644 --- a/svx/source/svdraw/sdrhittesthelper.cxx +++ b/svx/source/svdraw/sdrhittesthelper.cxx @@ -39,7 +39,8 @@ SdrObject* SdrObjectPrimitiveHit( sal_uInt16 nTol, const SdrPageView& rSdrPageView, const SdrLayerIDSet* pVisiLayer, - bool bTextOnly) + bool bTextOnly, + drawinglayer::primitive2d::Primitive2DContainer* pHitContainer) { SdrObject* pResult = nullptr; @@ -77,7 +78,7 @@ SdrObject* SdrObjectPrimitiveHit( const sdr::contact::ViewObjectContact& rVOC = rObject.GetViewContact().GetViewObjectContact( rSdrPageView.GetPageWindow(0)->GetObjectContact()); - if(ViewObjectContactPrimitiveHit(rVOC, aHitPosition, fLogicTolerance, bTextOnly)) + if(ViewObjectContactPrimitiveHit(rVOC, aHitPosition, fLogicTolerance, bTextOnly, pHitContainer)) { pResult = const_cast< SdrObject* >(&rObject); } @@ -117,7 +118,8 @@ bool ViewObjectContactPrimitiveHit( const sdr::contact::ViewObjectContact& rVOC, const basegfx::B2DPoint& rHitPosition, double fLogicHitTolerance, - bool bTextOnly) + bool bTextOnly, + drawinglayer::primitive2d::Primitive2DContainer* pHitContainer) { basegfx::B2DRange aObjectRange(rVOC.getObjectRange()); @@ -146,11 +148,23 @@ bool ViewObjectContactPrimitiveHit( fLogicHitTolerance, bTextOnly); + // ask for HitStack + aHitTestProcessor2D.collectHitStack(true); + // feed it with the primitives aHitTestProcessor2D.process(rSequence); // deliver result - return aHitTestProcessor2D.getHit(); + if (aHitTestProcessor2D.getHit()) + { + if (pHitContainer) + { + // fetch HitStack primitives if requested + *pHitContainer = aHitTestProcessor2D.getHitStack(); + } + + return true; + } } } } diff --git a/svx/source/svdraw/svdotextdecomposition.cxx b/svx/source/svdraw/svdotextdecomposition.cxx index 0ba47e9b4c83..2e30cc3edf5f 100644 --- a/svx/source/svdraw/svdotextdecomposition.cxx +++ b/svx/source/svdraw/svdotextdecomposition.cxx @@ -479,15 +479,22 @@ namespace if(pURLField) { - pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_URL, pURLField->GetURL()); + // extended this to hold more of the contents of the original + // SvxURLField since that stuff is still used in HitTest and e.g. Calc + std::vector< std::pair< OUString, OUString>> meValues; + meValues.push_back(std::pair< OUString, OUString>("URL", pURLField->GetURL())); + meValues.push_back(std::pair< OUString, OUString>("Representation", pURLField->GetRepresentation())); + meValues.push_back(std::pair< OUString, OUString>("TargetFrame", pURLField->GetTargetFrame())); + meValues.push_back(std::pair< OUString, OUString>("SvxURLFormat", OUString::number(static_cast<sal_uInt16>(pURLField->GetFormat())))); + pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_URL, &meValues); } else if(pPageField) { - pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_PAGE, ""); + pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_PAGE); } else { - pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_COMMON, ""); + pPrimitive = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(aSequence, drawinglayer::primitive2d::FIELD_TYPE_COMMON); } } diff --git a/svx/source/svdraw/svdview.cxx b/svx/source/svdraw/svdview.cxx index f11e6f6b0055..2ec9a93fef13 100644 --- a/svx/source/svdraw/svdview.cxx +++ b/svx/source/svdraw/svdview.cxx @@ -50,6 +50,7 @@ #include <svx/sdrhittesthelper.hxx> #include <svx/sdr/contact/viewcontact.hxx> #include <drawinglayer/processor2d/contourextractor2d.hxx> +#include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx> SdrViewEvent::SdrViewEvent() @@ -440,45 +441,66 @@ SdrHitKind SdrView::PickAnything(const Point& rLogicPos, SdrViewEvent& rVEvt) co SdrTextObj* pTextObj=dynamic_cast<SdrTextObj*>( pHitObj ); if (pTextObj!=nullptr && pTextObj->HasText()) { - bool bTEHit(pPV && - SdrObjectPrimitiveHit(*pTextObj, aLocalLogicPosition, 0, *pPV, &pPV->GetVisibleLayers(), true)); - - if (bTEHit) + // use the primitive-based HitTest which is more accurate anyways. It + // will correctly handle rotated/mirrored/sheared/scaled text and can + // now return a HitContainer containing the primitive hierarchy of the + // primitive that triggered the hit. The first entry is that primitive, + // the others are the full stack of primitives leading to that one which + // includes grouping primitives (like TextHierarchyPrimitives we deed here) + // but also all decomposed ones which lead to the creation of that primitive + drawinglayer::primitive2d::Primitive2DContainer aHitContainer; + const bool bTEHit(pPV && SdrObjectPrimitiveHit(*pTextObj, aLocalLogicPosition, 0, *pPV, &pPV->GetVisibleLayers(), true, &aHitContainer)); + + if (bTEHit && !aHitContainer.empty()) { - tools::Rectangle aTextRect; - tools::Rectangle aAnchor; - SdrOutliner* pOutliner = &pTextObj->ImpGetDrawOutliner(); - if( pTextObj->GetModel() ) - pOutliner = &pTextObj->GetModel()->GetHitTestOutliner(); - - pTextObj->TakeTextRect( *pOutliner, aTextRect, false, &aAnchor, false ); - - // #i73628# Use a text-relative position for hit test in hit test outliner - Point aTemporaryTextRelativePosition(aLocalLogicPosition - aTextRect.TopLeft()); - - // account for FitToSize - bool bFitToSize(pTextObj->IsFitToSize()); - if (bFitToSize) { - Fraction aX(aTextRect.GetWidth()-1,aAnchor.GetWidth()-1); - Fraction aY(aTextRect.GetHeight()-1,aAnchor.GetHeight()-1); - ResizePoint(aTemporaryTextRelativePosition,Point(),aX,aY); + // search for TextHierarchyFieldPrimitive2D which contains the needed information + // about a possible URLField + const drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D* pTextHierarchyFieldPrimitive2D = nullptr; + + for (const drawinglayer::primitive2d::Primitive2DReference& xReference : aHitContainer) + { + if (xReference.is()) + { + // try to cast to drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D implementation + pTextHierarchyFieldPrimitive2D = dynamic_cast<const drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D*>(xReference.get()); + + if (pTextHierarchyFieldPrimitive2D) + { + break; + } + } } - // account for rotation - const GeoStat& rGeo=pTextObj->GetGeoStat(); - if (rGeo.nRotationAngle!=0) RotatePoint(aTemporaryTextRelativePosition,Point(),-rGeo.nSin,rGeo.nCos); // -sin for Unrotate - // we currently don't account for ticker text - if(mpActualOutDev && mpActualOutDev->GetOutDevType() == OUTDEV_WINDOW) + + if (nullptr != pTextHierarchyFieldPrimitive2D) { - OutlinerView aOLV(pOutliner, static_cast<vcl::Window*>(mpActualOutDev.get())); - const EditView& aEV=aOLV.GetEditView(); - const SvxFieldItem* pItem=aEV.GetField(aTemporaryTextRelativePosition); - if (pItem!=nullptr) { - const SvxFieldData* pFld=pItem->GetField(); - const SvxURLField* pURL=dynamic_cast<const SvxURLField*>( pFld ); - if (pURL!=nullptr) { - eHit=SdrHitKind::UrlField; - rVEvt.pURLField=pURL; + if (drawinglayer::primitive2d::FieldType::FIELD_TYPE_URL == pTextHierarchyFieldPrimitive2D->getType()) + { + // problem with the old code is that a *pointer* to an instance of + // SvxURLField is set in the Event which is per se not good since that + // data comes from a temporary EditEngine's data and could vanish any + // moment. Have to replace for now with a static instance that gets + // filled/initialized from the original data held in the TextHierarchyField- + // Primitive2D (see impTextBreakupHandler::impCheckFieldPrimitive). + // Unfortunately things like 'TargetFrame' are still used in Calc, so this + // can currently not get replaced. For the future the Name/Value vector or + // the TextHierarchyFieldPrimitive2D itself should/will be used for handling + // that data + static SvxURLField aSvxURLField; + + aSvxURLField.SetURL(pTextHierarchyFieldPrimitive2D->getValue("URL")); + aSvxURLField.SetRepresentation(pTextHierarchyFieldPrimitive2D->getValue("Representation")); + aSvxURLField.SetTargetFrame(pTextHierarchyFieldPrimitive2D->getValue("TargetFrame")); + const OUString aFormat(pTextHierarchyFieldPrimitive2D->getValue("SvxURLFormat")); + + if (!aFormat.isEmpty()) + { + aSvxURLField.SetFormat(static_cast<SvxURLFormat>(aFormat.toInt32())); } + + // set HitKind and pointer to local static instance in the Event + // to comply to old stuff + eHit = SdrHitKind::UrlField; + rVEvt.pURLField = &aSvxURLField; } } } |