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

Reply via email to