24#include <com/sun/star/awt/XControlModel.hpp>
25#include <com/sun/star/beans/XPropertySet.hpp>
26#include <com/sun/star/container/XNameContainer.hpp>
27#include <com/sun/star/io/XInputStreamProvider.hpp>
28#include <com/sun/star/lang/XMultiServiceFactory.hpp>
29#include <com/sun/star/uno/XComponentContext.hpp>
30#include <osl/diagnose.h>
31#include <rtl/ustrbuf.hxx>
43#include <oox/token/properties.hxx>
44#include <oox/token/tokens.hxx>
45#include <unordered_map>
58const sal_uInt16 VBA_SITE_CLASSIDINDEX = 0x8000;
59const sal_uInt16 VBA_SITE_INDEXMASK = 0x7FFF;
60const sal_uInt16 VBA_SITE_FORM = 7;
61const sal_uInt16 VBA_SITE_IMAGE = 12;
62const sal_uInt16 VBA_SITE_FRAME = 14;
63const sal_uInt16 VBA_SITE_SPINBUTTON = 16;
64const sal_uInt16 VBA_SITE_COMMANDBUTTON = 17;
65const sal_uInt16 VBA_SITE_TABSTRIP = 18;
66const sal_uInt16 VBA_SITE_LABEL = 21;
67const sal_uInt16 VBA_SITE_TEXTBOX = 23;
68const sal_uInt16 VBA_SITE_LISTBOX = 24;
69const sal_uInt16 VBA_SITE_COMBOBOX = 25;
70const sal_uInt16 VBA_SITE_CHECKBOX = 26;
71const sal_uInt16 VBA_SITE_OPTIONBUTTON = 27;
72const sal_uInt16 VBA_SITE_TOGGLEBUTTON = 28;
73const sal_uInt16 VBA_SITE_SCROLLBAR = 47;
74const sal_uInt16 VBA_SITE_MULTIPAGE = 57;
75const sal_uInt16 VBA_SITE_UNKNOWN = 0x7FFF;
77const sal_uInt32 VBA_SITE_TABSTOP = 0x00000001;
78const sal_uInt32 VBA_SITE_VISIBLE = 0x00000002;
79const sal_uInt32 VBA_SITE_OSTREAM = 0x00000010;
80const sal_uInt32 VBA_SITE_DEFFLAGS = 0x00000033;
88class VbaControlNamesSet
91 explicit VbaControlNamesSet();
94 void insertName(
const VbaFormControl& rControl );
96 OUString generateDummyName();
99 ::std::set< OUString >
104constexpr OUStringLiteral gaDummyBaseName( u
"DummyGroupSep" );
106VbaControlNamesSet::VbaControlNamesSet() :
111void VbaControlNamesSet::insertName(
const VbaFormControl& rControl )
113 OUString
aName = rControl.getControlName();
114 if( !
aName.isEmpty() )
118OUString VbaControlNamesSet::generateDummyName()
123 aCtrlName = gaDummyBaseName + OUString::number( ++
mnIndex );
131struct VbaControlNameInserter
135 explicit VbaControlNameInserter( VbaControlNamesSet& rCtrlNames ) :
mrCtrlNames( rCtrlNames ) {}
136 void operator()(
const VbaFormControl& rControl ) {
mrCtrlNames.insertName( rControl ); }
142class VbaDummyFormControl :
public VbaFormControl
145 explicit VbaDummyFormControl(
const OUString& rName );
148VbaDummyFormControl::VbaDummyFormControl(
const OUString& rName )
150 mxSiteModel = std::make_shared<VbaSiteModel>();
151 mxSiteModel->importProperty( XML_Name, rName );
152 mxSiteModel->importProperty( XML_VariousPropertyBits, OUString(
'0' ) );
154 mxCtrlModel = std::make_shared<AxLabelModel>();
155 mxCtrlModel->setAwtModelMode();
156 mxCtrlModel->importProperty( XML_Size,
"10;10" );
161VbaSiteModel::VbaSiteModel() :
164 mnHelpContextId( 0 ),
168 mnClassIdOrCache( VBA_SITE_UNKNOWN ),
181 case XML_Name:
maName = rValue;
break;
182 case XML_Tag:
maTag = rValue;
break;
210 maPos.first += rDistance.first;
211 maPos.second += rDistance.second;
233 return aBuffer.makeStringAndClear();
242 sal_Int32 nTypeIndex =
static_cast< sal_Int32
>(
mnClassIdOrCache & VBA_SITE_INDEXMASK );
247 case VBA_SITE_COMMANDBUTTON: xCtrlModel= std::make_shared<AxCommandButtonModel>();
break;
248 case VBA_SITE_LABEL: xCtrlModel= std::make_shared<AxLabelModel>();
break;
249 case VBA_SITE_IMAGE: xCtrlModel= std::make_shared<AxImageModel>();
break;
250 case VBA_SITE_TOGGLEBUTTON: xCtrlModel= std::make_shared<AxToggleButtonModel>();
break;
251 case VBA_SITE_CHECKBOX: xCtrlModel= std::make_shared<AxCheckBoxModel>();
break;
252 case VBA_SITE_OPTIONBUTTON: xCtrlModel= std::make_shared<AxOptionButtonModel>();
break;
253 case VBA_SITE_TEXTBOX: xCtrlModel= std::make_shared<AxTextBoxModel>();
break;
254 case VBA_SITE_LISTBOX: xCtrlModel= std::make_shared<AxListBoxModel>();
break;
255 case VBA_SITE_COMBOBOX: xCtrlModel= std::make_shared<AxComboBoxModel>();
break;
256 case VBA_SITE_SPINBUTTON: xCtrlModel= std::make_shared<AxSpinButtonModel>();
break;
257 case VBA_SITE_SCROLLBAR: xCtrlModel= std::make_shared<AxScrollBarModel>();
break;
258 case VBA_SITE_TABSTRIP: xCtrlModel= std::make_shared<AxTabStripModel>();
260 case VBA_SITE_FRAME: xCtrlModel= std::make_shared<AxFrameModel>();
break;
261 case VBA_SITE_MULTIPAGE: xCtrlModel= std::make_shared<AxMultiPageModel>();
263 case VBA_SITE_FORM: xCtrlModel= std::make_shared<AxPageModel>();
265 default: OSL_FAIL(
"VbaSiteModel::createControlModel - unknown type index" );
271 OSL_ENSURE( pGuid,
"VbaSiteModel::createControlModel - invalid class table index" );
275 xCtrlModel = std::make_shared<ComCtlScrollBarModel>( 6 );
277 xCtrlModel = std::make_shared<ComCtlProgressBarModel>( 5 );
279 xCtrlModel = std::make_shared<ComCtlProgressBarModel>( 6 );
286 xCtrlModel->setAwtModelMode();
289 bool bModelIsContainer =
dynamic_cast< const AxContainerModelBase*
>( xCtrlModel.get() ) !=
nullptr;
290 bool bTypeMatch = bModelIsContainer ==
isContainer();
291 OSL_ENSURE( bTypeMatch,
"VbaSiteModel::createControlModel - container type does not match container flag" );
310 rPropMap.
setProperty( PROP_TabIndex,
static_cast< sal_Int16
>( nCtrlIndex ) );
334 OSL_ENSURE( xSubStrg,
"VbaFormControl::importModelOrStorage - cannot find storage for embedded control" );
338 else if( !rInStrm.
isEof() )
340 sal_Int64 nNextStrmPos = rInStrm.
tell() +
mxSiteModel->getStreamLength();
342 rInStrm.
seek( nNextStrmPos );
352 const Reference< XNameContainer >& rxParentNC,
const ControlConverter& rConv )
const
360 OUString aServiceName =
mxCtrlModel->getServiceName();
361 Reference< XMultiServiceFactory > xModelFactory( rxParentNC, UNO_QUERY_THROW );
362 Reference< XControlModel > xCtrlModel( xModelFactory->createInstance( aServiceName ), UNO_QUERY_THROW );
368 const OUString& rCtrlName =
mxSiteModel->getName();
369 OSL_ENSURE( !rxParentNC->hasByName( rCtrlName ),
"VbaFormControl::createAndConvert - multiple controls with equal name" );
391 OSL_ENSURE( pContainerModel,
"VbaFormControl::importStorage - missing container control model" );
392 if( !pContainerModel )
398 OSL_ENSURE( !aFStrm.
isEof(),
"VbaFormControl::importStorage - missing 'f' stream" );
419 ::std::ref( aOStrm ), ::std::ref( rStrg ), ::std::cref(
maClassTable ) );
431 typedef std::unordered_map< sal_uInt32, std::shared_ptr< VbaFormControl > > IdToPageMap;
432 IdToPageMap idToPage;
437 auto& elem = control->mxCtrlModel;
440 SAL_WARN(
"oox",
"empty control model");
447 idToPage[ xPageSiteRef->getId() ] = control;
452 sCaptions = pTabStrip->
maItems;
458 SAL_WARN(
"oox",
"unexpected control type " << elem->getControlType());
465 if ( sCaptions.size() == idToPage.size() )
467 AxArrayString::iterator itCaption = sCaptions.begin();
468 for (
const auto& rCtrlId : pMultiPage->
mnIDs )
470 IdToPageMap::iterator iter = idToPage.find( rCtrlId );
471 if ( iter != idToPage.end() )
494 const OUString& rCtrlName =
mxSiteModel->getName();
495 OSL_ENSURE( !rCtrlName.isEmpty(),
"VbaFormControl::convertProperties - control without name" );
496 if( !rCtrlName.isEmpty() )
510 Reference< XNameContainer > xCtrlModelNC( rxCtrlModel, UNO_QUERY_THROW );
514 ::std::cref( xCtrlModelNC ), ::std::cref( rConv ) );
518 OSL_FAIL(
"VbaFormControl::convertProperties - cannot get control container interface" );
544 sal_uInt64 nAnchorPos = rInStrm.
tell();
545 sal_uInt32 nSiteCount, nSiteDataSize;
548 sal_Int64 nSiteEndPos = rInStrm.
tell() + nSiteDataSize;
551 sal_uInt32 nSiteIndex = 0;
552 while( !rInStrm.
isEof() && (nSiteIndex < nSiteCount) )
556 if(
getFlag( nTypeCount, VBA_SITEINFO_COUNT ) )
563 nSiteIndex += (nTypeCount & VBA_SITEINFO_MASK);
578 bool bValid = !rInStrm.
isEof();
579 for( nSiteIndex = 0; bValid && (nSiteIndex < nSiteCount); ++nSiteIndex )
583 bValid = xControl->importSiteModel( rInStrm );
586 rInStrm.
seek( nSiteEndPos );
607 VbaControlNamesSet aControlNames;
608 VbaControlNameInserter aInserter( aControlNames );
612 control->maControls.forEach( aInserter );
622 VbaFormControlVectorVector aControlGroups;
625 VbaFormControlVectorMap aOptionGroups;
627 typedef VbaFormControlVectorMap::mapped_type VbaFormControlVectorRef;
628 bool bLastWasOptionButton =
false;
636 const OUString& rGroupName = pOptButtonModel->getGroupName();
637 VbaFormControlVectorRef& rxOptionGroup = aOptionGroups[ rGroupName ];
643 if( bLastWasOptionButton )
645 VbaFormControlVectorRef xDummyGroup = std::make_shared<VbaFormControlVector>();
646 aControlGroups.push_back( xDummyGroup );
647 OUString
aName = aControlNames.generateDummyName();
649 xDummyGroup->push_back( xDummyControl );
651 rxOptionGroup = std::make_shared<VbaFormControlVector>();
652 aControlGroups.push_back( rxOptionGroup );
657 rxOptionGroup->push_back(control);
658 bLastWasOptionButton =
true;
663 if( bLastWasOptionButton || aControlGroups.empty() )
665 VbaFormControlVectorRef xControlGroup = std::make_shared<VbaFormControlVector>();
666 aControlGroups.push_back( xControlGroup );
670 rLastGroup.push_back(control);
671 bLastWasOptionButton =
false;
678 control->moveEmbeddedToAbsoluteParent();
681 rLastGroup.insert( rLastGroup.end(), control->maControls.begin(), control->maControls.end() );
682 control->maControls.clear();
684 bLastWasOptionButton =
dynamic_cast< const AxOptionButtonModel*
>( rLastGroup.back()->mxCtrlModel.
get() ) !=
nullptr;
691 for (
auto const& controlGroup : aControlGroups)
725 sal_Int32 nLeftTabIndex = rxLeft->mxSiteModel ? rxLeft->mxSiteModel->getTabIndex() :
SAL_MAX_INT32;
726 sal_Int32 nRightTabIndex = rxRight->mxSiteModel ? rxRight->mxSiteModel->getTabIndex() :
SAL_MAX_INT32;
727 return nLeftTabIndex < nRightTabIndex;
732OUString lclGetQuotedString( std::u16string_view rCodeLine )
735 size_t nLen = rCodeLine.size();
736 if( (nLen > 0) && (rCodeLine[ 0 ] ==
'"') )
738 bool bExitLoop =
false;
739 for(
size_t nIndex = 1; !bExitLoop && (
nIndex < nLen); ++
nIndex )
743 bExitLoop = (cChar ==
'"') && ((nIndex + 1 == nLen) || (rCodeLine[
nIndex + 1 ] !=
'"'));
753 return aBuffer.makeStringAndClear();
756bool lclEatWhitespace( OUString& rCodeLine )
759 while( (nIndex < rCodeLine.getLength()) && ((rCodeLine[ nIndex ] ==
' ') || (rCodeLine[ nIndex ] ==
'\t')) )
763 rCodeLine = rCodeLine.copy( nIndex );
769bool lclEatKeyword( OUString& rCodeLine, std::u16string_view rKeyword )
771 if( rCodeLine.matchIgnoreAsciiCase( rKeyword ) )
773 rCodeLine = rCodeLine.copy( rKeyword.size() );
775 return rCodeLine.isEmpty() || lclEatWhitespace( rCodeLine );
783 const Reference< XModel >& rxDocModel,
const GraphicHelper& rGraphicHelper,
bool bDefaultColorBgr ) :
785 mxDocModel( rxDocModel ),
786 maConverter( rxDocModel, rGraphicHelper, bDefaultColorBgr )
788 OSL_ENSURE(
mxContext.is(),
"VbaUserForm::VbaUserForm - missing component context" );
789 OSL_ENSURE(
mxDocModel.is(),
"VbaUserForm::VbaUserForm - missing document model" );
793 StorageBase& rVbaFormStrg,
const OUString& rModuleName, rtl_TextEncoding eTextEnc )
795 OSL_ENSURE( rxDialogLib.is(),
"VbaUserForm::importForm - missing dialog library" );
801 OSL_ENSURE( !aInStrm.
isEof(),
"VbaUserForm::importForm - missing \\003VBFrame stream" );
802 if( aInStrm.
isEof() )
807 static const OUStringLiteral aBegin =
u"Begin";
809 bool bBeginFound =
false;
810 while( !bBeginFound && !aFrameTextStrm.
isEof() )
812 aLine = aFrameTextStrm.
readLine().trim();
813 bBeginFound = lclEatKeyword( aLine, aBegin );
816 if( !bBeginFound || !lclEatKeyword( aLine,
u"{C62A69F0-16DC-11CE-9E98-00AA00574A4F}" ) )
820 OUString aFormName = aLine.trim();
821 OSL_ENSURE( !aFormName.isEmpty(),
"VbaUserForm::importForm - missing form name" );
822 OSL_ENSURE( rModuleName.equalsIgnoreAsciiCase( aFormName ),
"VbaUserForm::importFrameStream - form and module name mismatch" );
823 if( aFormName.isEmpty() )
824 aFormName = rModuleName;
825 if( aFormName.isEmpty() )
828 mxSiteModel->importProperty( XML_Name, aFormName );
832 OUString aKey, aValue;
833 bool bExitLoop =
false;
834 while( !bExitLoop && !aFrameTextStrm.
isEof() )
836 aLine = aFrameTextStrm.
readLine().trim();
837 bExitLoop = aLine.equalsIgnoreAsciiCase(
"End" );
840 if( aKey.equalsIgnoreAsciiCase(
"Caption" ) )
841 mxCtrlModel->importProperty( XML_Caption, lclGetQuotedString( aValue ) );
842 else if( aKey.equalsIgnoreAsciiCase(
"Tag" ) )
843 mxSiteModel->importProperty( XML_Tag, lclGetQuotedString( aValue ) );
853 OUString aServiceName =
mxCtrlModel->getServiceName();
854 Reference< XMultiServiceFactory >
xFactory(
mxContext->getServiceManager(), UNO_QUERY_THROW );
855 Reference< XControlModel > xDialogModel(
xFactory->createInstance( aServiceName ), UNO_QUERY_THROW );
856 Reference< XNameContainer > xDialogNC( xDialogModel, UNO_QUERY_THROW );
862 Reference< XInputStreamProvider > xDialogSource( ::xmlscript::exportDialogModel( xDialogNC,
mxContext,
mxDocModel ), UNO_SET_THROW );
863 OSL_ENSURE( !rxDialogLib->hasByName( aFormName ),
"VbaUserForm::importForm - multiple dialogs with equal name" );
constexpr auto convertPointToMm100(N n)
#define COMCTL_GUID_PROGRESSBAR_50
#define COMCTL_GUID_PROGRESSBAR_60
#define COMCTL_GUID_SCROLLBAR_60
static sal_uInt32 decodeUnsigned(std::u16string_view rValue)
Returns the 32-bit unsigned integer value from the passed string (decimal).
void alignToBlock(sal_Int32 nBlockSize, sal_Int64 nAnchorPos)
Seeks the stream forward to a position that is a multiple of the passed block size,...
bool isEof() const
Returns true, if the stream position is invalid (EOF).
virtual sal_Int64 tell() const =0
Implementations return the current stream position, if possible.
virtual void seek(sal_Int64 nPos)=0
Implementations seek the stream to the passed position, if the stream is seekable.
static bool insertByName(const css::uno::Reference< css::container::XNameContainer > &rxNameContainer, const OUString &rName, const css::uno::Any &rObject)
Inserts an object into a name container.
static const VectorType::value_type * getVectorElement(const VectorType &rVector, sal_Int32 nIndex)
Returns the pointer to an existing element of the passed vector, or a null pointer,...
Provides helper functions for colors, device measurement conversion, graphics, and graphic objects ha...
A helper that maps property identifiers to property values.
bool setProperty(sal_Int32 nPropId, Type &&rValue)
Sets the specified property to the passed value.
A wrapper for a UNO property set.
void setProperties(const css::uno::Sequence< OUString > &rPropNames, const css::uno::Sequence< css::uno::Any > &rValues)
Puts the passed properties into the property set.
Template for a map of ref-counted objects with additional accessor functions.
Template for a vector of ref-counted objects with additional accessor functions.
value_type get(sal_Int32 nIndex) const
Returns a reference to the object with the passed index, or 0 on error.
void forEach(FunctorType aFunctor) const
Calls the passed functor for every contained object, automatically skips all elements that are empty ...
void forEachMemWithIndex(FuncType pFunc, ParamType1 aParam1, ParamType2 aParam2) const
Calls the passed member function of ObjType on every contained object.
void forEachMem(FuncType pFunc) const
Calls the passed member function of ObjType on every contained object, automatically skips all elemen...
Base class for storage access implementations.
css::uno::Reference< css::io::XInputStream > openInputStream(const OUString &rStreamName)
Opens and returns the specified input stream from the storage.
StorageRef openSubStorage(const OUString &rStorageName, bool bCreateMissing)
Opens and returns the specified sub storage from the storage.
bool isEof() const
Returns true, if no more text is available in the stream.
OUString readLine()
Reads a text line from the stream.
Import helper to read simple and complex ActiveX form control properties from a binary input stream.
void readIntProperty(DataType &ornValue)
Reads the next integer property value from the stream, if the respective flag in the property mask is...
bool finalizeImport()
Final processing, reads contents of all complex properties.
void readStringProperty(OUString &orValue)
Reads the next string property from the stream, if the respective flag in the property mask is set.
void readPairProperty(AxPairData &orPairData)
Reads the next pair property from the stream, if the respective flag in the property mask is set.
void skipUndefinedProperty()
Has to be called for undefined properties.
void skipStringProperty()
Skips the next string property in the stream, if the respective flag in the property mask is set.
Base class for ActiveX container controls.
virtual bool importBinaryModel(BinaryInputStream &rInStrm) override
Reads the leading structure in the 'f' stream containing the model for this control.
bool importClassTable(BinaryInputStream &rInStrm, AxClassTable &orClassTable)
Reads the class table structure for embedded controls following the own model from the 'f' stream.
virtual void importProperty(sal_Int32 nPropId, const OUString &rValue) override
Allows to set single properties specified by XML token identifier.
Base class for Forms 2.0 controls supporting text formatting.
sal_Int16 getFontHeight() const
Returns the font height in points.
std::vector< sal_uInt32 > mnIDs
void importPageAndMultiPageProperties(BinaryInputStream &rInStrm, sal_Int32 nPages)
std::vector< OUString > maItems
A base class with useful helper functions for something that is able to convert ActiveX and ComCtl fo...
void bindToSources(const css::uno::Reference< css::awt::XControlModel > &rxCtrlModel, const OUString &rCtrlSource, const OUString &rRowSource, sal_Int32 nRefSheet=0) const
Binds the passed control model to the passed data sources.
void convertPosition(PropertyMap &rPropMap, const AxPairData &rPos) const
Converts the passed position in 1/100 mm to UNO properties.
Base class for all models of form controls.
virtual ApiControlType getControlType() const =0
Derived classes return the UNO control type enum value.
sal_uInt32 mnStreamLen
Size of control stream data.
AxPairData maPos
Position in parent container.
void importProperty(sal_Int32 nPropId, const OUString &rValue)
Allows to set single properties specified by XML token identifier.
sal_uInt32 mnFlags
Various flags.
sal_uInt16 mnGroupId
Group identifier for grouped controls.
sal_Int32 mnId
Control identifier.
OUString maToolTip
Tool tip for the control.
ControlModelRef createControlModel(const AxClassTable &rClassTable) const
Tries to create the control model according to the site model.
sal_Int32 mnHelpContextId
Help context identifier.
OUString maRowSource
Source data for the control in a spreadsheet.
sal_uInt32 getStreamLength() const
Returns the length of the stream data for stream based controls.
OUString maTag
User defined tag.
sal_uInt16 mnClassIdOrCache
Class name identifier or GUID cache index.
bool isContainer() const
Returns true, if this control is a container control.
void convertProperties(PropertyMap &rPropMap, const ControlConverter &rConv, ApiControlType eCtrlType, sal_Int32 nCtrlIndex) const
Converts all form site properties.
void moveRelative(const AxPairData &rDistance)
Moves the control relative to its current position by the passed distance.
OUString getSubStorageName() const
Returns the name of the substorage for the container control data.
bool importBinaryModel(BinaryInputStream &rInStrm)
Imports the site model data from the passed input stream.
OUString maControlSource
Linked cell for the control value in a spreadsheet.
sal_Int16 mnTabIndex
Tab order index.
OUString maName
Name of the control.
Reference< XSingleServiceFactory > xFactory
#define SAL_WARN(area, stream)
bool extractKeyValue(OUString &rKey, OUString &rValue, std::u16string_view rKeyValue)
Extracts a key/value pair from a string separated by an equality sign.
::std::pair< sal_Int32, sal_Int32 > AxPairData
A pair of integer values as a property.
ApiControlType
Enumerates all UNO API control types supported by these filters.
@ API_CONTROL_PROGRESSBAR
std::shared_ptr< VbaSiteModel > VbaSiteModelRef
std::shared_ptr< ControlModelBase > ControlModelRef
::std::vector< OUString > AxClassTable
::std::vector< OUString > AxArrayString
An array of string values as a property.
std::shared_ptr< StorageBase > StorageRef
bool getFlag(Type nBitField, Type nMask)
Returns true, if at least one of the bits set in nMask is set in nBitField.
o3tl::enumarray< SvxBoxItemLine, sal_uInt16 > aDistance
::std::set< OUString > maCtrlNames
VbaControlNamesSet & mrCtrlNames
std::unique_ptr< char[]> aBuffer