diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2020-07-31 11:01:32 +0300 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2020-08-01 18:50:11 +0200 |
commit | dc5d8d39e229b2fb1091c179942e6dae9d160101 (patch) | |
tree | 5edeba9f99edcb450ccbb70288ca6a23a98899ac /sw | |
parent | 0898838bc962bae9ab698e1f585a67d832260110 (diff) |
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.kaganski@collabora.com>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/source/ui/vba/vbalistformat.cxx | 173 |
1 files changed, 172 insertions, 1 deletions
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 |