SmartArt: Add posssibility to edit (simple) text

A loaded SmartArt allows to start TextEdit when one of the
included nodes gets klicked. TextEdit seems to work, but the
object degrades from a SmartArt to a GroupObject with content.

I try to add the preconditions here which are needed to be
able to do change at a SmartArt in the future. Basic problem
is that the ModelData for SmartArt are 'attached' to the
GroupObject that is used for representation, but no ways
exist to support edit/change and promote that to that
seperated model.

One of the main hindrances is that the needed IDs that
create the associations between that model and the Shapes
is missing, added that. This needs to be added for two
scenarios (what makes it complicated):
- loaded replacement visualization
- re-created SmartArt (add/rmove used)
To test this I added a simple text edit that does a first
change at that SmartArt model data. For now just simple
text, of course TextAttributes need to follow, as do
changes when Attributes get changed (Line/Fill/style/...)

Thus it's a 1st step and needed quite some experimenting.
As long as this is not further progressed (which I try to
make happen) the default will stay to have SmartArt as
GroupObject with content - as it is today.

Unified connect/disconnect, added slot and commands for
disconnect, adapted test to use that.

Needed to adapt UnitTest testTextEditEmptyGrabBag, it needs
to work with a *real* SmartArt/Diagram. The former test
created a 'fake' one and checked if on TextEdit the GrabBag
gets deleted.
The updated SmartArt text edit *tries* to keep the Data (in
IDiagramHelper attached to SdrObjGroup). It clears the
GrabBag, but only if a 'real' SmartArt exists.
Thus I added a bugdoc for that task which contains a 'real'
SmartArt to test if GrabBag gets cleared on change of the
model data.

Also added a modified state to the SmartArt model data
(which is in IDiagramHelper). This is needed to decide
what shall be done at export time. As long as we have
no SmartArt model data export, the fallback to conversion
to SdrObjGroup has to be used (as before).

