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;
232 return aBuffer.makeStringAndClear();
241 sal_Int32 nTypeIndex =
static_cast< sal_Int32
>(
mnClassIdOrCache & VBA_SITE_INDEXMASK );
246 case VBA_SITE_COMMANDBUTTON: xCtrlModel= std::make_shared<AxCommandButtonModel>();
break;
247 case VBA_SITE_LABEL: xCtrlModel= std::make_shared<AxLabelModel>();
break;
248 case VBA_SITE_IMAGE: xCtrlModel= std::make_shared<AxImageModel>();
break;
249 case VBA_SITE_TOGGLEBUTTON: xCtrlModel= std::make_shared<AxToggleButtonModel>();
break;
250 case VBA_SITE_CHECKBOX: xCtrlModel= std::make_shared<AxCheckBoxModel>();
break;
251 case VBA_SITE_OPTIONBUTTON: xCtrlModel= std::make_shared<AxOptionButtonModel>();
break;
252 case VBA_SITE_TEXTBOX: xCtrlModel= std::make_shared<AxTextBoxModel>();
break;
253 case VBA_SITE_LISTBOX: xCtrlModel= std::make_shared<AxListBoxModel>();
break;
254 case VBA_SITE_COMBOBOX: xCtrlModel= std::make_shared<AxComboBoxModel>();
break;
255 case VBA_SITE_SPINBUTTON: xCtrlModel= std::make_shared<AxSpinButtonModel>();
break;
256 case VBA_SITE_SCROLLBAR: xCtrlModel= std::make_shared<AxScrollBarModel>();
break;
257 case VBA_SITE_TABSTRIP: xCtrlModel= std::make_shared<AxTabStripModel>();
259 case VBA_SITE_FRAME: xCtrlModel= std::make_shared<AxFrameModel>();
break;
260 case VBA_SITE_MULTIPAGE: xCtrlModel= std::make_shared<AxMultiPageModel>();
262 case VBA_SITE_FORM: xCtrlModel= std::make_shared<AxPageModel>();
264 default: OSL_FAIL(
"VbaSiteModel::createControlModel - unknown type index" );
270 OSL_ENSURE( pGuid,
"VbaSiteModel::createControlModel - invalid class table index" );
274 xCtrlModel = std::make_shared<ComCtlScrollBarModel>( 6 );
276 xCtrlModel = std::make_shared<ComCtlProgressBarModel>( 5 );
278 xCtrlModel = std::make_shared<ComCtlProgressBarModel>( 6 );
285 xCtrlModel->setAwtModelMode();
288 bool bModelIsContainer =
dynamic_cast< const AxContainerModelBase*
>( xCtrlModel.get() ) !=
nullptr;
289 bool bTypeMatch = bModelIsContainer ==
isContainer();
290 OSL_ENSURE( bTypeMatch,
"VbaSiteModel::createControlModel - container type does not match container flag" );
309 rPropMap.
setProperty( PROP_TabIndex,
static_cast< sal_Int16
>( nCtrlIndex ) );
333 OSL_ENSURE( xSubStrg,
"VbaFormControl::importModelOrStorage - cannot find storage for embedded control" );
337 else if( !rInStrm.
isEof() )
339 sal_Int64 nNextStrmPos = rInStrm.
tell() +
mxSiteModel->getStreamLength();
341 rInStrm.
seek( nNextStrmPos );
351 const Reference< XNameContainer >& rxParentNC,
const ControlConverter& rConv )
const
359 OUString aServiceName =
mxCtrlModel->getServiceName();
360 Reference< XMultiServiceFactory > xModelFactory( rxParentNC, UNO_QUERY_THROW );
361 Reference< XControlModel > xCtrlModel( xModelFactory->createInstance( aServiceName ), UNO_QUERY_THROW );
367 const OUString& rCtrlName =
mxSiteModel->getName();
368 OSL_ENSURE( !rxParentNC->hasByName( rCtrlName ),
"VbaFormControl::createAndConvert - multiple controls with equal name" );
390 OSL_ENSURE( pContainerModel,
"VbaFormControl::importStorage - missing container control model" );
391 if( !pContainerModel )
397 OSL_ENSURE( !aFStrm.
isEof(),
"VbaFormControl::importStorage - missing 'f' stream" );
418 ::std::ref( aOStrm ), ::std::ref( rStrg ), ::std::cref(
maClassTable ) );
430 typedef std::unordered_map< sal_uInt32, std::shared_ptr< VbaFormControl > > IdToPageMap;
431 IdToPageMap idToPage;
436 auto& elem = control->mxCtrlModel;
439 SAL_WARN(
"oox",
"empty control model");
446 idToPage[ xPageSiteRef->getId() ] = control;
451 sCaptions = pTabStrip->
maItems;
457 SAL_WARN(
"oox",
"unexpected control type " << elem->getControlType());
464 if ( sCaptions.size() == idToPage.size() )
466 AxArrayString::iterator itCaption = sCaptions.begin();
467 for (
const auto& rCtrlId : pMultiPage->
mnIDs )
469 IdToPageMap::iterator iter = idToPage.find( rCtrlId );
470 if ( iter != idToPage.end() )
493 const OUString& rCtrlName =
mxSiteModel->getName();
494 OSL_ENSURE( !rCtrlName.isEmpty(),
"VbaFormControl::convertProperties - control without name" );
495 if( !rCtrlName.isEmpty() )
509 Reference< XNameContainer > xCtrlModelNC( rxCtrlModel, UNO_QUERY_THROW );
513 ::std::cref( xCtrlModelNC ), ::std::cref( rConv ) );
517 OSL_FAIL(
"VbaFormControl::convertProperties - cannot get control container interface" );
543 sal_uInt64 nAnchorPos = rInStrm.
tell();
544 sal_uInt32 nSiteCount, nSiteDataSize;
547 sal_Int64 nSiteEndPos = rInStrm.
tell() + nSiteDataSize;
550 sal_uInt32 nSiteIndex = 0;
551 while( !rInStrm.
isEof() && (nSiteIndex < nSiteCount) )
555 if(
getFlag( nTypeCount, VBA_SITEINFO_COUNT ) )
562 nSiteIndex += (nTypeCount & VBA_SITEINFO_MASK);
577 bool bValid = !rInStrm.
isEof();
578 for( nSiteIndex = 0; bValid && (nSiteIndex < nSiteCount); ++nSiteIndex )
582 bValid = xControl->importSiteModel( rInStrm );
585 rInStrm.
seek( nSiteEndPos );
606 VbaControlNamesSet aControlNames;
607 VbaControlNameInserter aInserter( aControlNames );
611 control->maControls.forEach( aInserter );
621 VbaFormControlVectorVector aControlGroups;
624 VbaFormControlVectorMap aOptionGroups;
626 typedef VbaFormControlVectorMap::mapped_type VbaFormControlVectorRef;
627 bool bLastWasOptionButton =
false;
635 const OUString& rGroupName = pOptButtonModel->getGroupName();
636 VbaFormControlVectorRef& rxOptionGroup = aOptionGroups[ rGroupName ];
642 if( bLastWasOptionButton )
644 VbaFormControlVectorRef xDummyGroup = std::make_shared<VbaFormControlVector>();
645 aControlGroups.push_back( xDummyGroup );
646 OUString
aName = aControlNames.generateDummyName();
648 xDummyGroup->push_back( xDummyControl );
650 rxOptionGroup = std::make_shared<VbaFormControlVector>();
651 aControlGroups.push_back( rxOptionGroup );
656 rxOptionGroup->push_back(control);
657 bLastWasOptionButton =
true;
662 if( bLastWasOptionButton || aControlGroups.empty() )
664 VbaFormControlVectorRef xControlGroup = std::make_shared<VbaFormControlVector>();
665 aControlGroups.push_back( xControlGroup );
669 rLastGroup.push_back(control);
670 bLastWasOptionButton =
false;
677 control->moveEmbeddedToAbsoluteParent();
680 rLastGroup.insert( rLastGroup.end(), control->maControls.begin(), control->maControls.end() );
681 control->maControls.clear();
683 bLastWasOptionButton =
dynamic_cast< const AxOptionButtonModel*
>( rLastGroup.back()->mxCtrlModel.
get() ) !=
nullptr;
690 for (
auto const& controlGroup : aControlGroups)
724 sal_Int32 nLeftTabIndex = rxLeft->mxSiteModel ? rxLeft->mxSiteModel->getTabIndex() :
SAL_MAX_INT32;
725 sal_Int32 nRightTabIndex = rxRight->mxSiteModel ? rxRight->mxSiteModel->getTabIndex() :
SAL_MAX_INT32;
726 return nLeftTabIndex < nRightTabIndex;
731OUString lclGetQuotedString( std::u16string_view rCodeLine )
734 size_t nLen = rCodeLine.size();
735 if( (nLen > 0) && (rCodeLine[ 0 ] ==
'"') )
737 bool bExitLoop =
false;
738 for(
size_t nIndex = 1; !bExitLoop && (
nIndex < nLen); ++
nIndex )
742 bExitLoop = (cChar ==
'"') && ((nIndex + 1 == nLen) || (rCodeLine[
nIndex + 1 ] !=
'"'));
752 return aBuffer.makeStringAndClear();
755bool lclEatWhitespace( OUString& rCodeLine )
758 while( (nIndex < rCodeLine.getLength()) && ((rCodeLine[ nIndex ] ==
' ') || (rCodeLine[ nIndex ] ==
'\t')) )
762 rCodeLine = rCodeLine.copy( nIndex );
768bool lclEatKeyword( OUString& rCodeLine, std::u16string_view rKeyword )
770 if( rCodeLine.matchIgnoreAsciiCase( rKeyword ) )
772 rCodeLine = rCodeLine.copy( rKeyword.size() );
774 return rCodeLine.isEmpty() || lclEatWhitespace( rCodeLine );
782 const Reference< XModel >& rxDocModel,
const GraphicHelper& rGraphicHelper,
bool bDefaultColorBgr ) :
784 mxDocModel( rxDocModel ),
785 maConverter( rxDocModel, rGraphicHelper, bDefaultColorBgr )
787 OSL_ENSURE(
mxContext.is(),
"VbaUserForm::VbaUserForm - missing component context" );
788 OSL_ENSURE(
mxDocModel.is(),
"VbaUserForm::VbaUserForm - missing document model" );
792 StorageBase& rVbaFormStrg,
const OUString& rModuleName, rtl_TextEncoding eTextEnc )
794 OSL_ENSURE( rxDialogLib.is(),
"VbaUserForm::importForm - missing dialog library" );
800 OSL_ENSURE( !aInStrm.
isEof(),
"VbaUserForm::importForm - missing \\003VBFrame stream" );
801 if( aInStrm.
isEof() )
806 static constexpr OUStringLiteral aBegin =
u"Begin";
808 bool bBeginFound =
false;
809 while( !bBeginFound && !aFrameTextStrm.
isEof() )
811 aLine = aFrameTextStrm.
readLine().trim();
812 bBeginFound = lclEatKeyword( aLine, aBegin );
815 if( !bBeginFound || !lclEatKeyword( aLine,
u"{C62A69F0-16DC-11CE-9E98-00AA00574A4F}" ) )
819 OUString aFormName = aLine.trim();
820 OSL_ENSURE( !aFormName.isEmpty(),
"VbaUserForm::importForm - missing form name" );
821 OSL_ENSURE( rModuleName.equalsIgnoreAsciiCase( aFormName ),
"VbaUserForm::importFrameStream - form and module name mismatch" );
822 if( aFormName.isEmpty() )
823 aFormName = rModuleName;
824 if( aFormName.isEmpty() )
827 mxSiteModel->importProperty( XML_Name, aFormName );
831 OUString aKey, aValue;
832 bool bExitLoop =
false;
833 while( !bExitLoop && !aFrameTextStrm.
isEof() )
835 aLine = aFrameTextStrm.
readLine().trim();
836 bExitLoop = aLine.equalsIgnoreAsciiCase(
"End" );
839 if( aKey.equalsIgnoreAsciiCase(
"Caption" ) )
840 mxCtrlModel->importProperty( XML_Caption, lclGetQuotedString( aValue ) );
841 else if( aKey.equalsIgnoreAsciiCase(
"Tag" ) )
842 mxSiteModel->importProperty( XML_Tag, lclGetQuotedString( aValue ) );
852 OUString aServiceName =
mxCtrlModel->getServiceName();
853 Reference< XMultiServiceFactory >
xFactory(
mxContext->getServiceManager(), UNO_QUERY_THROW );
854 Reference< XControlModel > xDialogModel(
xFactory->createInstance( aServiceName ), UNO_QUERY_THROW );
855 Reference< XNameContainer > xDialogNC( xDialogModel, UNO_QUERY_THROW );
861 Reference< XInputStreamProvider > xDialogSource( ::xmlscript::exportDialogModel( xDialogNC,
mxContext,
mxDocModel ), UNO_SET_THROW );
862 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