sc/inc/postit.hxx | 20 ++++-- sc/source/core/data/postit.cxx | 52 ++++++++--------- sc/source/filter/inc/richstring.hxx | 3 + sc/source/filter/oox/commentsbuffer.cxx | 94 +++++++++++++++++++++----------- sc/source/filter/oox/richstring.cxx | 14 +++- sc/source/ui/docshell/docfunc.cxx | 9 +-- sc/source/ui/inc/docfunc.hxx | 10 ++- 7 files changed, 126 insertions(+), 76 deletions(-)
New commits: commit 2bda87fd8758448267c447ba26f1932325a1338d Author: Caolán McNamara <caolan.mcnam...@collabora.com> AuthorDate: Fri Aug 11 13:29:23 2023 +0100 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Sun Aug 13 18:13:20 2023 +0200 defer turning xlsx notes into SdrCaptions until activated to improve import performance Change-Id: I8dd3483372d20cbbb8694bae02a7d8b062324ff0 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155613 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/sc/inc/postit.hxx b/sc/inc/postit.hxx index c2a5cc9a60ad..df114eaf64a5 100644 --- a/sc/inc/postit.hxx +++ b/sc/inc/postit.hxx @@ -174,12 +174,20 @@ private: sal_uInt32 mnPostItId; }; +class GenerateNoteCaption +{ +public: + virtual void Generate(SdrCaptionObj& rCaptionObj) = 0; + virtual OUString GetSimpleText() const = 0; + virtual ~GenerateNoteCaption() {}; +}; + class SC_DLLPUBLIC ScNoteUtil { static ScPostIt* InsertNote(ScDocument& rDoc, const ScAddress& rPos, ScNoteData&& rNoteData, bool bAlwaysCreateCaption, sal_uInt32 nPostItId); - static ScNoteData CreateNoteData(ScDocument& rDoc, const ScAddress& rPos, const OutlinerParaObject& rOutlinerObj, + static ScNoteData CreateNoteData(ScDocument& rDoc, const ScAddress& rPos, const tools::Rectangle& rCaptionRect, bool bShown); public: @@ -242,13 +250,11 @@ public: const OutlinerParaObject& rOutlinerObj, const tools::Rectangle& rCaptionRect, bool bShown ); - // similar to above, except rPropertyNames/rPropertyValues contain the - // uno properties for the caption object formatting. - static ScPostIt* CreateNoteFromObjectProperties( + // similar to above, except xGenerator is a functor to apply import + // properties to the caption object to finalize it on demand + static ScPostIt* CreateNoteFromGenerator( ScDocument& rDoc, const ScAddress& rPos, - const css::uno::Sequence<OUString>& rPropertyNames, - const css::uno::Sequence<css::uno::Any>& rPropertyValues, - const OutlinerParaObject& rOutlinerObj, + std::unique_ptr<GenerateNoteCaption> xGenerator, const tools::Rectangle& rCaptionRect, bool bShown ); /** Creates a cell note based on the passed string and inserts it into the diff --git a/sc/source/core/data/postit.cxx b/sc/source/core/data/postit.cxx index cdcc03e4999d..b631d7659d99 100644 --- a/sc/source/core/data/postit.cxx +++ b/sc/source/core/data/postit.cxx @@ -424,15 +424,11 @@ ScNoteCaptionCreator::ScNoteCaptionCreator( ScDocument& rDoc, const ScAddress& r } // namespace - struct ScCaptionInitData { std::optional< SfxItemSet > moItemSet; /// Caption object formatting. - - uno::Sequence<OUString> maPropertyNames; /// Alternative import filter Caption object formatting property names - uno::Sequence<uno::Any> maPropertyValues; /// Alternative import filter Caption object formatting property values - std::optional< OutlinerParaObject > mxOutlinerObj; /// Text object with all text portion formatting. + std::unique_ptr< GenerateNoteCaption > mxGenerator; /// Operator to generate Caption Object from import data OUString maStyleName; /// Drawing style associated with the caption object. OUString maSimpleText; /// Simple text without formatting. Point maCaptionOffset; /// Caption position relative to cell corner. @@ -658,13 +654,18 @@ void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const bool bWasLocked = maNoteData.mxCaption->getSdrModelFromSdrObject().isLocked(); maNoteData.mxCaption->getSdrModelFromSdrObject().setLock(true); - // transfer ownership of outliner object to caption, or set simple text - OSL_ENSURE( xInitData->mxOutlinerObj || !xInitData->maSimpleText.isEmpty(), - "ScPostIt::CreateCaptionFromInitData - need either outliner para object or simple text" ); - if (xInitData->mxOutlinerObj) - maNoteData.mxCaption->SetOutlinerParaObject( std::move(xInitData->mxOutlinerObj) ); + if (xInitData->mxGenerator) + xInitData->mxGenerator->Generate(*maNoteData.mxCaption); else - maNoteData.mxCaption->SetText( xInitData->maSimpleText ); + { + // transfer ownership of outliner object to caption, or set simple text + OSL_ENSURE( xInitData->mxOutlinerObj || !xInitData->maSimpleText.isEmpty(), + "ScPostIt::CreateCaptionFromInitData - need either outliner para object or simple text" ); + if (xInitData->mxOutlinerObj) + maNoteData.mxCaption->SetOutlinerParaObject( std::move(xInitData->mxOutlinerObj) ); + else + maNoteData.mxCaption->SetText( xInitData->maSimpleText ); + } if (!xInitData->maStyleName.isEmpty()) { @@ -684,13 +685,6 @@ void ScPostIt::CreateCaptionFromInitData( const ScAddress& rPos ) const ScCaptionUtil::SetExtraItems(*maNoteData.mxCaption, *xInitData->moItemSet); } - if (xInitData->maPropertyNames.getLength()) - { - rtl::Reference<SvxShapeText> xAnnoShape(dynamic_cast<SvxShapeText*>(maNoteData.mxCaption->getUnoShape().get())); // SvxShapeText - assert(xAnnoShape && "will not be null"); - static_cast<SvxShape*>(xAnnoShape.get())->setPropertyValues(xInitData->maPropertyNames, xInitData->maPropertyValues); - } - // set position and size of the caption object if( xInitData->mbDefaultPosSize ) { @@ -941,13 +935,12 @@ ScPostIt* ScNoteUtil::CreateNoteFromCaption( return pNote; } -ScNoteData ScNoteUtil::CreateNoteData(ScDocument& rDoc, const ScAddress& rPos, const OutlinerParaObject& rOutlinerObj, +ScNoteData ScNoteUtil::CreateNoteData(ScDocument& rDoc, const ScAddress& rPos, const tools::Rectangle& rCaptionRect, bool bShown) { ScNoteData aNoteData( bShown ); aNoteData.mxInitData = std::make_shared<ScCaptionInitData>(); ScCaptionInitData& rInitData = *aNoteData.mxInitData; - rInitData.mxOutlinerObj = rOutlinerObj; // convert absolute caption position to relative position rInitData.mbDefaultPosSize = rCaptionRect.IsEmpty(); @@ -968,25 +961,28 @@ ScPostIt* ScNoteUtil::CreateNoteFromObjectData( const OutlinerParaObject& rOutlinerObj, const tools::Rectangle& rCaptionRect, bool bShown ) { - ScNoteData aNoteData(CreateNoteData(rDoc, rPos, rOutlinerObj, rCaptionRect, bShown)); + ScNoteData aNoteData(CreateNoteData(rDoc, rPos, rCaptionRect, bShown)); ScCaptionInitData& rInitData = *aNoteData.mxInitData; + rInitData.mxOutlinerObj = rOutlinerObj; rInitData.moItemSet.emplace(std::move(rItemSet)); rInitData.maStyleName = ScStyleNameConversion::ProgrammaticToDisplayName(rStyleName, SfxStyleFamily::Frame); return InsertNote(rDoc, rPos, std::move(aNoteData), /*bAlwaysCreateCaption*/false, 0/*nPostItId*/); } -ScPostIt* ScNoteUtil::CreateNoteFromObjectProperties( +ScPostIt* ScNoteUtil::CreateNoteFromGenerator( ScDocument& rDoc, const ScAddress& rPos, - const uno::Sequence<OUString>& rPropertyNames, - const uno::Sequence<uno::Any>& rPropertyValues, - const OutlinerParaObject& rOutlinerObj, const tools::Rectangle& rCaptionRect, + std::unique_ptr<GenerateNoteCaption> xGenerator, + const tools::Rectangle& rCaptionRect, bool bShown ) { - ScNoteData aNoteData(CreateNoteData(rDoc, rPos, rOutlinerObj, rCaptionRect, bShown)); + ScNoteData aNoteData(CreateNoteData(rDoc, rPos, rCaptionRect, bShown)); ScCaptionInitData& rInitData = *aNoteData.mxInitData; - rInitData.maPropertyNames = rPropertyNames; - rInitData.maPropertyValues = rPropertyValues; + rInitData.mxGenerator = std::move(xGenerator); + // because the Caption is generated on demand, we will need to create the + // simple text now to supply any querys for that which don't require + // creation of a full Caption + rInitData.maSimpleText = rInitData.mxGenerator->GetSimpleText(); return InsertNote(rDoc, rPos, std::move(aNoteData), /*bAlwaysCreateCaption*/false, 0/*nPostItId*/); } diff --git a/sc/source/filter/inc/richstring.hxx b/sc/source/filter/inc/richstring.hxx index b74e3036f473..3969de6b7974 100644 --- a/sc/source/filter/inc/richstring.hxx +++ b/sc/source/filter/inc/richstring.hxx @@ -228,6 +228,9 @@ public: OUString& orString, const oox::xls::Font* pFirstPortionFont ) const; + /** Get the text of all portions as a single string regardless of formatted or not */ + OUString getStringContent() const; + /** Converts the string and writes it into the passed XText, replace old contents of the text object,. @param rxText The XText interface of the target object. */ diff --git a/sc/source/filter/oox/commentsbuffer.cxx b/sc/source/filter/oox/commentsbuffer.cxx index 9307ad707006..1f1f2dd2540c 100644 --- a/sc/source/filter/oox/commentsbuffer.cxx +++ b/sc/source/filter/oox/commentsbuffer.cxx @@ -147,6 +147,44 @@ RichStringRef const & Comment::createText() return maModel.mxText; } +namespace +{ + struct OOXGenerateNoteCaption : public GenerateNoteCaption + { + css::uno::Sequence<OUString> maPropertyNames; /// import filter Caption object formatting property names + css::uno::Sequence<css::uno::Any> maPropertyValues; /// import filter Caption object formatting property values + std::shared_ptr<RichString> mxText; + + OOXGenerateNoteCaption(std::shared_ptr<RichString>& rText) + : mxText(rText) + { + } + + virtual void Generate(SdrCaptionObj& rCaptionObj) override + { + rtl::Reference<SvxShapeText> xAnnoShape(dynamic_cast<SvxShapeText*>(rCaptionObj.getUnoShape().get())); // SvxShapeText + assert(xAnnoShape && "will not be null"); + + if (maPropertyNames.getLength()) + { + // setting a property triggers expensive process, so set them all at once + static_cast<SvxShape*>(xAnnoShape.get())->setPropertyValues(maPropertyNames, maPropertyValues); + } + + // insert text and convert text formatting + Reference< XText > xAnnoText( xAnnoShape ); + xAnnoShape->addActionLock(); + mxText->convert( xAnnoText ); + xAnnoShape->removeActionLock(); + } + + virtual OUString GetSimpleText() const override + { + return mxText->getStringContent(); + } + }; +} + void Comment::finalizeImport() { // BIFF12 stores cell range instead of cell address, use first cell of this range @@ -160,24 +198,22 @@ void Comment::finalizeImport() ScTableSheetObj* pAnnosSupp = static_cast<ScTableSheetObj*>(getSheet().get()); rtl::Reference<ScAnnotationsObj> xAnnos = static_cast<ScAnnotationsObj*>(pAnnosSupp->getAnnotations().get()); ScDocShell* pDocShell = xAnnos->GetDocShell(); - // non-empty string required by note implementation (real text will be added below) - ScPostIt* pPostIt = pDocShell->GetDocFunc().ImportNote( maModel.maRange.aStart, OUString( ' ' ) ); - SdrCaptionObj* pCaption = pPostIt->GetOrCreateCaption( maModel.maRange.aStart ); - rtl::Reference< SvxShapeText > xAnnoShape( dynamic_cast<SvxShapeText*>(pCaption->getUnoShape().get() ) ); // SvxShapeText - assert(xAnnoShape && "will not be null"); - // setting a property triggers expensive process, so set them all at once + auto xGenerator = std::make_unique<OOXGenerateNoteCaption>(maModel.mxText); // Add shape formatting properties (autoFill, colHidden and rowHidden are dropped) // vvv TODO vvv TextFitToSize should be a drawing::TextFitToSizeType not bool - Sequence<OUString> aPropertyNames{ "TextFitToSize", "MoveProtect", "TextHorizontalAdjust", "TextVerticalAdjust" }; - Sequence<Any> aPropertyValues{ Any(maModel.mbAutoScale), Any(maModel.mbLocked), - Any(lcl_ToHorizAlign( maModel.mnTHA )), Any(lcl_ToVertAlign( maModel.mnTVA )) }; + xGenerator->maPropertyNames = + css::uno::Sequence<OUString>{ "TextFitToSize", "MoveProtect", "TextHorizontalAdjust", "TextVerticalAdjust" }; + xGenerator->maPropertyValues = + css::uno::Sequence<css::uno::Any>{ Any(maModel.mbAutoScale), Any(maModel.mbLocked), + Any(lcl_ToHorizAlign( maModel.mnTHA )), Any(lcl_ToVertAlign( maModel.mnTVA )) }; + tools::Rectangle aCaptionRect; if( maModel.maAnchor.Width > 0 && maModel.maAnchor.Height > 0 ) { - xAnnoShape->setPosition( css::awt::Point( maModel.maAnchor.X, maModel.maAnchor.Y ) ); - xAnnoShape->setSize( css::awt::Size( maModel.maAnchor.Width, maModel.maAnchor.Height ) ); + aCaptionRect = tools::Rectangle(Point(maModel.maAnchor.X, maModel.maAnchor.Y), + Size(maModel.maAnchor.Width, maModel.maAnchor.Height)); } // convert shape formatting and visibility @@ -188,8 +224,8 @@ void Comment::finalizeImport() css::awt::Rectangle aShapeRect = pVmlNoteShape->getShapeRectangle(); if (aShapeRect.Width > 0 || aShapeRect.Height > 0) { - xAnnoShape->setPosition(css::awt::Point(aShapeRect.X, aShapeRect.Y)); - xAnnoShape->setSize(css::awt::Size(aShapeRect.Width, aShapeRect.Height)); + aCaptionRect = tools::Rectangle(Point(aShapeRect.X, aShapeRect.Y), + Size(aShapeRect.Width, aShapeRect.Height)); ::oox::drawingml::ShapePropertyMap aPropMap(pVmlNoteShape->makeShapePropertyMap()); @@ -197,12 +233,12 @@ void Comment::finalizeImport() Sequence<Any> aVMLPropValues; aPropMap.fillSequences(aVMLPropNames, aVMLPropValues); - sal_uInt32 nOldPropLen = aPropertyNames.getLength(); + sal_uInt32 nOldPropLen = xGenerator->maPropertyNames.getLength(); sal_uInt32 nVMLPropLen = aVMLPropNames.getLength(); - aPropertyNames.realloc(nOldPropLen + nVMLPropLen); - aPropertyValues.realloc(nOldPropLen + nVMLPropLen); - OUString* pNames = aPropertyNames.getArray(); - Any* pValues = aPropertyValues.getArray(); + xGenerator->maPropertyNames.realloc(nOldPropLen + nVMLPropLen); + xGenerator->maPropertyValues.realloc(nOldPropLen + nVMLPropLen); + OUString* pNames = xGenerator->maPropertyNames.getArray(); + Any* pValues = xGenerator->maPropertyValues.getArray(); for (sal_uInt32 i = 0; i < nVMLPropLen; ++i) { pNames[nOldPropLen + i] = aVMLPropNames[i]; @@ -215,28 +251,24 @@ void Comment::finalizeImport() // Setting comment text alignment const ::oox::vml::ClientData* xClientData = pVmlNoteShape->getClientData(); - sal_uInt32 nOldPropLen = aPropertyNames.getLength(); - aPropertyNames.realloc(nOldPropLen + 2); - aPropertyValues.realloc(nOldPropLen + 2); - OUString* pNames = aPropertyNames.getArray(); - Any* pValues = aPropertyValues.getArray(); + sal_uInt32 nOldPropLen = xGenerator->maPropertyNames.getLength(); + xGenerator->maPropertyNames.realloc(nOldPropLen + 2); + xGenerator->maPropertyValues.realloc(nOldPropLen + 2); + OUString* pNames = xGenerator->maPropertyNames.getArray(); + Any* pValues = xGenerator->maPropertyValues.getArray(); pNames[nOldPropLen] = "TextVerticalAdjust"; pValues[nOldPropLen] <<= lcl_ToVertAlign(xClientData->mnTextVAlign); pNames[nOldPropLen + 1] = "ParaAdjust"; pValues[nOldPropLen + 1] <<= lcl_ToParaAlign( xClientData->mnTextHAlign); } - static_cast<SvxShape*>(xAnnoShape.get())->setPropertyValues(aPropertyNames, aPropertyValues); + xGenerator->mxText->finalizeImport(*this); + + pDocShell->GetDocFunc().ImportNote(maModel.maRange.aStart, std::move(xGenerator), + aCaptionRect, bVisible); if (bVisible) pDocShell->GetDocFunc().ShowNote( maModel.maRange.aStart, bVisible ); - - // insert text and convert text formatting - maModel.mxText->finalizeImport(*this); - Reference< XText > xAnnoText( xAnnoShape ); - xAnnoShape->addActionLock(); - maModel.mxText->convert( xAnnoText ); - xAnnoShape->removeActionLock(); } catch( Exception& ) { diff --git a/sc/source/filter/oox/richstring.cxx b/sc/source/filter/oox/richstring.cxx index a1345179c19a..06db87e3c733 100644 --- a/sc/source/filter/oox/richstring.cxx +++ b/sc/source/filter/oox/richstring.cxx @@ -398,18 +398,24 @@ void RichString::convert( const Reference< XText >& rxText ) } } -std::unique_ptr<EditTextObject> RichString::convert( ScEditEngineDefaulter& rEE, const oox::xls::Font* pFirstPortionFont ) +OUString RichString::getStringContent() const { - ESelection aSelection; - OUStringBuffer sString; for( auto& rTextPortion : maTextPortions ) sString.append(rTextPortion.getText()); + return sString.makeStringAndClear(); +} + +std::unique_ptr<EditTextObject> RichString::convert( ScEditEngineDefaulter& rEE, const oox::xls::Font* pFirstPortionFont ) +{ + ESelection aSelection; + + OUString sString(getStringContent()); // fdo#84370 - diving into editeng is not thread safe. SolarMutexGuard aGuard; - rEE.SetTextCurrentDefaults( sString.makeStringAndClear() ); + rEE.SetTextCurrentDefaults(sString); for( auto& rTextPortion : maTextPortions ) { diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx index 4d3288558c40..e89e48476e1c 100644 --- a/sc/source/ui/docshell/docfunc.cxx +++ b/sc/source/ui/docshell/docfunc.cxx @@ -1405,7 +1405,9 @@ void ScDocFunc::ReplaceNote( const ScAddress& rPos, const OUString& rNoteText, c } } -ScPostIt* ScDocFunc::ImportNote( const ScAddress& rPos, const OUString& rNoteText ) +void ScDocFunc::ImportNote( const ScAddress& rPos, + std::unique_ptr<GenerateNoteCaption> xGenerator, + const tools::Rectangle& rCaptionRect, bool bShown ) { ScDocShellModificator aModificator( rDocShell ); ScDocument& rDoc = rDocShell.GetDocument(); @@ -1414,13 +1416,12 @@ ScPostIt* ScDocFunc::ImportNote( const ScAddress& rPos, const OUString& rNoteTex SAL_WARN_IF(pOldNote, "sc.ui", "imported data has >1 notes on same cell? at pos " << rPos); // create new note - ScPostIt* pNewNote = ScNoteUtil::CreateNoteFromString( rDoc, rPos, rNoteText, false, true, /*nNoteId*/0 ); + ScNoteUtil::CreateNoteFromGenerator(rDoc, rPos, std::move(xGenerator), + rCaptionRect, bShown); rDoc.SetStreamValid(rPos.Tab(), false); aModificator.SetDocumentModified(); - - return pNewNote; } bool ScDocFunc::ApplyAttributes( const ScMarkData& rMark, const ScPatternAttr& rPattern, diff --git a/sc/source/ui/inc/docfunc.hxx b/sc/source/ui/inc/docfunc.hxx index 77bdb57012de..6419e285d5b7 100644 --- a/sc/source/ui/inc/docfunc.hxx +++ b/sc/source/ui/inc/docfunc.hxx @@ -29,6 +29,7 @@ #include <vector> #include <map> +class GenerateNoteCaption; class ScEditEngineDefaulter; class SdrUndoAction; class ScAddress; @@ -47,7 +48,6 @@ class ScConditionalFormat; class ScConditionalFormatList; class ScUndoRemoveMerge; class ScRangeName; -class ScPostIt; enum class TransliterationFlags; enum class CreateNameFlags; @@ -58,6 +58,10 @@ namespace sc class SparklineGroup; class Sparkline; } +namespace tools +{ + class Rectangle; +} class ScDocFunc { @@ -124,7 +128,9 @@ public: void SetNoteText( const ScAddress& rPos, const OUString& rNoteText, bool bApi ); void ReplaceNote( const ScAddress& rPos, const OUString& rNoteText, const OUString* pAuthor, const OUString* pDate, bool bApi ); - SC_DLLPUBLIC ScPostIt* ImportNote( const ScAddress& rPos, const OUString& rNoteText ); + SC_DLLPUBLIC void ImportNote( const ScAddress& rPos, + std::unique_ptr<GenerateNoteCaption> xGenerator, + const tools::Rectangle& rCaptionRect, bool bShown ); bool ApplyAttributes( const ScMarkData& rMark, const ScPatternAttr& rPattern, bool bApi );