Change-Id: Ie6ef3f3a8bbc5da99984d85f79f89e5df308e3c9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/195097
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
This commit is contained in:
Armin Le Grand (collabora)
2025-12-10 18:19:10 +01:00
committed by Armin Le Grand
parent ea37a0ab8f
commit 3ad22de97d
28 changed files with 309 additions and 93 deletions
+18 -1
View File
@@ -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);
};
+5
View File
@@ -34,6 +34,8 @@
#include <com/sun/star/drawing/XShape.hpp>
#include <oox/token/tokens.hxx>
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;
+8 -1
View File
@@ -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();
+1 -1
View File
@@ -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;
+1
View File
@@ -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 )
@@ -7915,6 +7915,11 @@ bit 3 (0x8): #define UICOMMANDDESCRIPTION_PROPERTIES_TOGGLEBUTTON 8
<value xml:lang="en-US">Regenerate Diagram</value>
</prop>
</node>
<node oor:name=".uno:DiagramToGroup" oor:op="replace">
<prop oor:name="Label" oor:type="xs:string">
<value xml:lang="en-US">Convert Diagram to Group Object</value>
</prop>
</node>
<node oor:name=".uno:EditDiagram" oor:op="replace">
<prop oor:name="Label" oor:type="xs:string">
<value xml:lang="en-US">Edit Diagram</value>
+23 -1
View File
@@ -25,6 +25,7 @@
#include <oox/ppt/pptimport.hxx>
#include <drawingml/fillproperties.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdoutl.hxx>
#include <comphelper/processfactory.hxx>
#include <oox/drawingml/themefragmenthandler.hxx>
#include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
@@ -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<beans::PropertyValue>()));
// 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(
@@ -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;
};
}
+18
View File
@@ -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 )
{
+8 -1
View File
@@ -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
+3 -2
View File
@@ -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; ]
+1
View File
@@ -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 );
}
}
+8 -1
View File
@@ -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<SdrObjGroup*>(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());
}
}
}
+9 -6
View File
@@ -14,6 +14,8 @@
#include <svx/svdomedia.hxx>
#include <svx/svdotable.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdogrp.hxx>
#include <svx/diagram/IDiagramHelper.hxx>
#include <docmodel/uno/UnoGradientTools.hxx>
#include <com/sun/star/animations/TransitionType.hpp>
@@ -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<beans::XPropertySet> xShape(getShapeFromPage(0, 0));
uno::Sequence<beans::PropertyValue> 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<drawing::XDrawPage> xPage(getPage(0));
uno::Reference<drawing::XShape> xShape(xPage->getByIndex(0), uno::UNO_QUERY);
SdrObjGroup* pSdrObjGroup
= dynamic_cast<SdrObjGroup*>(SdrObject::getSdrObjectFromXShape(xShape));
pSdrObjGroup->getDiagramHelper()->disconnectFromSdrObjGroup();
save(TestFilter::PPTX);
+5
View File
@@ -2928,6 +2928,11 @@ interface DrawView
ExecMethod = ExecCtrl ;
StateMethod = GetMenuState ;
]
SID_DIAGRAM_TO_GROUP
[
ExecMethod = ExecCtrl ;
StateMethod = GetMenuState ;
]
SID_EDIT_DIAGRAM
[
ExecMethod = ExecCtrl ;
+7 -1
View File
@@ -88,6 +88,7 @@
#include <svx/unoapi.hxx>
#include <svx/svdogrp.hxx>
#include <svx/ColorSets.hxx>
#include <svx/diagram/IDiagramHelper.hxx>
#include <sdmod.hxx>
#include <sdpage.hxx>
#include <unomodel.hxx>
@@ -2348,7 +2349,12 @@ void PowerPointExport::WriteShapeTree(const FSHelperPtr& pFS, PageType ePageType
{
SAL_INFO("sd.eppt", "mType: " << mType);
const SdrObjGroup* pDiagramCandidate(dynamic_cast<const SdrObjGroup*>(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++);
+9 -2
View File
@@ -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<SdrObjGroup*>(pObj));
mpDrawView->MarkObj(pObj, mpDrawView->GetSdrPageView());
}
else // SID_EDIT_DIAGRAM
else if (SID_EDIT_DIAGRAM == nSlot)
{
VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create();
VclPtr<VclAbstractDialog> 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());
}
}
}
+1
View File
@@ -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 );
}
Binary file not shown.
+30 -27
View File
@@ -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<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XShape> 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<drawing::XShape> 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<drawing::XShapes> 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<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0),
uno::UNO_QUERY);
uno::Reference<drawing::XShape> xGroupShape(xGroup, uno::UNO_QUERY);
xDrawPage->add(xGroupShape);
xGroup->add(xRect1);
xGroup->add(xRect2);
uno::Reference<text::XTextRange> xRect2Text(xRect2, uno::UNO_QUERY);
xRect2Text->setString(u"x"_ustr);
uno::Sequence<beans::PropertyValue> aGrabBag = {
comphelper::makePropertyValue(u"OOXLayout"_ustr, true),
};
uno::Reference<beans::XPropertySet> 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<drawing::XShape> xShape(xDrawPage->getByIndex(0), uno::UNO_QUERY);
uno::Reference<drawing::XShapes> xGroupShape(xShape, uno::UNO_QUERY);
// get the GrabBag. After import is *has* to be set, check that
uno::Sequence<beans::PropertyValue> aGrabBag;
uno::Reference<beans::XPropertySet> 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<drawing::XShape> 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()
+17
View File
@@ -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
()
[
+25 -1
View File
@@ -39,6 +39,8 @@
#include <svx/strings.hrc>
#include <svx/dialmgr.hxx>
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<beans::PropertyValue>()));
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);
}
+47
View File
@@ -22,6 +22,7 @@
#include <fstream>
#include <svx/diagram/datamodel.hxx>
#include <svx/svdoutl.hxx>
#include <comphelper/xmltools.hxx>
#include <sal/log.hxx>
#include <utility>
@@ -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: */
+13
View File
@@ -76,6 +76,7 @@
#include <svx/sdsxyitm.hxx>
#include <svx/sdtmfitm.hxx>
#include <svx/sdasitm.hxx>
#include <svx/diagram/IDiagramHelper.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
@@ -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();
}
+23 -13
View File
@@ -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<SdrObject*>(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<OutlinerParaObject> 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<beans::PropertyValue>()));
}
}
void SdrObject::NbcSetOutlinerParaObject(std::optional<OutlinerParaObject> /*pTextObject*/, bool /*bAdjustTextFrameWidthAndHeight = true*/)
+5 -33
View File
@@ -34,6 +34,11 @@
#include <vcl/canvastools.hxx>
#include <svx/diagram/IDiagramHelper.hxx>
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<css::beans::PropertyValue> propList(rVal.get< css::uno::Sequence<css::beans::PropertyValue> >());
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
{
// <aOutRect> has to contain the bounding rectangle
+7
View File
@@ -67,6 +67,13 @@ interface BaseTextDrawBase
StateMethod = GetState ;
]
SID_DIAGRAM_TO_GROUP
[
AutoUpdate = TRUE ,
ExecMethod = Execute ;
StateMethod = GetState ;
]
SID_EDIT_DIAGRAM
[
AutoUpdate = TRUE ,
+9 -2
View File
@@ -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<SdrObjGroup*>(pObj));
pSdrView->MarkObj(pObj, pSdrView->GetSdrPageView());
}
else // SID_EDIT_DIAGRAM
else if(SID_EDIT_DIAGRAM == nSlotId)
{
VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create();
VclPtr<VclAbstractDialog> 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());
}
}
}
}