sw/source/ui/vba/vbalistformat.cxx | 173 ++++++++++++++++++++++++++++++++++++- 1 file changed, 172 insertions(+), 1 deletion(-)
New commits: commit dc5d8d39e229b2fb1091c179942e6dae9d160101 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Fri Jul 31 11:01:32 2020 +0300 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Sat Aug 1 18:50:11 2020 +0200 Implement VBA's ListFormat.ConvertNumbersToText This only handles lists with PositionAndSpaceMode::LABEL_ALIGNMENT. TODO: handle PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION. TODO: handle NumberingType::BITMAP. It doesn't align number according to Adjust, since that requires to use a tab stop at the number position with appropriate alignment, and it's unclear how would that interact with LabelFollowedBy modes other than LISTTAB. When first tab stop position is greater than ParaLeftMargin, Writer uses left margin as implicit tab stop position, thus in this case list appearance is different from processed text appearance. In case of justified paragraphs, space after number (which does not participate in justification when part of numbering) becomes part of justification after conversion to text. Change-Id: I88ad6617f8a09307ecad9d28edee92a59c68a4d4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/99939 Tested-by: Mike Kaganski <mike.kagan...@collabora.com> Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/sw/source/ui/vba/vbalistformat.cxx b/sw/source/ui/vba/vbalistformat.cxx index 9ad18ebfcf33..d8642cb7fab0 100644 --- a/sw/source/ui/vba/vbalistformat.cxx +++ b/sw/source/ui/vba/vbalistformat.cxx @@ -20,11 +20,23 @@ #include <vbahelper/vbahelper.hxx> #include <ooo/vba/word/WdListApplyTo.hpp> #include <ooo/vba/word/WdDefaultListBehavior.hpp> +#include <com/sun/star/awt/FontDescriptor.hpp> #include <com/sun/star/container/XEnumerationAccess.hpp> #include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/document/XUndoManagerSupplier.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> #include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/style/TabStop.hpp> +#include <com/sun/star/text/PositionAndSpaceMode.hpp> +#include <com/sun/star/util/Color.hpp> +#include <comphelper/sequence.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <comphelper/scopeguard.hxx> +#include <editeng/numitem.hxx> #include "vbalisttemplate.hxx" +#include <vector> + using namespace ::ooo::vba; using namespace ::com::sun::star; @@ -88,7 +100,166 @@ void SAL_CALL SwVbaListFormat::ApplyListTemplate( const css::uno::Reference< wor void SAL_CALL SwVbaListFormat::ConvertNumbersToText( ) { - throw uno::RuntimeException("Not implemented" ); + css::uno::Reference<css::frame::XModel> xModel(getThisWordDoc(mxContext)); + css::uno::Reference<css::document::XUndoManagerSupplier> xUndoSupplier( + xModel, css::uno::UNO_QUERY_THROW); + css::uno::Reference<css::document::XUndoManager> xUndoManager(xUndoSupplier->getUndoManager()); + xUndoManager->enterUndoContext("ConvertNumbersToText"); + xModel->lockControllers(); + comphelper::ScopeGuard g([xModel, xUndoManager]() { + xModel->unlockControllers(); + xUndoManager->leaveUndoContext(); + }); + + css::uno::Reference<css::container::XEnumerationAccess> xEnumAccess(mxTextRange, + css::uno::UNO_QUERY_THROW); + auto xEnum = xEnumAccess->createEnumeration(); + if (!xEnum->hasMoreElements()) + return; + + std::vector<css::uno::Reference<css::beans::XPropertySet>> aParagraphs; + while (xEnum->hasMoreElements()) + aParagraphs.emplace_back(xEnum->nextElement(), css::uno::UNO_QUERY_THROW); + + // in reverse order, to get proper label strings + for (auto it = aParagraphs.rbegin(); it != aParagraphs.rend(); ++it) + { + if (bool bNumber; ((*it)->getPropertyValue("NumberingIsNumber") >>= bNumber) && bNumber) + { + css::uno::Reference<css::text::XTextRange> xRange(*it, css::uno::UNO_QUERY_THROW); + OUString sLabelString; + (*it)->getPropertyValue("ListLabelString") >>= sLabelString; + // sal_Int16 nAdjust = SAL_MAX_INT16; // TODO? + sal_Int16 nNumberingType = SAL_MAX_INT16; // css::style::NumberingType + sal_Int16 nPositionAndSpaceMode = SAL_MAX_INT16; + sal_Int16 nLabelFollowedBy = SAL_MAX_INT16; + sal_Int32 nListtabStopPosition = SAL_MAX_INT32; + sal_Int32 nFirstLineIndent = SAL_MAX_INT32; + sal_Int32 nIndentAt = SAL_MAX_INT32; + OUString sCharStyleName, sBulletChar; + css::awt::FontDescriptor aBulletFont; + bool bHasFont; + css::util::Color aBulletColor = css::util::Color(COL_AUTO); + bool bHasColor; + + { + sal_uInt16 nLevel = SAL_MAX_UINT16; + (*it)->getPropertyValue("NumberingLevel") >>= nLevel; + css::uno::Reference<css::container::XIndexAccess> xNumberingRules; + (*it)->getPropertyValue("NumberingRules") >>= xNumberingRules; + comphelper::SequenceAsHashMap aLevelRule(xNumberingRules->getByIndex(nLevel)); + + // See offapi/com/sun/star/text/NumberingLevel.idl + aLevelRule["CharStyleName"] >>= sCharStyleName; + aLevelRule["NumberingType"] >>= nNumberingType; + // TODO: aLevelRule["Adjust"] >>= nAdjust; // HoriOrientation::LEFT/RIGHT/CENTER + aLevelRule["PositionAndSpaceMode"] >>= nPositionAndSpaceMode; + aLevelRule["LabelFollowedBy"] >>= nLabelFollowedBy; + aLevelRule["ListtabStopPosition"] >>= nListtabStopPosition; + aLevelRule["FirstLineIndent"] >>= nFirstLineIndent; + aLevelRule["IndentAt"] >>= nIndentAt; + aLevelRule["BulletChar"] >>= sBulletChar; + bHasFont = (aLevelRule["BulletFont"] >>= aBulletFont); + bHasColor = (aLevelRule["BulletColor"] >>= aBulletColor); + } + + if (nPositionAndSpaceMode == css::text::PositionAndSpaceMode::LABEL_ALIGNMENT + && nNumberingType != css::style::NumberingType::BITMAP) // TODO + { + switch (nLabelFollowedBy) + { + case SvxNumberFormat::LabelFollowedBy::LISTTAB: + sLabelString += "\t"; + break; + case SvxNumberFormat::LabelFollowedBy::SPACE: + sLabelString += " "; + break; + case SvxNumberFormat::LabelFollowedBy::NEWLINE: + sLabelString += "\n"; + break; + } + + css::uno::Reference<css::text::XTextRange> xNumberText(xRange->getStart()); + xNumberText->setString(sLabelString); + css::uno::Reference<css::beans::XPropertySet> xNumberProps( + xNumberText, css::uno::UNO_QUERY_THROW); + if (!sCharStyleName.isEmpty()) + xNumberProps->setPropertyValue("CharStyleName", css::uno::Any(sCharStyleName)); + + if (nNumberingType == css::style::NumberingType::CHAR_SPECIAL) + { + css::uno::Reference<css::text::XTextRange> xBulletText(xNumberText->getStart()); + xBulletText->setString(sBulletChar); + + std::unordered_map<OUString, css::uno::Any> aNameValues; + if (bHasFont) + { + aNameValues.insert({ + { "CharFontName", css::uno::Any(aBulletFont.Name) }, + { "CharFontStyleName", css::uno::Any(aBulletFont.StyleName) }, + { "CharFontFamily", css::uno::Any(aBulletFont.Family) }, + { "CharFontCharSet", css::uno::Any(aBulletFont.CharSet) }, + { "CharWeight", css::uno::Any(aBulletFont.Weight) }, + { "CharUnderline", css::uno::Any(aBulletFont.Underline) }, + { "CharStrikeout", css::uno::Any(aBulletFont.Strikeout) }, + { "CharAutoKerning", css::uno::Any(aBulletFont.Kerning) }, + { "CharFontPitch", css::uno::Any(aBulletFont.Pitch) }, + { "CharWordMode", css::uno::Any(aBulletFont.WordLineMode) }, + { "CharRotation", css::uno::Any(static_cast<sal_Int16>( + std::round(aBulletFont.Orientation * 10))) }, + }); + if (aBulletFont.Height) + aNameValues["CharHeight"] <<= aBulletFont.Height; + } + if (bHasColor) + { + aNameValues["CharColor"] <<= aBulletColor; + } + + if (css::uno::Reference<css::beans::XMultiPropertySet> xBulletMultiProps{ + xBulletText, css::uno::UNO_QUERY }) + { + xBulletMultiProps->setPropertyValues( + comphelper::mapKeysToSequence(aNameValues), + comphelper::mapValuesToSequence(aNameValues)); + } + else + { + css::uno::Reference<css::beans::XPropertySet> xBulletProps( + xBulletText, css::uno::UNO_QUERY_THROW); + for (const auto& [rName, rVal] : aNameValues) + xBulletProps->setPropertyValue(rName, rVal); + } + } + else + { + // TODO: css::style::NumberingType::BITMAP + } + + (*it)->setPropertyValue("ParaLeftMargin", css::uno::Any(nIndentAt)); + (*it)->setPropertyValue("ParaFirstLineIndent", css::uno::Any(nFirstLineIndent)); + if (nLabelFollowedBy == SvxNumberFormat::LabelFollowedBy::LISTTAB) + { + css::uno::Sequence<css::style::TabStop> stops; + (*it)->getPropertyValue("ParaTabStops") >>= stops; + css::style::TabStop tabStop{}; + tabStop.Position = nListtabStopPosition - nIndentAt; + tabStop.Alignment = com::sun::star::style::TabAlign::TabAlign_LEFT; + tabStop.FillChar = ' '; + (*it)->setPropertyValue( + "ParaTabStops", + css::uno::Any(comphelper::combineSequences({ tabStop }, stops))); + // FIXME: What if added tap stop is greater than already defined ones? + } + } + else + { + // TODO: css::text::PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION + continue; // for now, keep such lists as is + } + (*it)->setPropertyValue("NumberingRules", css::uno::Any()); + } + } } OUString _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits