LibreOffice Module sw (master) 1
vbalistformat.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19#include "vbalistformat.hxx"
20#include <utility>
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>
37#include <editeng/numitem.hxx>
38#include "vbalisttemplate.hxx"
39
40#include <vector>
41
42using namespace ::ooo::vba;
43using namespace ::com::sun::star;
44
45SwVbaListFormat::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 ))
46{
47}
48
50{
51}
52
53void 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 )
54{
55 bool bContinuePreviousList = true;
56 if( ContinuePreviousList.hasValue() )
57 ContinuePreviousList >>= bContinuePreviousList;
58
59 // "applyto" must be current selection
60 sal_Int32 bApplyTo = word::WdListApplyTo::wdListApplyToSelection;
61 if( ApplyTo.hasValue() )
62 ApplyTo >>= bApplyTo;
63 if( bApplyTo != word::WdListApplyTo::wdListApplyToSelection )
64 throw uno::RuntimeException();
65
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();
72
73 uno::Reference< container::XEnumerationAccess > xEnumAccess( mxTextRange, uno::UNO_QUERY_THROW );
74 uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration();
75 if (!xEnum->hasMoreElements())
76 return;
77
78 SwVbaListTemplate& rListTemplate = dynamic_cast<SwVbaListTemplate&>(*ListTemplate);
79
80 bool isFirstElement = true;
81 do
82 {
83 uno::Reference< beans::XPropertySet > xProps( xEnum->nextElement(), uno::UNO_QUERY_THROW );
84 if( isFirstElement )
85 {
86 bool isNumberingRestart = !bContinuePreviousList;
87 xProps->setPropertyValue("ParaIsNumberingRestart", uno::Any( isNumberingRestart ) );
88 if( isNumberingRestart )
89 {
90 xProps->setPropertyValue("NumberingStartValue", uno::Any( sal_Int16(1) ) );
91 }
92 isFirstElement = false;
93 }
94 else
95 {
96 xProps->setPropertyValue("ParaIsNumberingRestart", uno::Any( false ) );
97 }
98 rListTemplate.applyListTemplate( xProps );
99 }
100 while( xEnum->hasMoreElements() );
101}
102
103template <class Ref>
104static void addParagraphsToList(const Ref& a,
105 std::vector<css::uno::Reference<css::beans::XPropertySet>>& rList)
106{
107 if (css::uno::Reference<css::lang::XServiceInfo> xInfo{ a, css::uno::UNO_QUERY })
108 {
109 if (xInfo->supportsService("com.sun.star.text.Paragraph"))
110 {
111 rList.emplace_back(xInfo, css::uno::UNO_QUERY_THROW);
112 }
113 else if (xInfo->supportsService("com.sun.star.text.TextTable"))
114 {
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)
118 {
119 addParagraphsToList(xTable->getCellByName(rName), rList);
120 }
121 }
122 }
123 if (css::uno::Reference<css::container::XEnumerationAccess> xEnumAccess{ a,
124 css::uno::UNO_QUERY })
125 {
126 auto xEnum = xEnumAccess->createEnumeration();
127 while (xEnum->hasMoreElements())
128 addParagraphsToList(xEnum->nextElement(), rList);
129 }
130}
131
133{
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();
143 });
144
145 std::vector<css::uno::Reference<css::beans::XPropertySet>> aParagraphs;
146 addParagraphsToList(mxTextRange, aParagraphs);
147
148 // in reverse order, to get proper label strings
149 for (auto iter = aParagraphs.rbegin(); iter != aParagraphs.rend(); ++iter)
150 {
151 auto& rPropertySet = *iter;
152 if (bool bNumber; (rPropertySet->getPropertyValue("NumberingIsNumber") >>= bNumber) && bNumber)
153 {
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;
167 OUString sCharStyleName, sBulletChar;
168 css::awt::FontDescriptor aBulletFont;
169 bool bHasFont;
170 css::util::Color aBulletColor = css::util::Color(COL_AUTO);
171 bool bHasColor;
172
173 {
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));
179
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;
185
186 // for css::text::PositionAndSpaceMode::LABEL_ALIGNMENT
187 aLevelRule["LabelFollowedBy"] >>= nLabelFollowedBy;
188 aLevelRule["ListtabStopPosition"] >>= nListtabStopPosition;
189 aLevelRule["FirstLineIndent"] >>= nFirstLineIndent;
190 aLevelRule["IndentAt"] >>= nIndentAt;
191
192 // for css::text::PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION
193 aLevelRule["LeftMargin"] >>= nLeftMargin;
194 aLevelRule["SymbolTextDistance"] >>= nSymbolTextDistance;
195 aLevelRule["FirstLineOffset"] >>= nFirstLineOffset;
196
197 aLevelRule["BulletChar"] >>= sBulletChar;
198 bHasFont = (aLevelRule["BulletFont"] >>= aBulletFont);
199 bHasColor = (aLevelRule["BulletColor"] >>= aBulletColor);
200 }
201
202 if (nNumberingType != css::style::NumberingType::BITMAP) // TODO
203 {
204 if (nPositionAndSpaceMode
205 == css::text::PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION)
206 {
207 nIndentAt = nLeftMargin;
208 nFirstLineIndent = nFirstLineOffset;
209 nListtabStopPosition = nSymbolTextDistance;
210 nLabelFollowedBy = SvxNumberFormat::LabelFollowedBy::LISTTAB;
211 }
212
213 switch (nLabelFollowedBy)
214 {
215 case SvxNumberFormat::LabelFollowedBy::LISTTAB:
216 sLabelString += "\t";
217 break;
218 case SvxNumberFormat::LabelFollowedBy::SPACE:
219 sLabelString += " ";
220 break;
221 case SvxNumberFormat::LabelFollowedBy::NEWLINE:
222 sLabelString += "\n";
223 break;
224 }
225
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));
232
233 if (nNumberingType == css::style::NumberingType::CHAR_SPECIAL)
234 {
235 css::uno::Reference<css::text::XTextRange> xBulletText(xNumberText->getStart());
236 xBulletText->setString(sBulletChar);
237
238 std::unordered_map<OUString, css::uno::Any> aNameValues;
239 if (bHasFont)
240 {
241 aNameValues.insert({
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))) },
254 });
255 if (aBulletFont.Height)
256 aNameValues["CharHeight"] <<= aBulletFont.Height;
257 }
258 if (bHasColor)
259 {
260 aNameValues["CharColor"] <<= aBulletColor;
261 }
262
263 if (css::uno::Reference<css::beans::XMultiPropertySet> xBulletMultiProps{
264 xBulletText, css::uno::UNO_QUERY })
265 {
266 xBulletMultiProps->setPropertyValues(
269 }
270 else
271 {
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);
276 }
277 }
278 else
279 {
280 // TODO: css::style::NumberingType::BITMAP
281 }
282
283 rPropertySet->setPropertyValue("ParaLeftMargin", css::uno::Any(nIndentAt));
284 rPropertySet->setPropertyValue("ParaFirstLineIndent", css::uno::Any(nFirstLineIndent));
285 if (nLabelFollowedBy == SvxNumberFormat::LabelFollowedBy::LISTTAB)
286 {
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?
296 }
297 }
298 else
299 {
300 continue; // for now, keep such lists as is
301 }
302
303 // In case of higher outline levels, each assignment of empty value just sets level 1
304 while (rPropertySet->getPropertyValue("NumberingRules") != css::uno::Any())
305 {
306 rPropertySet->setPropertyValue("NumberingRules", css::uno::Any());
307 }
308 }
309 }
310}
311
312OUString
314{
315 return "SwVbaListFormat";
316}
317
318uno::Sequence< OUString >
320{
321 static uno::Sequence< OUString > const aServiceNames
322 {
323 "ooo.vba.word.ListFormat"
324 };
325 return aServiceNames;
326}
327
328/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OUString sCharStyleName
css::uno::Reference< css::uno::XComponentContext > mxContext
virtual void SAL_CALL ApplyListTemplate(const css::uno::Reference< ::ooo::vba::word::XListTemplate > &ListTemplate, const css::uno::Any &ContinuePreviousList, const css::uno::Any &ApplyTo, const css::uno::Any &DefaultListBehavior) override
virtual OUString getServiceImplName() override
css::uno::Reference< css::text::XTextRange > mxTextRange
virtual void SAL_CALL ConvertNumbersToText() override
virtual ~SwVbaListFormat() override
virtual css::uno::Sequence< OUString > getServiceNames() override
SwVbaListFormat(const css::uno::Reference< ooo::vba::XHelperInterface > &rParent, const css::uno::Reference< css::uno::XComponentContext > &rContext, css::uno::Reference< css::text::XTextRange > xTextRange)
void applyListTemplate(css::uno::Reference< css::beans::XPropertySet > const &xProps)
constexpr ::Color COL_AUTO(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
Sequence< OUString > aServiceNames
uno_Any a
sal_Int32 nSymbolTextDistance
sal_Int32 nFirstLineOffset
tools::Long const nLeftMargin
css::uno::Sequence< typename M::key_type > mapKeysToSequence(M const &map)
css::uno::Sequence< typename M::mapped_type > mapValuesToSequence(M const &map)
css::uno::Sequence< T > combineSequences(css::uno::Sequence< T > const &left, css::uno::Sequence< T > const &right)
VBAHELPER_DLLPUBLIC css::uno::Reference< css::frame::XModel > getThisWordDoc(const css::uno::Reference< css::uno::XComponentContext > &xContext)
Reference< XModel > xModel
#define SAL_MAX_UINT16
#define SAL_MAX_INT32
#define SAL_MAX_INT16
static void addParagraphsToList(const Ref &a, std::vector< css::uno::Reference< css::beans::XPropertySet > > &rList)