328 lines
15 KiB
C++
328 lines
15 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
#include "vbalistformat.hxx"
|
|
#include <utility>
|
|
#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/text/XTextTable.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;
|
|
|
|
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 ))
|
|
{
|
|
}
|
|
|
|
SwVbaListFormat::~SwVbaListFormat()
|
|
{
|
|
}
|
|
|
|
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 )
|
|
{
|
|
bool bContinuePreviousList = true;
|
|
if( ContinuePreviousList.hasValue() )
|
|
ContinuePreviousList >>= bContinuePreviousList;
|
|
|
|
// "applyto" must be current selection
|
|
sal_Int32 bApplyTo = word::WdListApplyTo::wdListApplyToSelection;
|
|
if( ApplyTo.hasValue() )
|
|
ApplyTo >>= bApplyTo;
|
|
if( bApplyTo != word::WdListApplyTo::wdListApplyToSelection )
|
|
throw uno::RuntimeException();
|
|
|
|
// default behaviour must be wdWord8ListBehavior
|
|
sal_Int32 nDefaultListBehavior = word::WdDefaultListBehavior::wdWord8ListBehavior;
|
|
if( DefaultListBehavior.hasValue() )
|
|
DefaultListBehavior >>= nDefaultListBehavior;
|
|
if( nDefaultListBehavior != word::WdDefaultListBehavior::wdWord8ListBehavior )
|
|
throw uno::RuntimeException();
|
|
|
|
uno::Reference< container::XEnumerationAccess > xEnumAccess( mxTextRange, uno::UNO_QUERY_THROW );
|
|
uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration();
|
|
if (!xEnum->hasMoreElements())
|
|
return;
|
|
|
|
SwVbaListTemplate& rListTemplate = dynamic_cast<SwVbaListTemplate&>(*ListTemplate);
|
|
|
|
bool isFirstElement = true;
|
|
do
|
|
{
|
|
uno::Reference< beans::XPropertySet > xProps( xEnum->nextElement(), uno::UNO_QUERY_THROW );
|
|
if( isFirstElement )
|
|
{
|
|
bool isNumberingRestart = !bContinuePreviousList;
|
|
xProps->setPropertyValue(u"ParaIsNumberingRestart"_ustr, uno::Any( isNumberingRestart ) );
|
|
if( isNumberingRestart )
|
|
{
|
|
xProps->setPropertyValue(u"NumberingStartValue"_ustr, uno::Any( sal_Int16(1) ) );
|
|
}
|
|
isFirstElement = false;
|
|
}
|
|
else
|
|
{
|
|
xProps->setPropertyValue(u"ParaIsNumberingRestart"_ustr, uno::Any( false ) );
|
|
}
|
|
rListTemplate.applyListTemplate( xProps );
|
|
}
|
|
while( xEnum->hasMoreElements() );
|
|
}
|
|
|
|
template <class Ref>
|
|
static void addParagraphsToList(const Ref& a,
|
|
std::vector<css::uno::Reference<css::beans::XPropertySet>>& rList)
|
|
{
|
|
if (css::uno::Reference<css::lang::XServiceInfo> xInfo{ a, css::uno::UNO_QUERY })
|
|
{
|
|
if (xInfo->supportsService(u"com.sun.star.text.Paragraph"_ustr))
|
|
{
|
|
rList.emplace_back(xInfo, css::uno::UNO_QUERY_THROW);
|
|
}
|
|
else if (xInfo->supportsService(u"com.sun.star.text.TextTable"_ustr))
|
|
{
|
|
css::uno::Reference<css::text::XTextTable> xTable(xInfo, css::uno::UNO_QUERY_THROW);
|
|
const auto aNames = xTable->getCellNames();
|
|
for (const auto& rName : aNames)
|
|
{
|
|
addParagraphsToList(xTable->getCellByName(rName), rList);
|
|
}
|
|
}
|
|
}
|
|
if (css::uno::Reference<css::container::XEnumerationAccess> xEnumAccess{ a,
|
|
css::uno::UNO_QUERY })
|
|
{
|
|
auto xEnum = xEnumAccess->createEnumeration();
|
|
while (xEnum->hasMoreElements())
|
|
addParagraphsToList(xEnum->nextElement(), rList);
|
|
}
|
|
}
|
|
|
|
void SAL_CALL SwVbaListFormat::ConvertNumbersToText( )
|
|
{
|
|
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(u"ConvertNumbersToText"_ustr);
|
|
xModel->lockControllers();
|
|
comphelper::ScopeGuard g([xModel, xUndoManager]() {
|
|
xModel->unlockControllers();
|
|
xUndoManager->leaveUndoContext();
|
|
});
|
|
|
|
std::vector<css::uno::Reference<css::beans::XPropertySet>> aParagraphs;
|
|
addParagraphsToList(mxTextRange, aParagraphs);
|
|
|
|
// in reverse order, to get proper label strings
|
|
for (auto iter = aParagraphs.rbegin(); iter != aParagraphs.rend(); ++iter)
|
|
{
|
|
auto& rPropertySet = *iter;
|
|
if (bool bNumber; (rPropertySet->getPropertyValue(u"NumberingIsNumber"_ustr) >>= bNumber) && bNumber)
|
|
{
|
|
css::uno::Reference<css::text::XTextRange> xRange(rPropertySet, css::uno::UNO_QUERY_THROW);
|
|
OUString sLabelString;
|
|
rPropertySet->getPropertyValue(u"ListLabelString"_ustr) >>= 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;
|
|
sal_Int32 nLeftMargin = SAL_MAX_INT32;
|
|
sal_Int32 nSymbolTextDistance = SAL_MAX_INT32;
|
|
sal_Int32 nFirstLineOffset = 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;
|
|
rPropertySet->getPropertyValue(u"NumberingLevel"_ustr) >>= nLevel;
|
|
css::uno::Reference<css::container::XIndexAccess> xNumberingRules;
|
|
rPropertySet->getPropertyValue(u"NumberingRules"_ustr) >>= xNumberingRules;
|
|
comphelper::SequenceAsHashMap aLevelRule(xNumberingRules->getByIndex(nLevel));
|
|
|
|
// See offapi/com/sun/star/text/NumberingLevel.idl
|
|
aLevelRule[u"CharStyleName"_ustr] >>= sCharStyleName;
|
|
aLevelRule[u"NumberingType"_ustr] >>= nNumberingType;
|
|
// TODO: aLevelRule["Adjust"] >>= nAdjust; // HoriOrientation::LEFT/RIGHT/CENTER
|
|
aLevelRule[u"PositionAndSpaceMode"_ustr] >>= nPositionAndSpaceMode;
|
|
|
|
// for css::text::PositionAndSpaceMode::LABEL_ALIGNMENT
|
|
aLevelRule[u"LabelFollowedBy"_ustr] >>= nLabelFollowedBy;
|
|
aLevelRule[u"ListtabStopPosition"_ustr] >>= nListtabStopPosition;
|
|
aLevelRule[u"FirstLineIndent"_ustr] >>= nFirstLineIndent;
|
|
aLevelRule[u"IndentAt"_ustr] >>= nIndentAt;
|
|
|
|
// for css::text::PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION
|
|
aLevelRule[u"LeftMargin"_ustr] >>= nLeftMargin;
|
|
aLevelRule[u"SymbolTextDistance"_ustr] >>= nSymbolTextDistance;
|
|
aLevelRule[u"FirstLineOffset"_ustr] >>= nFirstLineOffset;
|
|
|
|
aLevelRule[u"BulletChar"_ustr] >>= sBulletChar;
|
|
bHasFont = (aLevelRule[u"BulletFont"_ustr] >>= aBulletFont);
|
|
bHasColor = (aLevelRule[u"BulletColor"_ustr] >>= aBulletColor);
|
|
}
|
|
|
|
if (nNumberingType != css::style::NumberingType::BITMAP) // TODO
|
|
{
|
|
if (nPositionAndSpaceMode
|
|
== css::text::PositionAndSpaceMode::LABEL_WIDTH_AND_POSITION)
|
|
{
|
|
nIndentAt = nLeftMargin;
|
|
nFirstLineIndent = nFirstLineOffset;
|
|
nListtabStopPosition = nSymbolTextDistance;
|
|
nLabelFollowedBy = SvxNumberFormat::LabelFollowedBy::LISTTAB;
|
|
}
|
|
|
|
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(u"CharStyleName"_ustr, 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[u"CharHeight"_ustr] <<= aBulletFont.Height;
|
|
}
|
|
if (bHasColor)
|
|
{
|
|
aNameValues[u"CharColor"_ustr] <<= 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
|
|
}
|
|
|
|
rPropertySet->setPropertyValue(u"ParaLeftMargin"_ustr, css::uno::Any(nIndentAt));
|
|
rPropertySet->setPropertyValue(u"ParaFirstLineIndent"_ustr, css::uno::Any(nFirstLineIndent));
|
|
if (nLabelFollowedBy == SvxNumberFormat::LabelFollowedBy::LISTTAB)
|
|
{
|
|
css::uno::Sequence<css::style::TabStop> stops;
|
|
rPropertySet->getPropertyValue(u"ParaTabStops"_ustr) >>= stops;
|
|
css::style::TabStop tabStop{};
|
|
tabStop.Position = nListtabStopPosition;
|
|
tabStop.Alignment = css::style::TabAlign::TabAlign_LEFT;
|
|
tabStop.FillChar = ' ';
|
|
rPropertySet->setPropertyValue(u"ParaTabStops"_ustr,
|
|
css::uno::Any(comphelper::combineSequences({ tabStop }, stops)));
|
|
// FIXME: What if added tap stop is greater than already defined ones?
|
|
}
|
|
}
|
|
else
|
|
{
|
|
continue; // for now, keep such lists as is
|
|
}
|
|
|
|
// In case of higher outline levels, each assignment of empty value just sets level 1
|
|
while (rPropertySet->getPropertyValue(u"NumberingRules"_ustr) != css::uno::Any())
|
|
{
|
|
rPropertySet->setPropertyValue(u"NumberingRules"_ustr, css::uno::Any());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
OUString
|
|
SwVbaListFormat::getServiceImplName()
|
|
{
|
|
return u"SwVbaListFormat"_ustr;
|
|
}
|
|
|
|
uno::Sequence< OUString >
|
|
SwVbaListFormat::getServiceNames()
|
|
{
|
|
static uno::Sequence< OUString > const aServiceNames
|
|
{
|
|
u"ooo.vba.word.ListFormat"_ustr
|
|
};
|
|
return aServiceNames;
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|