1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 #include "vbalistformat.hxx"
21 #include <vbahelper/vbahelper.hxx>
22 #include <ooo/vba/word/WdListApplyTo.hpp>
23 #include <ooo/vba/word/WdDefaultListBehavior.hpp>
24 #include <com/sun/star/awt/FontDescriptor.hpp>
25 #include <com/sun/star/container/XEnumerationAccess.hpp>
26 #include <com/sun/star/container/XEnumeration.hpp>
27 #include <com/sun/star/document/XUndoManagerSupplier.hpp>
28 #include <com/sun/star/beans/XMultiPropertySet.hpp>
29 #include <com/sun/star/beans/XPropertySet.hpp>
30 #include <com/sun/star/style/TabStop.hpp>
31 #include <com/sun/star/text/PositionAndSpaceMode.hpp>
32 #include <com/sun/star/text/XTextTable.hpp>
33 #include <com/sun/star/util/Color.hpp>
34 #include <comphelper/sequence.hxx>
35 #include <comphelper/sequenceashashmap.hxx>
36 #include <comphelper/scopeguard.hxx>
37 #include <editeng/numitem.hxx>
38 #include "vbalisttemplate.hxx"
42 using namespace ::ooo::vba
;
43 using namespace ::com::sun::star
;
45 SwVbaListFormat::SwVbaListFormat( const uno::Reference
< ooo::vba::XHelperInterface
>& rParent
, const uno::Reference
< uno::XComponentContext
>& rContext
, uno::Reference
< text::XTextRange
> xTextRange
) : SwVbaListFormat_BASE( rParent
, rContext
), mxTextRange(std::move( xTextRange
))
49 SwVbaListFormat::~SwVbaListFormat()
53 void SAL_CALL
SwVbaListFormat::ApplyListTemplate( const css::uno::Reference
< word::XListTemplate
>& ListTemplate
, const css::uno::Any
& ContinuePreviousList
, const css::uno::Any
& ApplyTo
, const css::uno::Any
& DefaultListBehavior
)
55 bool bContinuePreviousList
= true;
56 if( ContinuePreviousList
.hasValue() )
57 ContinuePreviousList
>>= bContinuePreviousList
;
59 // "applyto" must be current selection
60 sal_Int32 bApplyTo
= word::WdListApplyTo::wdListApplyToSelection
;
61 if( ApplyTo
.hasValue() )
63 if( bApplyTo
!= word::WdListApplyTo::wdListApplyToSelection
)
64 throw uno::RuntimeException();
66 // default behaviour must be wdWord8ListBehavior
67 sal_Int32 nDefaultListBehavior
= word::WdDefaultListBehavior::wdWord8ListBehavior
;
68 if( DefaultListBehavior
.hasValue() )
69 DefaultListBehavior
>>= nDefaultListBehavior
;
70 if( nDefaultListBehavior
!= word::WdDefaultListBehavior::wdWord8ListBehavior
)
71 throw uno::RuntimeException();
73 uno::Reference
< container::XEnumerationAccess
> xEnumAccess( mxTextRange
, uno::UNO_QUERY_THROW
);
74 uno::Reference
< container::XEnumeration
> xEnum
= xEnumAccess
->createEnumeration();
75 if (!xEnum
->hasMoreElements())
78 SwVbaListTemplate
& rListTemplate
= dynamic_cast<SwVbaListTemplate
&>(*ListTemplate
);
80 bool isFirstElement
= true;
83 uno::Reference
< beans::XPropertySet
> xProps( xEnum
->nextElement(), uno::UNO_QUERY_THROW
);
86 bool isNumberingRestart
= !bContinuePreviousList
;
87 xProps
->setPropertyValue("ParaIsNumberingRestart", uno::Any( isNumberingRestart
) );
88 if( isNumberingRestart
)
90 xProps
->setPropertyValue("NumberingStartValue", uno::Any( sal_Int16(1) ) );
92 isFirstElement
= false;
96 xProps
->setPropertyValue("ParaIsNumberingRestart", uno::Any( false ) );
98 rListTemplate
.applyListTemplate( xProps
);
100 while( xEnum
->hasMoreElements() );
104 static void addParagraphsToList(const Ref
& a
,
105 std::vector
<css::uno::Reference
<css::beans::XPropertySet
>>& rList
)
107 if (css::uno::Reference
<css::lang::XServiceInfo
> xInfo
{ a
, css::uno::UNO_QUERY
})
109 if (xInfo
->supportsService("com.sun.star.text.Paragraph"))
111 rList
.emplace_back(xInfo
, css::uno::UNO_QUERY_THROW
);
113 else if (xInfo
->supportsService("com.sun.star.text.TextTable"))
115 css::uno::Reference
<css::text::XTextTable
> xTable(xInfo
, css::uno::UNO_QUERY_THROW
);
116 const auto aNames
= xTable
->getCellNames();
117 for (const auto& rName
: aNames
)
119 addParagraphsToList(xTable
->getCellByName(rName
), rList
);
123 if (css::uno::Reference
<css::container::XEnumerationAccess
> xEnumAccess
{ a
,
124 css::uno::UNO_QUERY
})
126 auto xEnum
= xEnumAccess
->createEnumeration();
127 while (xEnum
->hasMoreElements())
128 addParagraphsToList(xEnum
->nextElement(), rList
);
132 void SAL_CALL
SwVbaListFormat::ConvertNumbersToText( )
134 css::uno::Reference
<css::frame::XModel
> xModel(getThisWordDoc(mxContext
));
135 css::uno::Reference
<css::document::XUndoManagerSupplier
> xUndoSupplier(
136 xModel
, css::uno::UNO_QUERY_THROW
);
137 css::uno::Reference
<css::document::XUndoManager
> xUndoManager(xUndoSupplier
->getUndoManager());
138 xUndoManager
->enterUndoContext("ConvertNumbersToText");
139 xModel
->lockControllers();
140 comphelper::ScopeGuard
g([xModel
, xUndoManager
]() {
141 xModel
->unlockControllers();
142 xUndoManager
->leaveUndoContext();
145 std::vector
<css::uno::Reference
<css::beans::XPropertySet
>> aParagraphs
;
146 addParagraphsToList(mxTextRange
, aParagraphs
);
148 // in reverse order, to get proper label strings
149 for (auto iter
= aParagraphs
.rbegin(); iter
!= aParagraphs
.rend(); ++iter
)
151 auto& rPropertySet
= *iter
;
152 if (bool bNumber
; (rPropertySet
->getPropertyValue("NumberingIsNumber") >>= bNumber
) && bNumber
)
154 css::uno::Reference
<css::text::XTextRange
> xRange(rPropertySet
, css::uno::UNO_QUERY_THROW
);
155 OUString sLabelString
;
156 rPropertySet
->getPropertyValue("ListLabelString") >>= sLabelString
;
157 // sal_Int16 nAdjust = SAL_MAX_INT16; // TODO?
158 sal_Int16 nNumberingType
= SAL_MAX_INT16
; // css::style::NumberingType
159 sal_Int16 nPositionAndSpaceMode
= SAL_MAX_INT16
;
160 sal_Int16 nLabelFollowedBy
= SAL_MAX_INT16
;
161 sal_Int32 nListtabStopPosition
= SAL_MAX_INT32
;
162 sal_Int32 nFirstLineIndent
= SAL_MAX_INT32
;
163 sal_Int32 nIndentAt
= SAL_MAX_INT32
;
164 sal_Int32 nLeftMargin
= SAL_MAX_INT32
;
165 sal_Int32 nSymbolTextDistance
= SAL_MAX_INT32
;
166 sal_Int32 nFirstLineOffset
= SAL_MAX_INT32
;
167 OUString sCharStyleName
, sBulletChar
;
168 css::awt::FontDescriptor aBulletFont
;
170 css::util::Color aBulletColor
= css::util::Color(COL_AUTO
);
174 sal_uInt16 nLevel
= SAL_MAX_UINT16
;
175 rPropertySet
->getPropertyValue("NumberingLevel") >>= nLevel
;
176 css::uno::Reference
<css::container::XIndexAccess
> xNumberingRules
;
177 rPropertySet
->getPropertyValue("NumberingRules") >>= xNumberingRules
;
178 comphelper::SequenceAsHashMap
aLevelRule(xNumberingRules
->getByIndex(nLevel
));
180 // See offapi/com/sun/star/text/NumberingLevel.idl
181 aLevelRule
["CharStyleName"] >>= sCharStyleName
;
182 aLevelRule
["NumberingType"] >>= nNumberingType
;
183 // TODO: aLevelRule["Adjust"] >>= nAdjust; // HoriOrientation::LEFT/RIGHT/CENTER
184 aLevelRule
["PositionAndSpaceMode"] >>= nPositionAndSpaceMode
;
186 // for css::text::PositionAndSpaceMode::LABEL_ALIGNMENT
187 aLevelRule
["LabelFollowedBy"] >>= nLabelFollowedBy
;
188 aLevelRule
["ListtabStopPosition"] >>= nListtabStopPosition
;
189 aLevelRule
["FirstLineIndent"] >>= nFirstLineIndent
;
190 aLevelRule
["IndentAt"] >>= nIndentAt
;
192 // for css::text::PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION
193 aLevelRule
["LeftMargin"] >>= nLeftMargin
;
194 aLevelRule
["SymbolTextDistance"] >>= nSymbolTextDistance
;
195 aLevelRule
["FirstLineOffset"] >>= nFirstLineOffset
;
197 aLevelRule
["BulletChar"] >>= sBulletChar
;
198 bHasFont
= (aLevelRule
["BulletFont"] >>= aBulletFont
);
199 bHasColor
= (aLevelRule
["BulletColor"] >>= aBulletColor
);
202 if (nNumberingType
!= css::style::NumberingType::BITMAP
) // TODO
204 if (nPositionAndSpaceMode
205 == css::text::PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION
)
207 nIndentAt
= nLeftMargin
;
208 nFirstLineIndent
= nFirstLineOffset
;
209 nListtabStopPosition
= nSymbolTextDistance
;
210 nLabelFollowedBy
= SvxNumberFormat::LabelFollowedBy::LISTTAB
;
213 switch (nLabelFollowedBy
)
215 case SvxNumberFormat::LabelFollowedBy::LISTTAB
:
216 sLabelString
+= "\t";
218 case SvxNumberFormat::LabelFollowedBy::SPACE
:
221 case SvxNumberFormat::LabelFollowedBy::NEWLINE
:
222 sLabelString
+= "\n";
226 css::uno::Reference
<css::text::XTextRange
> xNumberText(xRange
->getStart());
227 xNumberText
->setString(sLabelString
);
228 css::uno::Reference
<css::beans::XPropertySet
> xNumberProps(
229 xNumberText
, css::uno::UNO_QUERY_THROW
);
230 if (!sCharStyleName
.isEmpty())
231 xNumberProps
->setPropertyValue("CharStyleName", css::uno::Any(sCharStyleName
));
233 if (nNumberingType
== css::style::NumberingType::CHAR_SPECIAL
)
235 css::uno::Reference
<css::text::XTextRange
> xBulletText(xNumberText
->getStart());
236 xBulletText
->setString(sBulletChar
);
238 std::unordered_map
<OUString
, css::uno::Any
> aNameValues
;
242 { "CharFontName", css::uno::Any(aBulletFont
.Name
) },
243 { "CharFontStyleName", css::uno::Any(aBulletFont
.StyleName
) },
244 { "CharFontFamily", css::uno::Any(aBulletFont
.Family
) },
245 { "CharFontCharSet", css::uno::Any(aBulletFont
.CharSet
) },
246 { "CharWeight", css::uno::Any(aBulletFont
.Weight
) },
247 { "CharUnderline", css::uno::Any(aBulletFont
.Underline
) },
248 { "CharStrikeout", css::uno::Any(aBulletFont
.Strikeout
) },
249 { "CharAutoKerning", css::uno::Any(aBulletFont
.Kerning
) },
250 { "CharFontPitch", css::uno::Any(aBulletFont
.Pitch
) },
251 { "CharWordMode", css::uno::Any(aBulletFont
.WordLineMode
) },
252 { "CharRotation", css::uno::Any(static_cast<sal_Int16
>(
253 std::round(aBulletFont
.Orientation
* 10))) },
255 if (aBulletFont
.Height
)
256 aNameValues
["CharHeight"] <<= aBulletFont
.Height
;
260 aNameValues
["CharColor"] <<= aBulletColor
;
263 if (css::uno::Reference
<css::beans::XMultiPropertySet
> xBulletMultiProps
{
264 xBulletText
, css::uno::UNO_QUERY
})
266 xBulletMultiProps
->setPropertyValues(
267 comphelper::mapKeysToSequence(aNameValues
),
268 comphelper::mapValuesToSequence(aNameValues
));
272 css::uno::Reference
<css::beans::XPropertySet
> xBulletProps(
273 xBulletText
, css::uno::UNO_QUERY_THROW
);
274 for (const auto& [rName
, rVal
] : aNameValues
)
275 xBulletProps
->setPropertyValue(rName
, rVal
);
280 // TODO: css::style::NumberingType::BITMAP
283 rPropertySet
->setPropertyValue("ParaLeftMargin", css::uno::Any(nIndentAt
));
284 rPropertySet
->setPropertyValue("ParaFirstLineIndent", css::uno::Any(nFirstLineIndent
));
285 if (nLabelFollowedBy
== SvxNumberFormat::LabelFollowedBy::LISTTAB
)
287 css::uno::Sequence
<css::style::TabStop
> stops
;
288 rPropertySet
->getPropertyValue("ParaTabStops") >>= stops
;
289 css::style::TabStop tabStop
{};
290 tabStop
.Position
= nListtabStopPosition
;
291 tabStop
.Alignment
= com::sun::star::style::TabAlign::TabAlign_LEFT
;
292 tabStop
.FillChar
= ' ';
293 rPropertySet
->setPropertyValue("ParaTabStops",
294 css::uno::Any(comphelper::combineSequences({ tabStop
}, stops
)));
295 // FIXME: What if added tap stop is greater than already defined ones?
300 continue; // for now, keep such lists as is
303 // In case of higher outline levels, each assignment of empty value just sets level 1
304 while (rPropertySet
->getPropertyValue("NumberingRules") != css::uno::Any())
306 rPropertySet
->setPropertyValue("NumberingRules", css::uno::Any());
313 SwVbaListFormat::getServiceImplName()
315 return "SwVbaListFormat";
318 uno::Sequence
< OUString
>
319 SwVbaListFormat::getServiceNames()
321 static uno::Sequence
< OUString
> const aServiceNames
323 "ooo.vba.word.ListFormat"
325 return aServiceNames
;
328 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */