diff --git a/include/svx/diagram/IDiagramHelper.hxx b/include/svx/diagram/IDiagramHelper.hxx index a6d23b1ab63c..d36e5eb861d5 100644 --- a/include/svx/diagram/IDiagramHelper.hxx +++ b/include/svx/diagram/IDiagramHelper.hxx @@ -83,8 +83,13 @@ private: // and the layouting stuff bool mbSelfCreated; + // set to true if the model contained here for the Diagram was + // modified + bool mbModified; // false + protected: - void anchorToSdrObjGroup(SdrObjGroup& rTarget); + // remember associated SdrObjGroup + SdrObjGroup* mpAssociatedSdrObjGroup; public: IDiagramHelper(bool bSelfCreated); @@ -118,6 +123,18 @@ public: bool isSelfCreated() const { return mbSelfCreated; } void setSelfCreated() { mbSelfCreated = true; } + // connect/disconnect to/from Group + void connectToSdrObjGroup(SdrObjGroup& rTarget); + void disconnectFromSdrObjGroup(); + + // modified state of this local model. Needs to be set to know + // how to do correct export + bool isModified() const { return mbModified; } + void setModified() { mbModified = true; } + + // react on changes to objects identified by DiagramDataModelID, returns true if a change was done + virtual void TextInformationChange(const OUString& rDiagramDataModelID, SdrOutliner& rOutl) = 0; + static void AddAdditionalVisualization(const SdrObjGroup& rTarget, SdrHdlList& rHdlList); }; diff --git a/include/svx/diagram/datamodel.hxx b/include/svx/diagram/datamodel.hxx index 2b62c0b75ec2..86d083f2c953 100644 --- a/include/svx/diagram/datamodel.hxx +++ b/include/svx/diagram/datamodel.hxx @@ -34,6 +34,8 @@ #include #include +class Outliner; + namespace svx::diagram { enum TypeConstant { @@ -230,6 +232,9 @@ public: DiagramDataStatePtr extractDiagramDataState() const; void applyDiagramDataState(const DiagramDataStatePtr& rState); + // react on changes to objects identified by DiagramDataModelID, returns true if a change was done + bool TextInformationChange(const OUString& rDiagramDataModelID, Outliner& rOutl); + protected: // helpers void getChildrenString(OUStringBuffer& rBuf, const Point* pPoint, sal_Int32 nLevel) const; diff --git a/include/svx/svdobj.hxx b/include/svx/svdobj.hxx index 7917d988cd20..9a788d4eee0c 100644 --- a/include/svx/svdobj.hxx +++ b/include/svx/svdobj.hxx @@ -227,8 +227,11 @@ class SVXCORE_DLLPUBLIC SdrObject : public SfxListener, public cppu::OWeakObject { public: // Basic DiagramHelper support + virtual bool isDiagram() const; virtual const std::shared_ptr< svx::diagram::IDiagramHelper >& getDiagramHelper() const; - bool isDiagram() const { return bool(getDiagramHelper()); } + const std::shared_ptr< svx::diagram::IDiagramHelper >& getDiagramHelperFromDiagramOrMember() const; + void setDiagramDataModelID(const OUString& rID) { msDiagramDataModelID = rID; } + const OUString& getDiagramDataModelID() const { return msDiagramDataModelID; } private: friend class SdrObjListIter; @@ -984,9 +987,13 @@ private: // HACK: Do not automatically insert newly created object into a page. // The user needs to do it manually later. bool mbDoNotInsertIntoPageAutomatically; + // Hyperlink for the whole shape OUString msHyperlink; + // if this object is a representation of Diagram Sub-Data, hold the DataModelID + OUString msDiagramDataModelID; + // only for internal use! SvxShape* getSvxShape(); diff --git a/include/svx/svdogrp.hxx b/include/svx/svdogrp.hxx index 32a7750e90d4..5949f3d4b4b0 100644 --- a/include/svx/svdogrp.hxx +++ b/include/svx/svdogrp.hxx @@ -29,6 +29,7 @@ class SVXCORE_DLLPUBLIC SdrObjGroup final : public SdrObject, public SdrObjList { public: // Basic DiagramHelper support + virtual bool isDiagram() const override; virtual const std::shared_ptr< svx::diagram::IDiagramHelper >& getDiagramHelper() const override; private: @@ -66,7 +67,6 @@ public: virtual void handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage) override; virtual SdrObjList* GetSubList() const override; - virtual void SetGrabBagItem(const css::uno::Any& rVal) override; virtual const tools::Rectangle& GetCurrentBoundRect() const override; virtual const tools::Rectangle& GetSnapRect() const override; diff --git a/include/svx/svxids.hrc b/include/svx/svxids.hrc index 4563591571aa..a93ad0c3bed9 100644 --- a/include/svx/svxids.hrc +++ b/include/svx/svxids.hrc @@ -385,6 +385,7 @@ class XFillGradientItem; // CAUTION! Range <250 .. 250> used by EditEngine (!) +#define SID_DIAGRAM_TO_GROUP ( SID_SVX_START + 252 ) #define SID_DRAW_TEXT ( SID_SVX_START + 253 ) #define SID_DRAW_CAPTION ( SID_SVX_START + 254 ) #define SID_DRAW_SELECT ( SID_SVX_START + 255 ) diff --git a/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu index 88718fecb8f5..e23423904154 100644 --- a/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu +++ b/officecfg/registry/data/org/openoffice/Office/UI/GenericCommands.xcu @@ -7915,6 +7915,11 @@ bit 3 (0x8): #define UICOMMANDDESCRIPTION_PROPERTIES_TOGGLEBUTTON 8 Regenerate Diagram + + + Convert Diagram to Group Object + + Edit Diagram diff --git a/oox/source/drawingml/diagram/diagramhelper.cxx b/oox/source/drawingml/diagram/diagramhelper.cxx index cfd0b45b790f..d19e1a5e0bd7 100644 --- a/oox/source/drawingml/diagram/diagramhelper.cxx +++ b/oox/source/drawingml/diagram/diagramhelper.cxx @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -233,6 +234,26 @@ void AdvancedDiagramHelper::applyDiagramDataState(const svx::diagram::DiagramDat mpDiagramPtr->getData()->applyDiagramDataState(rState); } +void AdvancedDiagramHelper::TextInformationChange(const OUString& rDiagramDataModelID, SdrOutliner& rOutl) +{ + if(!mpDiagramPtr) + { + return; + } + + // try text change for model part in DiagramData + const bool bChanged(mpDiagramPtr->getData()->TextInformationChange(rDiagramDataModelID, rOutl)); + + if(bChanged && nullptr != mpAssociatedSdrObjGroup) + { + // if change was done, reset GrabBagItem to delete buffered DiagramData which is no longer valid + mpAssociatedSdrObjGroup->SetGrabBagItem(uno::Any(uno::Sequence())); + + // also set self to modified to get correct exports + setModified(); + } +} + void AdvancedDiagramHelper::doAnchor(SdrObjGroup& rTarget, ::oox::drawingml::Shape& rRootShape) { if(!mpDiagramPtr) @@ -247,7 +268,8 @@ void AdvancedDiagramHelper::doAnchor(SdrObjGroup& rTarget, ::oox::drawingml::Sha // secure that data at the Diagram ModelData by copying. mpDiagramPtr->getData()->secureDataFromShapeToModelAfterDiagramImport(rRootShape); - anchorToSdrObjGroup(rTarget); + // initialize connection to GroupObject + connectToSdrObjGroup(rTarget); } const std::shared_ptr< ::oox::drawingml::Theme >& AdvancedDiagramHelper::getOrCreateThemePtr( diff --git a/oox/source/drawingml/diagram/diagramhelper.hxx b/oox/source/drawingml/diagram/diagramhelper.hxx index 2cb88f471b29..22915e7b87e2 100644 --- a/oox/source/drawingml/diagram/diagramhelper.hxx +++ b/oox/source/drawingml/diagram/diagramhelper.hxx @@ -82,6 +82,9 @@ public: void doAnchor(SdrObjGroup& rTarget, ::oox::drawingml::Shape& rRootShape); const std::shared_ptr< ::oox::drawingml::Theme >& getOrCreateThemePtr( const rtl::Reference< oox::shape::ShapeFilterBase>& rxFilter ) const; + + // react on changes to objects identified by DiagramDataModelID, returns true if a change was done + virtual void TextInformationChange(const OUString& rDiagramDataModelID, SdrOutliner& rOutl) override; }; } diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx index 4f2f9dc8d6a9..0d28032ab50e 100644 --- a/oox/source/drawingml/shape.cxx +++ b/oox/source/drawingml/shape.cxx @@ -1435,6 +1435,24 @@ Reference< XShape > const & Shape::createAndInsert( ActionLockGuard const alg(mxShape); + if (!getDiagramDataModelID().isEmpty()) + { + SdrObject* pShape(SdrObject::getSdrObjectFromXShape(mxShape)); + + if (nullptr != pShape) + { + // check if we have a DiagramHelper + std::shared_ptr< svx::diagram::IDiagramHelper > pIDiagramHelper( + pShape->getDiagramHelperFromDiagramOrMember()); + + if (pIDiagramHelper) + { + // only needed when DiagramHelper exists + pShape->setDiagramDataModelID(getDiagramDataModelID()); + } + } + } + // sj: removing default text of placeholder objects such as SlideNumberShape or HeaderShape if ( bClearText ) { diff --git a/oox/source/ppt/pptshapegroupcontext.cxx b/oox/source/ppt/pptshapegroupcontext.cxx index ef8934835bed..91684cf8d47b 100644 --- a/oox/source/ppt/pptshapegroupcontext.cxx +++ b/oox/source/ppt/pptshapegroupcontext.cxx @@ -112,7 +112,14 @@ ContextHandlerRef PPTShapeGroupContext::onCreateContext( sal_Int32 aElementToken { pShape->getFillProperties().moFillType = XML_noFill; } - pShape->setModelId(rAttribs.getStringDefaulted( XML_modelId )); + const OUString aModelID(rAttribs.getStringDefaulted( XML_modelId )); + pShape->setModelId(aModelID); + + // also set DataModelID to have these also available for the imported + // replacement visualization. This is key to allow changes to + // DiagramHelper model changes + pShape->setDiagramDataModelID(aModelID); + return new PPTShapeContext( *this, mpSlidePersistPtr, mpGroupShapePtr, pShape ); } case PPT_TOKEN( pic ): // CT_Picture diff --git a/sc/sdi/drawsh.sdi b/sc/sdi/drawsh.sdi index dc13528984e0..281ea24aab09 100644 --- a/sc/sdi/drawsh.sdi +++ b/sc/sdi/drawsh.sdi @@ -136,8 +136,9 @@ interface TableDraw SID_UNGROUP [ ExecMethod = ExecDrawFunc; StateMethod = GetDrawFuncState; ] SID_ENTER_GROUP [ ExecMethod = ExecDrawFunc; StateMethod = GetDrawFuncState; ] SID_LEAVE_GROUP [ ExecMethod = ExecDrawFunc; StateMethod = GetDrawFuncState; ] - SID_REGENERATE_DIAGRAM [ ExecMethod = ExecDrawFunc; StateMethod = GetDrawFuncState ] - SID_EDIT_DIAGRAM [ ExecMethod = ExecDrawFunc; StateMethod = GetDrawFuncState ] + SID_REGENERATE_DIAGRAM [ ExecMethod = ExecDrawFunc; StateMethod = GetDrawFuncState; ] + SID_DIAGRAM_TO_GROUP [ ExecMethod = ExecDrawFunc; StateMethod = GetDrawFuncState; ] + SID_EDIT_DIAGRAM [ ExecMethod = ExecDrawFunc; StateMethod = GetDrawFuncState; ] // !!! special SID_DELETE [ExecMethod = ExecDrawFunc ;StateMethod = GetDrawFuncState; ] diff --git a/sc/source/ui/drawfunc/drawsh2.cxx b/sc/source/ui/drawfunc/drawsh2.cxx index a82741dbb51f..9e8c009fcf74 100644 --- a/sc/source/ui/drawfunc/drawsh2.cxx +++ b/sc/source/ui/drawfunc/drawsh2.cxx @@ -284,6 +284,7 @@ void ScDrawShell::GetDrawFuncState( SfxItemSet& rSet ) // disable functions if (!pObj->isDiagram()) { rSet.DisableItem( SID_REGENERATE_DIAGRAM ); + rSet.DisableItem( SID_DIAGRAM_TO_GROUP ); rSet.DisableItem( SID_EDIT_DIAGRAM ); } } diff --git a/sc/source/ui/drawfunc/drawsh5.cxx b/sc/source/ui/drawfunc/drawsh5.cxx index 51235d7a0696..992e7b1b161c 100644 --- a/sc/source/ui/drawfunc/drawsh5.cxx +++ b/sc/source/ui/drawfunc/drawsh5.cxx @@ -276,6 +276,7 @@ void ScDrawShell::ExecDrawFunc( SfxRequest& rReq ) break; case SID_REGENERATE_DIAGRAM: + case SID_DIAGRAM_TO_GROUP: case SID_EDIT_DIAGRAM: { const SdrMarkList& rMarkList = pView->GetMarkedObjectList(); @@ -293,7 +294,7 @@ void ScDrawShell::ExecDrawFunc( SfxRequest& rReq ) pObj->getDiagramHelper()->reLayout(*static_cast(pObj)); pView->MarkObj(pObj, pView->GetSdrPageView()); } - else // SID_EDIT_DIAGRAM + else if (SID_EDIT_DIAGRAM == nSlotId) { VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); vcl::Window* pWin = rViewData.GetActiveWin(); @@ -307,6 +308,12 @@ void ScDrawShell::ExecDrawFunc( SfxRequest& rReq ) } ); } + else // SID_DIAGRAM_TO_GROUP + { + pView->UnmarkAll(); + pObj->getDiagramHelper()->disconnectFromSdrObjGroup(); + pView->MarkObj(pObj, pView->GetSdrPageView()); + } } } diff --git a/sd/qa/unit/export-tests-ooxml2.cxx b/sd/qa/unit/export-tests-ooxml2.cxx index d009c43cde0f..a9ed1af551b2 100644 --- a/sd/qa/unit/export-tests-ooxml2.cxx +++ b/sd/qa/unit/export-tests-ooxml2.cxx @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include @@ -1595,12 +1597,13 @@ CPPUNIT_TEST_FIXTURE(SdOOXMLExportTest2, testSmartartRotation2) createSdImpressDoc("pptx/smartart-rotation2.pptx"); // clear SmartArt data to check how group shapes with double-rotated children are exported, not smartart - // NOTE: Resetting the GrabBag data is a *very* indirect way to reset the SmartArt functionality. - // Since this worked before and there is not (yet?) a better way to do it using UNO API, I added - // code to support this for now - uno::Reference xShape(getShapeFromPage(0, 0)); - uno::Sequence aInteropGrabBag; - xShape->setPropertyValue(u"InteropGrabBag"_ustr, uno::Any(aInteropGrabBag)); + // NOTE: Now we have a slot (comphelper::dispatchCommand(u".uno:DiagramToGroup"_ustr, {})) and method + // at IDiagramHelper to do that, adapted removal of Diagram/SmartArt functionality + uno::Reference xPage(getPage(0)); + uno::Reference xShape(xPage->getByIndex(0), uno::UNO_QUERY); + SdrObjGroup* pSdrObjGroup + = dynamic_cast(SdrObject::getSdrObjectFromXShape(xShape)); + pSdrObjGroup->getDiagramHelper()->disconnectFromSdrObjGroup(); save(TestFilter::PPTX); diff --git a/sd/sdi/_drvwsh.sdi b/sd/sdi/_drvwsh.sdi index c574c2cf62ef..a87109cb8b9e 100644 --- a/sd/sdi/_drvwsh.sdi +++ b/sd/sdi/_drvwsh.sdi @@ -2928,6 +2928,11 @@ interface DrawView ExecMethod = ExecCtrl ; StateMethod = GetMenuState ; ] + SID_DIAGRAM_TO_GROUP + [ + ExecMethod = ExecCtrl ; + StateMethod = GetMenuState ; + ] SID_EDIT_DIAGRAM [ ExecMethod = ExecCtrl ; diff --git a/sd/source/filter/eppt/pptx-epptooxml.cxx b/sd/source/filter/eppt/pptx-epptooxml.cxx index 558a142e5d62..2964e0d2db25 100644 --- a/sd/source/filter/eppt/pptx-epptooxml.cxx +++ b/sd/source/filter/eppt/pptx-epptooxml.cxx @@ -88,6 +88,7 @@ #include #include #include +#include #include #include #include @@ -2348,7 +2349,12 @@ void PowerPointExport::WriteShapeTree(const FSHelperPtr& pFS, PageType ePageType { SAL_INFO("sd.eppt", "mType: " << mType); const SdrObjGroup* pDiagramCandidate(dynamic_cast(SdrObject::getSdrObjectFromXShape(mXShape))); - const bool bIsDiagram(nullptr != pDiagramCandidate && pDiagramCandidate->isDiagram()); + bool bIsDiagram(nullptr != pDiagramCandidate && pDiagramCandidate->isDiagram()); + + // check if it was modified. For now, since we have no ppt export for Diagram, + // do not export as Diagram, that would be empty if the GrabBag was deleted + if (bIsDiagram && pDiagramCandidate->getDiagramHelper()->isModified()) + bIsDiagram = false; if (bIsDiagram) WriteDiagram(pFS, aDML, mXShape, mnDiagramId++); diff --git a/sd/source/ui/view/drviews3.cxx b/sd/source/ui/view/drviews3.cxx index ae6c27645807..169c8886cdbe 100644 --- a/sd/source/ui/view/drviews3.cxx +++ b/sd/source/ui/view/drviews3.cxx @@ -488,6 +488,7 @@ void DrawViewShell::ExecCtrl(SfxRequest& rReq) break; case SID_REGENERATE_DIAGRAM: + case SID_DIAGRAM_TO_GROUP: case SID_EDIT_DIAGRAM: { if (1 == rMarkList.GetMarkCount()) @@ -497,13 +498,13 @@ void DrawViewShell::ExecCtrl(SfxRequest& rReq) // Support advanced DiagramHelper if(nullptr != pObj && pObj->isDiagram()) { - if(SID_REGENERATE_DIAGRAM == nSlot) + if (SID_REGENERATE_DIAGRAM == nSlot) { mpDrawView->UnmarkAll(); pObj->getDiagramHelper()->reLayout(*static_cast(pObj)); mpDrawView->MarkObj(pObj, mpDrawView->GetSdrPageView()); } - else // SID_EDIT_DIAGRAM + else if (SID_EDIT_DIAGRAM == nSlot) { VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); VclPtr pDlg = pFact->CreateDiagramDialog( @@ -516,6 +517,12 @@ void DrawViewShell::ExecCtrl(SfxRequest& rReq) } ); } + else // SID_DIAGRAM_TO_GROUP + { + mpDrawView->UnmarkAll(); + pObj->getDiagramHelper()->disconnectFromSdrObjGroup(); + mpDrawView->MarkObj(pObj, mpDrawView->GetSdrPageView()); + } } } diff --git a/sd/source/ui/view/drviewsj.cxx b/sd/source/ui/view/drviewsj.cxx index 1cfa0f16bc5f..016755683e9e 100644 --- a/sd/source/ui/view/drviewsj.cxx +++ b/sd/source/ui/view/drviewsj.cxx @@ -158,6 +158,7 @@ void DrawViewShell::GetMenuStateSel( SfxItemSet &rSet ) if(!pSdrObjGroup || !pSdrObjGroup->isDiagram()) { rSet.DisableItem( SID_REGENERATE_DIAGRAM ); + rSet.DisableItem( SID_DIAGRAM_TO_GROUP ); rSet.DisableItem( SID_EDIT_DIAGRAM ); } diff --git a/svx/qa/unit/data/tdf132368.pptx b/svx/qa/unit/data/tdf132368.pptx new file mode 100644 index 000000000000..3941d37661e5 Binary files /dev/null and b/svx/qa/unit/data/tdf132368.pptx differ diff --git a/svx/qa/unit/svdraw.cxx b/svx/qa/unit/svdraw.cxx index b3b8ce14e227..b1f26780aea6 100644 --- a/svx/qa/unit/svdraw.cxx +++ b/svx/qa/unit/svdraw.cxx @@ -237,46 +237,49 @@ CPPUNIT_TEST_FIXTURE(SvdrawTest, testHandlePathObjScale) CPPUNIT_TEST_FIXTURE(SvdrawTest, testTextEditEmptyGrabBag) { - // Given a document with a groupshape, which has 2 children. - loadFromURL(u"private:factory/sdraw"_ustr); - uno::Reference xFactory(mxComponent, uno::UNO_QUERY); - uno::Reference xRect1( - xFactory->createInstance(u"com.sun.star.drawing.RectangleShape"_ustr), uno::UNO_QUERY); - xRect1->setPosition(awt::Point(1000, 1000)); - xRect1->setSize(awt::Size(10000, 10000)); - uno::Reference xRect2( - xFactory->createInstance(u"com.sun.star.drawing.RectangleShape"_ustr), uno::UNO_QUERY); - xRect2->setPosition(awt::Point(1000, 1000)); - xRect2->setSize(awt::Size(10000, 10000)); - uno::Reference xGroup( - xFactory->createInstance(u"com.sun.star.drawing.GroupShape"_ustr), uno::UNO_QUERY); + // Adapted this test to work with a *real* SmartArt/Diagram (SA). The former + // test created a 'fake' one and checked if on TextEdit The GrabBag gets deleted. + // The updated SA text edit *tries* to keep the SA Data (in IDiagramHelper + // attached to SdrObjGroup). It clears the GrabBag, but only if a 'real' SA + // exists. + // Thus I added a bugdoc for that task which contains a 'real' SA to test + // if GrabBag gets cleared on change of the SA model data. + + // load document + loadFromFile(u"tdf132368.pptx"); + + // get DrawPage uno::Reference xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); uno::Reference xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), uno::UNO_QUERY); - uno::Reference xGroupShape(xGroup, uno::UNO_QUERY); - xDrawPage->add(xGroupShape); - xGroup->add(xRect1); - xGroup->add(xRect2); - uno::Reference xRect2Text(xRect2, uno::UNO_QUERY); - xRect2Text->setString(u"x"_ustr); - uno::Sequence aGrabBag = { - comphelper::makePropertyValue(u"OOXLayout"_ustr, true), - }; - uno::Reference xGroupProps(xGroup, uno::UNO_QUERY); - xGroupProps->setPropertyValue(u"InteropGrabBag"_ustr, uno::Any(aGrabBag)); - // When editing the shape text of the 2nd rectangle (insert a char at the start). + // get 1st object, this is the SA. Get as GroupObject + uno::Reference xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY); + uno::Reference xGroupShape(xShape, uno::UNO_QUERY); + + // get the GrabBag. After import is *has* to be set, check that + uno::Sequence aGrabBag; + uno::Reference xGroupProps(xGroupShape, uno::UNO_QUERY); + xGroupProps->getPropertyValue(u"InteropGrabBag"_ustr) >>= aGrabBag; + CPPUNIT_ASSERT(aGrabBag.hasElements()); + + // get the 1st text shape (containing 'A'). There is a BGShape and an Arrow + // in indices before + uno::Reference xShapeA(xGroupShape->getByIndex(2), uno::UNO_QUERY); + + // TextEdit: insert a char at the start SfxViewShell* pViewShell = SfxViewShell::Current(); CPPUNIT_ASSERT(pViewShell); SdrView* pSdrView = pViewShell->GetDrawView(); - SdrObject* pObject = SdrObject::getSdrObjectFromXShape(xRect2); + SdrObject* pObject = SdrObject::getSdrObjectFromXShape(xShapeA); pSdrView->SdrBeginTextEdit(pObject); EditView& rEditView = pSdrView->GetTextEditOutlinerView()->GetEditView(); - rEditView.InsertText(u"y"_ustr); + rEditView.InsertText(u"X"_ustr); pSdrView->SdrEndTextEdit(); // Then make sure that grab-bag is empty to avoid losing the new text. xGroupProps->getPropertyValue(u"InteropGrabBag"_ustr) >>= aGrabBag; + // Without the accompanying fix in place, this test would have failed with: // assertion failed // - Expression: !aGrabBag.hasElements() diff --git a/svx/sdi/svx.sdi b/svx/sdi/svx.sdi index 8fb8cf205f10..cd0a9ab59ac1 100644 --- a/svx/sdi/svx.sdi +++ b/svx/sdi/svx.sdi @@ -2660,6 +2660,23 @@ SfxVoidItem RegenerateDiagram SID_REGENERATE_DIAGRAM GroupId = SfxGroupId::Modify; ] +SfxVoidItem DiagramToGroup SID_DIAGRAM_TO_GROUP +() +[ + AutoUpdate = FALSE, + FastCall = FALSE, + ReadOnlyDoc = FALSE, + Toggle = FALSE, + Container = FALSE, + RecordAbsolute = FALSE, + RecordPerSet; + + AccelConfig = TRUE, + MenuConfig = TRUE, + ToolBoxConfig = TRUE, + GroupId = SfxGroupId::Modify; +] + SfxVoidItem EditDiagram SID_EDIT_DIAGRAM () [ diff --git a/svx/source/diagram/IDiagramHelper.cxx b/svx/source/diagram/IDiagramHelper.cxx index 5f17433a6181..5ccffe123507 100644 --- a/svx/source/diagram/IDiagramHelper.cxx +++ b/svx/source/diagram/IDiagramHelper.cxx @@ -39,6 +39,8 @@ #include #include +using namespace ::com::sun::star; + namespace { // helper to create the geometry for a rounded polygon, maybe @@ -408,13 +410,35 @@ IDiagramHelper::IDiagramHelper(bool bSelfCreated) , mbUseDiagramModelData(true) , mbForceThemePtrRecreation(false) , mbSelfCreated(bSelfCreated) +, mbModified(false) +, mpAssociatedSdrObjGroup(nullptr) { } IDiagramHelper::~IDiagramHelper() {} -void IDiagramHelper::anchorToSdrObjGroup(SdrObjGroup& rTarget) +void IDiagramHelper::disconnectFromSdrObjGroup() { + if (nullptr != mpAssociatedSdrObjGroup) + { + // if change was done, reset GrabBagItem to delete buffered DiagramData which is no longer valid + mpAssociatedSdrObjGroup->SetGrabBagItem(uno::Any(uno::Sequence())); + mpAssociatedSdrObjGroup->mp_DiagramHelper.reset(); + mpAssociatedSdrObjGroup = nullptr; + } +} + +void IDiagramHelper::connectToSdrObjGroup(SdrObjGroup& rTarget) +{ + if (mpAssociatedSdrObjGroup == &rTarget && rTarget.mp_DiagramHelper.get() == this) + // connection already established + return; + + // ensure unconnect if already connected + disconnectFromSdrObjGroup(); + + // connect to target + mpAssociatedSdrObjGroup = &rTarget; rTarget.mp_DiagramHelper.reset(this); } diff --git a/svx/source/diagram/datamodel.cxx b/svx/source/diagram/datamodel.cxx index 2dc9e345a825..02fea52cf493 100644 --- a/svx/source/diagram/datamodel.cxx +++ b/svx/source/diagram/datamodel.cxx @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -493,6 +494,52 @@ void DiagramData::buildDiagramDataModel(bool /*bClearOoxShapes*/) #endif } +bool DiagramData::TextInformationChange(const OUString& rDiagramDataModelID, Outliner& rOutl) +{ + // try to get the Point fo rthe associated ID + const auto pDataNode = maPointNameMap.find(rDiagramDataModelID); + if (pDataNode == maPointNameMap.end()) + return false; + + // use PresentationAssociationId to get to the text containing Point + const OUString& rPresentationAssociationId(pDataNode->second->msPresentationAssociationId); + if (rPresentationAssociationId.isEmpty()) + return false; + + // try to get the text-associated Point + const auto pTextNode = maPointNameMap.find(rPresentationAssociationId); + if (pTextNode == maPointNameMap.end()) + return false; + + // check if it has a text node - it should + if (!pTextNode->second->msTextBody) + return false; + + // access TextBody + TextBodyPtr pTextBody(pTextNode->second->msTextBody); + + // now for outliner/source: Do we have data at all? + if(0 == rOutl.GetParagraphCount()) + return false; + + // if yes, use 1st paragraph (for now) + const Paragraph* pPara(rOutl.GetParagraph(0)); + if (nullptr == pPara) + return false; + + // extract 1st para as text + const OUString aCurrentText(rOutl.GetText(pPara)); + + // check if text differs at all + if (aCurrentText == pTextBody->msText) + return false; + + // do change and return true (change was done) + // NOTE: for now only rough text change, attributes are missing and will need to be added + pTextBody->msText = aCurrentText; + return true; +} + } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/svdraw/svdoashp.cxx b/svx/source/svdraw/svdoashp.cxx index 4c4b94abfe26..44d1e6ec4ff3 100644 --- a/svx/source/svdraw/svdoashp.cxx +++ b/svx/source/svdraw/svdoashp.cxx @@ -76,6 +76,7 @@ #include #include #include +#include #include #include #include @@ -2608,8 +2609,20 @@ void SdrObjCustomShape::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, tools if (pPaperMax!=nullptr) *pPaperMax=aPaperMax; if (pViewInit!=nullptr) *pViewInit=aViewInit; } + void SdrObjCustomShape::EndTextEdit( SdrOutliner& rOutl ) { + if (!getDiagramDataModelID().isEmpty()) + { + std::shared_ptr< svx::diagram::IDiagramHelper > pIDiagramHelper(getDiagramHelperFromDiagramOrMember()); + + if (pIDiagramHelper) + { + // try to do the needed changes at the associated DiagramData model + pIDiagramHelper->TextInformationChange(getDiagramDataModelID(), rOutl); + } + } + SdrTextObj::EndTextEdit( rOutl ); InvalidateRenderGeometry(); } diff --git a/svx/source/svdraw/svdobj.cxx b/svx/source/svdraw/svdobj.cxx index 66c35a1086da..898dae7d6228 100644 --- a/svx/source/svdraw/svdobj.cxx +++ b/svx/source/svdraw/svdobj.cxx @@ -201,12 +201,31 @@ struct SdrObject::Impl meRelativeHeightRelation(text::RelOrientation::PAGE_FRAME) {} }; +bool SdrObject::isDiagram() const +{ + return false; +} + const std::shared_ptr< svx::diagram::IDiagramHelper >& SdrObject::getDiagramHelper() const { static std::shared_ptr< svx::diagram::IDiagramHelper > aEmpty; return aEmpty; } +const std::shared_ptr< svx::diagram::IDiagramHelper >& SdrObject::getDiagramHelperFromDiagramOrMember() const +{ + SdrObject* pCurrent(const_cast(this)); + + while (pCurrent) + { + if (pCurrent->isDiagram()) + return pCurrent->getDiagramHelper(); + pCurrent = pCurrent->getParentSdrObjectFromSdrObject(); + } + + return getDiagramHelper(); +} + // BaseProperties section sdr::properties::BaseProperties& SdrObject::GetProperties() const @@ -347,6 +366,8 @@ SdrObject::SdrObject(SdrModel& rSdrModel) , mnLayerID(0) , mpSvxShape( nullptr ) , mbDoNotInsertIntoPageAutomatically(false) + , msHyperlink() + , msDiagramDataModelID() { m_bVirtObj =false; m_bSnapRectDirty =true; @@ -383,6 +404,8 @@ SdrObject::SdrObject(SdrModel& rSdrModel, SdrObject const & rSource) , mnLayerID(0) , mpSvxShape( nullptr ) , mbDoNotInsertIntoPageAutomatically(false) + , msHyperlink() + , msDiagramDataModelID() { m_bVirtObj =false; m_bSnapRectDirty =true; @@ -1855,19 +1878,6 @@ void SdrObject::SetOutlinerParaObject(std::optional pTextObj if (GetCurrentBoundRect()!=aBoundRect0) { SendUserCall(SdrUserCallType::Resize,aBoundRect0); } - - if (!getSdrModelFromSdrObject().IsUndoEnabled()) - return; - - // Don't do this during import. - if (SdrObject* pTopGroupObj = getParentSdrObjectFromSdrObject()) - { - while (SdrObject* pParent = pTopGroupObj->getParentSdrObjectFromSdrObject()) - pTopGroupObj = pParent; - // A shape was modified, which is in a group shape. Empty the group shape's grab-bag, - // which potentially contains the old text of the shapes in case of diagrams. - pTopGroupObj->SetGrabBagItem(uno::Any(uno::Sequence())); - } } void SdrObject::NbcSetOutlinerParaObject(std::optional /*pTextObject*/, bool /*bAdjustTextFrameWidthAndHeight = true*/) diff --git a/svx/source/svdraw/svdogrp.cxx b/svx/source/svdraw/svdogrp.cxx index 849a0f106053..6342efc796b8 100644 --- a/svx/source/svdraw/svdogrp.cxx +++ b/svx/source/svdraw/svdogrp.cxx @@ -34,6 +34,11 @@ #include #include +bool SdrObjGroup::isDiagram() const +{ + return bool(mp_DiagramHelper); +} + const std::shared_ptr< svx::diagram::IDiagramHelper >& SdrObjGroup::getDiagramHelper() const { return mp_DiagramHelper; @@ -204,39 +209,6 @@ SdrObjList* SdrObjGroup::GetSubList() const { return const_cast< SdrObjGroup* >(this); } - -static bool containsOOXData(const css::uno::Any& rVal) -{ - const css::uno::Sequence propList(rVal.get< css::uno::Sequence >()); - for (const auto& rProp : propList) - { - if(rProp.Name.startsWith("OOX")) - { - return true; - } - } - - return false; -} - -void SdrObjGroup::SetGrabBagItem(const css::uno::Any& rVal) -{ - // detect if the intention is to disable Diagram functionality - if(isDiagram() && !containsOOXData(rVal)) - { - css::uno::Any aOld; - GetGrabBagItem(aOld); - - if(containsOOXData(aOld)) - { - mp_DiagramHelper.reset(); - } - } - - // call parent - SdrObject::SetGrabBagItem(rVal); -} - const tools::Rectangle& SdrObjGroup::GetCurrentBoundRect() const { // has to contain the bounding rectangle diff --git a/sw/sdi/_drwbase.sdi b/sw/sdi/_drwbase.sdi index 4fa17e1f96eb..7517d5556e80 100644 --- a/sw/sdi/_drwbase.sdi +++ b/sw/sdi/_drwbase.sdi @@ -67,6 +67,13 @@ interface BaseTextDrawBase StateMethod = GetState ; ] + SID_DIAGRAM_TO_GROUP + [ + AutoUpdate = TRUE , + ExecMethod = Execute ; + StateMethod = GetState ; + ] + SID_EDIT_DIAGRAM [ AutoUpdate = TRUE , diff --git a/sw/source/uibase/shells/drwbassh.cxx b/sw/source/uibase/shells/drwbassh.cxx index 85eeb0c70072..46a6e7dac306 100644 --- a/sw/source/uibase/shells/drwbassh.cxx +++ b/sw/source/uibase/shells/drwbassh.cxx @@ -460,6 +460,7 @@ void SwDrawBaseShell::Execute(SfxRequest& rReq) break; case SID_REGENERATE_DIAGRAM: + case SID_DIAGRAM_TO_GROUP: case SID_EDIT_DIAGRAM: { const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList(); @@ -471,13 +472,13 @@ void SwDrawBaseShell::Execute(SfxRequest& rReq) // Support advanced DiagramHelper if(nullptr != pObj && pObj->isDiagram()) { - if(SID_REGENERATE_DIAGRAM == nSlotId) + if (SID_REGENERATE_DIAGRAM == nSlotId) { pSdrView->UnmarkAll(); pObj->getDiagramHelper()->reLayout(*static_cast(pObj)); pSdrView->MarkObj(pObj, pSdrView->GetSdrPageView()); } - else // SID_EDIT_DIAGRAM + else if(SID_EDIT_DIAGRAM == nSlotId) { VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create(); VclPtr pDlg = pFact->CreateDiagramDialog( @@ -490,6 +491,12 @@ void SwDrawBaseShell::Execute(SfxRequest& rReq) } ); } + else // SID_DIAGRAM_TO_GROUP + { + pSdrView->UnmarkAll(); + pObj->getDiagramHelper()->disconnectFromSdrObjGroup(); + pSdrView->MarkObj(pObj, pSdrView->GetSdrPageView()); + } } } }