LibreOffice Module oox (master) 1
vbacontrol.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
21
22#include <algorithm>
23#include <set>
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>
32#include <sal/log.hxx>
42#include <oox/ole/vbahelper.hxx>
43#include <oox/token/properties.hxx>
44#include <oox/token/tokens.hxx>
45#include <unordered_map>
46
47namespace oox::ole {
48
49using namespace ::com::sun::star::awt;
50using namespace ::com::sun::star::container;
51using namespace ::com::sun::star::frame;
52using namespace ::com::sun::star::io;
53using namespace ::com::sun::star::lang;
54using namespace ::com::sun::star::uno;
55
56namespace {
57
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;
76
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;
81
82const sal_uInt8 VBA_SITEINFO_COUNT = 0x80;
83const sal_uInt8 VBA_SITEINFO_MASK = 0x7F;
84
88class VbaControlNamesSet
89{
90public:
91 explicit VbaControlNamesSet();
92
94 void insertName( const VbaFormControl& rControl );
96 OUString generateDummyName();
97
98private:
99 ::std::set< OUString >
101 sal_Int32 mnIndex;
102};
103
104constexpr OUStringLiteral gaDummyBaseName( u"DummyGroupSep" );
105
106VbaControlNamesSet::VbaControlNamesSet() :
107 mnIndex( 0 )
108{
109}
110
111void VbaControlNamesSet::insertName( const VbaFormControl& rControl )
112{
113 OUString aName = rControl.getControlName();
114 if( !aName.isEmpty() )
115 maCtrlNames.insert( aName );
116}
117
118OUString VbaControlNamesSet::generateDummyName()
119{
120 OUString aCtrlName;
121 do
122 {
123 aCtrlName = gaDummyBaseName + OUString::number( ++mnIndex );
124 }
125 while( maCtrlNames.count( aCtrlName ) > 0 );
126 maCtrlNames.insert( aCtrlName );
127 return aCtrlName;
128}
129
131struct VbaControlNameInserter
132{
133public:
134 VbaControlNamesSet& mrCtrlNames;
135 explicit VbaControlNameInserter( VbaControlNamesSet& rCtrlNames ) : mrCtrlNames( rCtrlNames ) {}
136 void operator()( const VbaFormControl& rControl ) { mrCtrlNames.insertName( rControl ); }
137};
138
142class VbaDummyFormControl : public VbaFormControl
143{
144public:
145 explicit VbaDummyFormControl( const OUString& rName );
146};
147
148VbaDummyFormControl::VbaDummyFormControl( const OUString& rName )
149{
150 mxSiteModel = std::make_shared<VbaSiteModel>();
151 mxSiteModel->importProperty( XML_Name, rName );
152 mxSiteModel->importProperty( XML_VariousPropertyBits, OUString( '0' ) );
153
154 mxCtrlModel = std::make_shared<AxLabelModel>();
155 mxCtrlModel->setAwtModelMode();
156 mxCtrlModel->importProperty( XML_Size, "10;10" );
157}
158
159} // namespace
160
161VbaSiteModel::VbaSiteModel() :
162 maPos( 0, 0 ),
163 mnId( 0 ),
164 mnHelpContextId( 0 ),
165 mnFlags( VBA_SITE_DEFFLAGS ),
166 mnStreamLen( 0 ),
167 mnTabIndex( -1 ),
168 mnClassIdOrCache( VBA_SITE_UNKNOWN ),
169 mnGroupId( 0 )
170{
171}
172
174{
175}
176
177void VbaSiteModel::importProperty( sal_Int32 nPropId, const OUString& rValue )
178{
179 switch( nPropId )
180 {
181 case XML_Name: maName = rValue; break;
182 case XML_Tag: maTag = rValue; break;
183 case XML_VariousPropertyBits: mnFlags = AttributeConversion::decodeUnsigned( rValue ); break;
184 }
185}
186
188{
189 AxBinaryPropertyReader aReader( rInStrm );
190 aReader.readStringProperty( maName );
191 aReader.readStringProperty( maTag );
192 aReader.readIntProperty< sal_Int32 >( mnId );
193 aReader.readIntProperty< sal_Int32 >( mnHelpContextId );
194 aReader.readIntProperty< sal_uInt32 >( mnFlags );
195 aReader.readIntProperty< sal_uInt32 >( mnStreamLen );
196 aReader.readIntProperty< sal_Int16 >( mnTabIndex );
197 aReader.readIntProperty< sal_uInt16 >( mnClassIdOrCache );
198 aReader.readPairProperty( maPos );
199 aReader.readIntProperty< sal_uInt16 >( mnGroupId );
200 aReader.skipUndefinedProperty();
201 aReader.readStringProperty( maToolTip );
202 aReader.skipStringProperty(); // license key
205 return aReader.finalizeImport();
206}
207
209{
210 maPos.first += rDistance.first;
211 maPos.second += rDistance.second;
212}
213
215{
216 return !getFlag( mnFlags, VBA_SITE_OSTREAM );
217}
218
220{
221 return isContainer() ? 0 : mnStreamLen;
222}
223
225{
226 if( mnId >= 0 )
227 {
228 OUStringBuffer aBuffer;
229 aBuffer.append( 'i' );
230 if( mnId < 10 )
231 aBuffer.append( '0' );
232 aBuffer.append( mnId );
233 return aBuffer.makeStringAndClear();
234 }
235 return OUString();
236}
237
239{
240 ControlModelRef xCtrlModel;
241
242 sal_Int32 nTypeIndex = static_cast< sal_Int32 >( mnClassIdOrCache & VBA_SITE_INDEXMASK );
243 if( !getFlag( mnClassIdOrCache, VBA_SITE_CLASSIDINDEX ) )
244 {
245 switch( nTypeIndex )
246 {
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>();
259 break;
260 case VBA_SITE_FRAME: xCtrlModel= std::make_shared<AxFrameModel>(); break;
261 case VBA_SITE_MULTIPAGE: xCtrlModel= std::make_shared<AxMultiPageModel>();
262 break;
263 case VBA_SITE_FORM: xCtrlModel= std::make_shared<AxPageModel>();
264 break;
265 default: OSL_FAIL( "VbaSiteModel::createControlModel - unknown type index" );
266 }
267 }
268 else
269 {
270 const OUString* pGuid = ContainerHelper::getVectorElement( rClassTable, nTypeIndex );
271 OSL_ENSURE( pGuid, "VbaSiteModel::createControlModel - invalid class table index" );
272 if( pGuid )
273 {
274 if( *pGuid == COMCTL_GUID_SCROLLBAR_60 )
275 xCtrlModel = std::make_shared<ComCtlScrollBarModel>( 6 );
276 else if( *pGuid == COMCTL_GUID_PROGRESSBAR_50 )
277 xCtrlModel = std::make_shared<ComCtlProgressBarModel>( 5 );
278 else if( *pGuid == COMCTL_GUID_PROGRESSBAR_60 )
279 xCtrlModel = std::make_shared<ComCtlProgressBarModel>( 6 );
280 }
281 }
282
283 if( xCtrlModel )
284 {
285 // user form controls are AWT models
286 xCtrlModel->setAwtModelMode();
287
288 // check that container model matches container flag in site data
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" );
292 if( !bTypeMatch )
293 xCtrlModel.reset();
294 }
295 return xCtrlModel;
296}
297
299 const ControlConverter& rConv, ApiControlType eCtrlType, sal_Int32 nCtrlIndex ) const
300{
301 rPropMap.setProperty( PROP_Name, maName );
302 rPropMap.setProperty( PROP_Tag, maTag );
303
304 if( eCtrlType != API_CONTROL_DIALOG )
305 {
306 rPropMap.setProperty( PROP_HelpText, maToolTip );
307 rPropMap.setProperty( PROP_EnableVisible, getFlag( mnFlags, VBA_SITE_VISIBLE ) );
308 // we need to set the passed control index to make option button groups work
309 if( (0 <= nCtrlIndex) && (nCtrlIndex <= SAL_MAX_INT16) )
310 rPropMap.setProperty( PROP_TabIndex, static_cast< sal_Int16 >( nCtrlIndex ) );
311 // progress bar and group box support TabIndex, but not Tabstop...
312 if( (eCtrlType != API_CONTROL_PROGRESSBAR) && (eCtrlType != API_CONTROL_GROUPBOX) && (eCtrlType != API_CONTROL_FRAME) && (eCtrlType != API_CONTROL_PAGE) )
313 rPropMap.setProperty( PROP_Tabstop, getFlag( mnFlags, VBA_SITE_TABSTOP ) );
314 rConv.convertPosition( rPropMap, maPos );
315 }
316}
317
319{
320}
321
323{
324}
325
327{
328 if( !mxSiteModel )
329 return;
330
331 if( mxSiteModel->isContainer() )
332 {
333 StorageRef xSubStrg = rStrg.openSubStorage( mxSiteModel->getSubStorageName(), false );
334 OSL_ENSURE( xSubStrg, "VbaFormControl::importModelOrStorage - cannot find storage for embedded control" );
335 if( xSubStrg )
336 importStorage( *xSubStrg, rClassTable );
337 }
338 else if( !rInStrm.isEof() )
339 {
340 sal_Int64 nNextStrmPos = rInStrm.tell() + mxSiteModel->getStreamLength();
341 importControlModel( rInStrm, rClassTable );
342 rInStrm.seek( nNextStrmPos );
343 }
344}
345
347{
348 return mxSiteModel ? mxSiteModel->getName() : OUString();
349}
350
351void VbaFormControl::createAndConvert( sal_Int32 nCtrlIndex,
352 const Reference< XNameContainer >& rxParentNC, const ControlConverter& rConv ) const
353{
354 if( !(rxParentNC.is() && mxSiteModel && mxCtrlModel) )
355 return;
356
357 try
358 {
359 // create the control model
360 OUString aServiceName = mxCtrlModel->getServiceName();
361 Reference< XMultiServiceFactory > xModelFactory( rxParentNC, UNO_QUERY_THROW );
362 Reference< XControlModel > xCtrlModel( xModelFactory->createInstance( aServiceName ), UNO_QUERY_THROW );
363
364 // convert all properties and embedded controls
365 if( convertProperties( xCtrlModel, rConv, nCtrlIndex ) )
366 {
367 // insert into parent container
368 const OUString& rCtrlName = mxSiteModel->getName();
369 OSL_ENSURE( !rxParentNC->hasByName( rCtrlName ), "VbaFormControl::createAndConvert - multiple controls with equal name" );
370 ContainerHelper::insertByName( rxParentNC, rCtrlName, Any( xCtrlModel ) );
371 }
372 }
373 catch(const Exception& )
374 {
375 }
376}
377
378// protected ------------------------------------------------------------------
379
381{
382 createControlModel( rClassTable );
383 if( mxCtrlModel )
384 mxCtrlModel->importBinaryModel( rInStrm );
385}
386
388{
389 createControlModel( rClassTable );
390 AxContainerModelBase* pContainerModel = dynamic_cast< AxContainerModelBase* >( mxCtrlModel.get() );
391 OSL_ENSURE( pContainerModel, "VbaFormControl::importStorage - missing container control model" );
392 if( !pContainerModel )
393 return;
394
395 /* Open the 'f' stream containing the model of this control and a list
396 of site models for all child controls. */
397 BinaryXInputStream aFStrm( rStrg.openInputStream( "f" ), true );
398 OSL_ENSURE( !aFStrm.isEof(), "VbaFormControl::importStorage - missing 'f' stream" );
399
400 /* Read the properties of this container control and the class table
401 (into the maClassTable vector) containing a list of GUIDs for
402 exotic embedded controls. */
403 if( !(!aFStrm.isEof() && pContainerModel->importBinaryModel( aFStrm ) && pContainerModel->importClassTable( aFStrm, maClassTable )) )
404 return;
405
406 /* Read the site models of all embedded controls (this fills the
407 maControls vector). Ignore failure of importSiteModels() but
408 try to import as much controls as possible. */
409 importEmbeddedSiteModels( aFStrm );
410 /* Open the 'o' stream containing models of embedded simple
411 controls. Stream may be empty or missing, if this control
412 contains no controls or only container controls. */
413 BinaryXInputStream aOStrm( rStrg.openInputStream( "o" ), true );
414
415 /* Iterate over all embedded controls, import model from 'o'
416 stream (for embedded simple controls) or from the substorage
417 (for embedded container controls). */
419 ::std::ref( aOStrm ), ::std::ref( rStrg ), ::std::cref( maClassTable ) );
420
421 // Special handling for multi-page which has non-standard
422 // containment and additionally needs to re-order Page children
423 if ( pContainerModel->getControlType() == API_CONTROL_MULTIPAGE )
424 {
425 AxMultiPageModel* pMultiPage = dynamic_cast< AxMultiPageModel* >( pContainerModel );
426 assert(pMultiPage);
427 {
428 BinaryXInputStream aXStrm( rStrg.openInputStream( "x" ), true );
429 pMultiPage->importPageAndMultiPageProperties( aXStrm, maControls.size() );
430 }
431 typedef std::unordered_map< sal_uInt32, std::shared_ptr< VbaFormControl > > IdToPageMap;
432 IdToPageMap idToPage;
433 AxArrayString sCaptions;
434
435 for (auto const& control : maControls)
436 {
437 auto& elem = control->mxCtrlModel;
438 if (!elem)
439 {
440 SAL_WARN("oox", "empty control model");
441 continue;
442 }
443 if (elem->getControlType() == API_CONTROL_PAGE)
444 {
445 VbaSiteModelRef xPageSiteRef = control->mxSiteModel;
446 if ( xPageSiteRef )
447 idToPage[ xPageSiteRef->getId() ] = control;
448 }
449 else if (elem->getControlType() == API_CONTROL_TABSTRIP)
450 {
451 AxTabStripModel* pTabStrip = static_cast<AxTabStripModel*>(elem.get());
452 sCaptions = pTabStrip->maItems;
453 pMultiPage->mnActiveTab = pTabStrip->mnListIndex;
454 pMultiPage->mnTabStyle = pTabStrip->mnTabStyle;
455 }
456 else
457 {
458 SAL_WARN("oox", "unexpected control type " << elem->getControlType());
459 }
460 }
461 // apply caption/titles to pages
462
463 maControls.clear();
464 // need to sort the controls according to the order of the ids
465 if ( sCaptions.size() == idToPage.size() )
466 {
467 AxArrayString::iterator itCaption = sCaptions.begin();
468 for ( const auto& rCtrlId : pMultiPage->mnIDs )
469 {
470 IdToPageMap::iterator iter = idToPage.find( rCtrlId );
471 if ( iter != idToPage.end() )
472 {
473 AxPageModel* pPage = static_cast<AxPageModel*> ( iter->second->mxCtrlModel.get() );
474
475 pPage->importProperty( XML_Caption, *itCaption );
476 maControls.push_back( iter->second );
477 }
478 ++itCaption;
479 }
480 }
481 }
482 /* Reorder the controls (sorts all option buttons of an option
483 group together), and move all children of all embedded frames
484 (group boxes) to this control (UNO group boxes cannot contain
485 other controls). */
487}
488
489bool VbaFormControl::convertProperties( const Reference< XControlModel >& rxCtrlModel,
490 const ControlConverter& rConv, sal_Int32 nCtrlIndex ) const
491{
492 if( rxCtrlModel.is() && mxSiteModel && mxCtrlModel )
493 {
494 const OUString& rCtrlName = mxSiteModel->getName();
495 OSL_ENSURE( !rCtrlName.isEmpty(), "VbaFormControl::convertProperties - control without name" );
496 if( !rCtrlName.isEmpty() )
497 {
498 // convert all properties
499 PropertyMap aPropMap;
500 mxSiteModel->convertProperties( aPropMap, rConv, mxCtrlModel->getControlType(), nCtrlIndex );
501 rConv.bindToSources( rxCtrlModel, mxSiteModel->getControlSource(), mxSiteModel->getRowSource() );
502 mxCtrlModel->convertProperties( aPropMap, rConv );
503 mxCtrlModel->convertSize( aPropMap, rConv );
504 PropertySet aPropSet( rxCtrlModel );
505 aPropSet.setProperties( aPropMap );
506
507 // create and convert all embedded controls
508 if( !maControls.empty() ) try
509 {
510 Reference< XNameContainer > xCtrlModelNC( rxCtrlModel, UNO_QUERY_THROW );
511 /* Call conversion for all controls. Pass vector index as new
512 tab order to make option button groups work correctly. */
514 ::std::cref( xCtrlModelNC ), ::std::cref( rConv ) );
515 }
516 catch(const Exception& )
517 {
518 OSL_FAIL( "VbaFormControl::convertProperties - cannot get control container interface" );
519 }
520
521 return true;
522 }
523 }
524 return false;
525}
526
527// private --------------------------------------------------------------------
528
530{
531 // derived classes may have created their own control model
532 if( !mxCtrlModel && mxSiteModel )
533 mxCtrlModel = mxSiteModel->createControlModel( rClassTable );
534}
535
537{
538 mxSiteModel = std::make_shared<VbaSiteModel>();
539 return mxSiteModel->importBinaryModel( rInStrm );
540}
541
543{
544 sal_uInt64 nAnchorPos = rInStrm.tell();
545 sal_uInt32 nSiteCount, nSiteDataSize;
546 nSiteCount = rInStrm.readuInt32();
547 nSiteDataSize = rInStrm.readuInt32();
548 sal_Int64 nSiteEndPos = rInStrm.tell() + nSiteDataSize;
549
550 // skip the site info structure
551 sal_uInt32 nSiteIndex = 0;
552 while( !rInStrm.isEof() && (nSiteIndex < nSiteCount) )
553 {
554 rInStrm.skip( 1 ); // site depth
555 sal_uInt8 nTypeCount = rInStrm.readuInt8(); // 'type-or-count' byte
556 if( getFlag( nTypeCount, VBA_SITEINFO_COUNT ) )
557 {
558 /* Count flag is set: the 'type-or-count' byte contains the number
559 of controls in the lower bits, the type specifier follows in
560 the next byte. The type specifier should always be 1 according
561 to the specification. */
562 rInStrm.skip( 1 );
563 nSiteIndex += (nTypeCount & VBA_SITEINFO_MASK);
564 }
565 else
566 {
567 /* Count flag is not set: the 'type-or-count' byte contains the
568 type specifier of *one* control in the lower bits (this type
569 should be 1, see above). */
570 ++nSiteIndex;
571 }
572 }
573 // align the stream to 32bit, relative to start of entire site info
574 rInStrm.alignToBlock( 4, nAnchorPos );
575
576 // import the site models for all embedded controls
577 maControls.clear();
578 bool bValid = !rInStrm.isEof();
579 for( nSiteIndex = 0; bValid && (nSiteIndex < nSiteCount); ++nSiteIndex )
580 {
581 VbaFormControlRef xControl = std::make_shared<VbaFormControl>();
582 maControls.push_back( xControl );
583 bValid = xControl->importSiteModel( rInStrm );
584 }
585
586 rInStrm.seek( nSiteEndPos );
587}
588
590{
591 /* This function performs two tasks:
592
593 1) Reorder the controls appropriately (sort all option buttons of an
594 option group together to make grouping work).
595 2) Move all children of all embedded frames (group boxes) to this
596 control (UNO group boxes cannot contain other controls).
597 */
598
599 // first, sort all controls by original tab index
600 ::std::sort( maControls.begin(), maControls.end(), &compareByTabIndex );
601
602 /* Collect the programmatical names of all embedded controls (needed to be
603 able to set unused names to new dummy controls created below). Also
604 collect the names of all children of embedded frames (group boxes).
605 Luckily, names of controls must be unique in the entire form, not just
606 in the current container. */
607 VbaControlNamesSet aControlNames;
608 VbaControlNameInserter aInserter( aControlNames );
609 maControls.forEach( aInserter );
610 for (auto const& control : maControls)
611 if( control->mxCtrlModel && (control->mxCtrlModel->getControlType() == API_CONTROL_GROUPBOX) )
612 control->maControls.forEach( aInserter );
613
614 /* Reprocess the sorted list and collect all option button controls that
615 are part of the same option group (determined by group name). All
616 controls will be stored in a vector of vectors, that collects every
617 option button group in one vector element, and other controls between
618 these option groups (or leading or trailing controls) in other vector
619 elements. If an option button group follows another group, a dummy
620 separator control has to be inserted. */
621 typedef RefVector< VbaFormControlVector > VbaFormControlVectorVector;
622 VbaFormControlVectorVector aControlGroups;
623
624 typedef RefMap< OUString, VbaFormControlVector > VbaFormControlVectorMap;
625 VbaFormControlVectorMap aOptionGroups;
626
627 typedef VbaFormControlVectorMap::mapped_type VbaFormControlVectorRef;
628 bool bLastWasOptionButton = false;
629 for (auto const& control : maControls)
630 {
631 const ControlModelBase* pCtrlModel = control->mxCtrlModel.get();
632
633 if( const AxOptionButtonModel* pOptButtonModel = dynamic_cast< const AxOptionButtonModel* >( pCtrlModel ) )
634 {
635 // check if a new option group needs to be created
636 const OUString& rGroupName = pOptButtonModel->getGroupName();
637 VbaFormControlVectorRef& rxOptionGroup = aOptionGroups[ rGroupName ];
638 if( !rxOptionGroup )
639 {
640 /* If last control was an option button too, we have two
641 option groups following each other, so a dummy separator
642 control is needed. */
643 if( bLastWasOptionButton )
644 {
645 VbaFormControlVectorRef xDummyGroup = std::make_shared<VbaFormControlVector>();
646 aControlGroups.push_back( xDummyGroup );
647 OUString aName = aControlNames.generateDummyName();
648 VbaFormControlRef xDummyControl = std::make_shared<VbaDummyFormControl>( aName );
649 xDummyGroup->push_back( xDummyControl );
650 }
651 rxOptionGroup = std::make_shared<VbaFormControlVector>();
652 aControlGroups.push_back( rxOptionGroup );
653 }
654 /* Append the option button to the control group (which is now
655 referred by the vector aControlGroups and by the map
656 aOptionGroups). */
657 rxOptionGroup->push_back(control);
658 bLastWasOptionButton = true;
659 }
660 else
661 {
662 // open a new control group, if the last group is an option group
663 if( bLastWasOptionButton || aControlGroups.empty() )
664 {
665 VbaFormControlVectorRef xControlGroup = std::make_shared<VbaFormControlVector>();
666 aControlGroups.push_back( xControlGroup );
667 }
668 // append the control to the last control group
669 VbaFormControlVector& rLastGroup = *aControlGroups.back();
670 rLastGroup.push_back(control);
671 bLastWasOptionButton = false;
672
673 // if control is a group box, move all its children to this control
674 if( pCtrlModel && (pCtrlModel->getControlType() == API_CONTROL_GROUPBOX) )
675 {
676 /* Move all embedded controls of the group box relative to the
677 position of the group box. */
678 control->moveEmbeddedToAbsoluteParent();
679 /* Insert all children of the group box into the last control
680 group (following the group box). */
681 rLastGroup.insert( rLastGroup.end(), control->maControls.begin(), control->maControls.end() );
682 control->maControls.clear();
683 // check if last control of the group box is an option button
684 bLastWasOptionButton = dynamic_cast< const AxOptionButtonModel* >( rLastGroup.back()->mxCtrlModel.get() ) != nullptr;
685 }
686 }
687 }
688
689 // flatten the vector of vectors of form controls to a single vector
690 maControls.clear();
691 for (auto const& controlGroup : aControlGroups)
692 maControls.insert( maControls.end(), controlGroup->begin(), controlGroup->end() );
693}
694
696{
697 if( mxSiteModel )
698 mxSiteModel->moveRelative( rDistance );
699}
700
702{
703 if( !mxSiteModel || maControls.empty() )
704 return;
705
706 // distance to move is equal to position of this control in its parent
707 AxPairData aDistance = mxSiteModel->getPosition();
708
709 /* For group boxes: add half of the font height to Y position (VBA
710 positions relative to frame border line, not to 'top' of frame). */
711 const AxFontDataModel* pFontModel = dynamic_cast< const AxFontDataModel* >( mxCtrlModel.get() );
712 if( pFontModel && (pFontModel->getControlType() == API_CONTROL_GROUPBOX) )
713 {
714 sal_Int32 nFontHeight = convertPointToMm100(pFontModel->getFontHeight());
715 aDistance.second += nFontHeight / 2;
716 }
717
718 // move the embedded controls
720}
721
723{
724 // sort controls without model to the end
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;
728}
729
730namespace {
731
732OUString lclGetQuotedString( std::u16string_view rCodeLine )
733{
734 OUStringBuffer aBuffer;
735 size_t nLen = rCodeLine.size();
736 if( (nLen > 0) && (rCodeLine[ 0 ] == '"') )
737 {
738 bool bExitLoop = false;
739 for( size_t nIndex = 1; !bExitLoop && (nIndex < nLen); ++nIndex )
740 {
741 sal_Unicode cChar = rCodeLine[ nIndex ];
742 // exit on closing quote char (but check on double quote chars)
743 bExitLoop = (cChar == '"') && ((nIndex + 1 == nLen) || (rCodeLine[ nIndex + 1 ] != '"'));
744 if( !bExitLoop )
745 {
746 aBuffer.append( cChar );
747 // skip second quote char
748 if( cChar == '"' )
749 ++nIndex;
750 }
751 }
752 }
753 return aBuffer.makeStringAndClear();
754}
755
756bool lclEatWhitespace( OUString& rCodeLine )
757{
758 sal_Int32 nIndex = 0;
759 while( (nIndex < rCodeLine.getLength()) && ((rCodeLine[ nIndex ] == ' ') || (rCodeLine[ nIndex ] == '\t')) )
760 ++nIndex;
761 if( nIndex > 0 )
762 {
763 rCodeLine = rCodeLine.copy( nIndex );
764 return true;
765 }
766 return false;
767}
768
769bool lclEatKeyword( OUString& rCodeLine, std::u16string_view rKeyword )
770{
771 if( rCodeLine.matchIgnoreAsciiCase( rKeyword ) )
772 {
773 rCodeLine = rCodeLine.copy( rKeyword.size() );
774 // success, if code line ends after keyword, or if whitespace follows
775 return rCodeLine.isEmpty() || lclEatWhitespace( rCodeLine );
776 }
777 return false;
778}
779
780} // namespace
781
782VbaUserForm::VbaUserForm( const Reference< XComponentContext >& rxContext,
783 const Reference< XModel >& rxDocModel, const GraphicHelper& rGraphicHelper, bool bDefaultColorBgr ) :
784 mxContext( rxContext ),
785 mxDocModel( rxDocModel ),
786 maConverter( rxDocModel, rGraphicHelper, bDefaultColorBgr )
787{
788 OSL_ENSURE( mxContext.is(), "VbaUserForm::VbaUserForm - missing component context" );
789 OSL_ENSURE( mxDocModel.is(), "VbaUserForm::VbaUserForm - missing document model" );
790}
791
792void VbaUserForm::importForm( const Reference< XNameContainer >& rxDialogLib,
793 StorageBase& rVbaFormStrg, const OUString& rModuleName, rtl_TextEncoding eTextEnc )
794{
795 OSL_ENSURE( rxDialogLib.is(), "VbaUserForm::importForm - missing dialog library" );
796 if( !mxContext.is() || !mxDocModel.is() || !rxDialogLib.is() )
797 return;
798
799 // check that the '03VBFrame' stream exists, this is required for forms
800 BinaryXInputStream aInStrm( rVbaFormStrg.openInputStream( "\003VBFrame" ), true );
801 OSL_ENSURE( !aInStrm.isEof(), "VbaUserForm::importForm - missing \\003VBFrame stream" );
802 if( aInStrm.isEof() )
803 return;
804
805 // scan for the line 'Begin {GUID} <FormName>'
806 TextInputStream aFrameTextStrm( mxContext, aInStrm, eTextEnc );
807 static const OUStringLiteral aBegin = u"Begin";
808 OUString aLine;
809 bool bBeginFound = false;
810 while( !bBeginFound && !aFrameTextStrm.isEof() )
811 {
812 aLine = aFrameTextStrm.readLine().trim();
813 bBeginFound = lclEatKeyword( aLine, aBegin );
814 }
815 // check for the specific GUID that represents VBA forms
816 if( !bBeginFound || !lclEatKeyword( aLine, u"{C62A69F0-16DC-11CE-9E98-00AA00574A4F}" ) )
817 return;
818
819 // remaining line is the form name
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() )
826 return;
827 mxSiteModel = std::make_shared<VbaSiteModel>();
828 mxSiteModel->importProperty( XML_Name, aFormName );
829
830 // read the form properties (caption is contained in this '03VBFrame' stream, not in the 'f' stream)
831 mxCtrlModel = std::make_shared<AxUserFormModel>();
832 OUString aKey, aValue;
833 bool bExitLoop = false;
834 while( !bExitLoop && !aFrameTextStrm.isEof() )
835 {
836 aLine = aFrameTextStrm.readLine().trim();
837 bExitLoop = aLine.equalsIgnoreAsciiCase( "End" );
838 if( !bExitLoop && VbaHelper::extractKeyValue( aKey, aValue, aLine ) )
839 {
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 ) );
844 }
845 }
846
847 // use generic container control functionality to import the embedded controls
848 importStorage( rVbaFormStrg, AxClassTable() );
849
850 try
851 {
852 // create the dialog model
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 );
857
858 // convert properties and embedded controls
859 if( convertProperties( xDialogModel, maConverter, 0 ) )
860 {
861 // export the dialog to XML and insert it into the dialog library
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" );
864 ContainerHelper::insertByName( rxDialogLib, aFormName, Any( xDialogSource ) );
865 }
866 }
867 catch(const Exception& )
868 {
869 }
870}
871
872} // namespace oox
873
874/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
constexpr auto convertPointToMm100(N n)
#define COMCTL_GUID_PROGRESSBAR_50
Definition: axcontrol.hxx:57
#define COMCTL_GUID_PROGRESSBAR_60
Definition: axcontrol.hxx:58
#define COMCTL_GUID_SCROLLBAR_60
Definition: axcontrol.hxx:56
static sal_uInt32 decodeUnsigned(std::u16string_view rValue)
Returns the 32-bit unsigned integer value from the passed string (decimal).
Interface for binary input stream classes.
virtual void skip(sal_Int32 nBytes, size_t nAtomSize=1)=0
Derived classes implement seeking the stream forward by the passed number of bytes.
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.
Wraps a UNO input stream and provides convenient access functions.
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.
Definition: propertymap.hxx:52
bool setProperty(sal_Int32 nPropId, Type &&rValue)
Sets the specified property to the passed value.
Definition: propertymap.hxx:72
A wrapper for a UNO property set.
Definition: propertyset.hxx:58
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.
Definition: refmap.hxx:41
Template for a vector of ref-counted objects with additional accessor functions.
Definition: refvector.hxx:43
value_type get(sal_Int32 nIndex) const
Returns a reference to the object with the passed index, or 0 on error.
Definition: refvector.hxx:52
void forEach(FunctorType aFunctor) const
Calls the passed functor for every contained object, automatically skips all elements that are empty ...
Definition: refvector.hxx:61
void forEachMemWithIndex(FuncType pFunc, ParamType1 aParam1, ParamType2 aParam2) const
Calls the passed member function of ObjType on every contained object.
Definition: refvector.hxx:109
void forEachMem(FuncType pFunc) const
Calls the passed member function of ObjType on every contained object, automatically skips all elemen...
Definition: refvector.hxx:69
Base class for storage access implementations.
Definition: storagebase.hxx:52
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.
Definition: axcontrol.hxx:798
virtual bool importBinaryModel(BinaryInputStream &rInStrm) override
Reads the leading structure in the 'f' stream containing the model for this control.
Definition: axcontrol.cxx:2389
bool importClassTable(BinaryInputStream &rInStrm, AxClassTable &orClassTable)
Reads the class table structure for embedded controls following the own model from the 'f' stream.
Definition: axcontrol.cxx:2432
virtual void importProperty(sal_Int32 nPropId, const OUString &rValue) override
Allows to set single properties specified by XML token identifier.
Definition: axcontrol.cxx:2383
Base class for Forms 2.0 controls supporting text formatting.
Definition: axcontrol.hxx:483
sal_Int16 getFontHeight() const
Returns the font height in points.
Definition: axcontrol.hxx:494
std::vector< sal_uInt32 > mnIDs
Definition: axcontrol.hxx:861
void importPageAndMultiPageProperties(BinaryInputStream &rInStrm, sal_Int32 nPages)
Definition: axcontrol.cxx:2509
Model for a Forms 2.0 option button.
Definition: axcontrol.hxx:670
std::vector< OUString > maItems
Definition: axcontrol.hxx:600
A base class with useful helper functions for something that is able to convert ActiveX and ComCtl fo...
Definition: axcontrol.hxx:194
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.
Definition: axcontrol.cxx:329
void convertPosition(PropertyMap &rPropMap, const AxPairData &rPos) const
Converts the passed position in 1/100 mm to UNO properties.
Definition: axcontrol.cxx:240
Base class for all models of form controls.
Definition: axcontrol.hxx:347
virtual ApiControlType getControlType() const =0
Derived classes return the UNO control type enum value.
void moveRelative(const AxPairData &rDistance)
Moves the control relative to its current position by the passed distance.
Definition: vbacontrol.cxx:695
OUString getControlName() const
Returns the programmatical name of the control.
Definition: vbacontrol.cxx:346
VbaSiteModelRef mxSiteModel
Common control properties.
Definition: vbacontrol.hxx:177
VbaFormControlVector::value_type VbaFormControlRef
Definition: vbacontrol.hxx:155
void importModelOrStorage(BinaryInputStream &rInStrm, StorageBase &rStrg, const AxClassTable &rClassTable)
Imports the model from the passed stream or storage, depending on the control's type.
Definition: vbacontrol.cxx:326
ControlModelRef mxCtrlModel
Specific control properties.
Definition: vbacontrol.hxx:178
void importStorage(StorageBase &rStrg, const AxClassTable &rClassTable)
Creates and imports the control model, and imports all embedded controls from the passed substorage.
Definition: vbacontrol.cxx:387
void importControlModel(BinaryInputStream &rInStrm, const AxClassTable &rClassTable)
Creates and imports the control model containing properties of the control.
Definition: vbacontrol.cxx:380
VbaFormControlVector maControls
All embedded form controls.
Definition: vbacontrol.hxx:181
void createControlModel(const AxClassTable &rClassTable)
Creates the control model according to the current site model.
Definition: vbacontrol.cxx:529
bool convertProperties(const css::uno::Reference< css::awt::XControlModel > &rxCtrlModel, const ControlConverter &rConv, sal_Int32 nCtrlIndex) const
Converts all control properties, and inserts and converts embedded controls.
Definition: vbacontrol.cxx:489
bool importSiteModel(BinaryInputStream &rInStrm)
Imports the site model data containing common properties of the control.
Definition: vbacontrol.cxx:536
void importEmbeddedSiteModels(BinaryInputStream &rInStrm)
Imports the site models of all embedded controls from the 'f' stream.
Definition: vbacontrol.cxx:542
AxClassTable maClassTable
Class identifiers for exotic embedded controls.
Definition: vbacontrol.hxx:182
void createAndConvert(sal_Int32 nCtrlIndex, const css::uno::Reference< css::container::XNameContainer > &rxParentNC, const ControlConverter &rConv) const
Creates the UNO control model, inserts it into the passed container, and converts all control propert...
Definition: vbacontrol.cxx:351
static bool compareByTabIndex(const VbaFormControlRef &rxLeft, const VbaFormControlRef &rxRight)
Functor for comparing controls by their tab index.
Definition: vbacontrol.cxx:722
void moveEmbeddedToAbsoluteParent()
Moves all embedded controls from their relative position in this control to an absolute position in t...
Definition: vbacontrol.cxx:701
sal_uInt32 mnStreamLen
Size of control stream data.
Definition: vbacontrol.hxx:101
AxPairData maPos
Position in parent container.
Definition: vbacontrol.hxx:97
void importProperty(sal_Int32 nPropId, const OUString &rValue)
Allows to set single properties specified by XML token identifier.
Definition: vbacontrol.cxx:177
sal_uInt32 mnFlags
Various flags.
Definition: vbacontrol.hxx:100
sal_uInt16 mnGroupId
Group identifier for grouped controls.
Definition: vbacontrol.hxx:104
sal_Int32 mnId
Control identifier.
Definition: vbacontrol.hxx:98
OUString maToolTip
Tool tip for the control.
Definition: vbacontrol.hxx:93
ControlModelRef createControlModel(const AxClassTable &rClassTable) const
Tries to create the control model according to the site model.
Definition: vbacontrol.cxx:238
sal_Int32 mnHelpContextId
Help context identifier.
Definition: vbacontrol.hxx:99
OUString maRowSource
Source data for the control in a spreadsheet.
Definition: vbacontrol.hxx:95
sal_uInt32 getStreamLength() const
Returns the length of the stream data for stream based controls.
Definition: vbacontrol.cxx:219
OUString maTag
User defined tag.
Definition: vbacontrol.hxx:92
sal_uInt16 mnClassIdOrCache
Class name identifier or GUID cache index.
Definition: vbacontrol.hxx:103
bool isContainer() const
Returns true, if this control is a container control.
Definition: vbacontrol.cxx:214
void convertProperties(PropertyMap &rPropMap, const ControlConverter &rConv, ApiControlType eCtrlType, sal_Int32 nCtrlIndex) const
Converts all form site properties.
Definition: vbacontrol.cxx:298
void moveRelative(const AxPairData &rDistance)
Moves the control relative to its current position by the passed distance.
Definition: vbacontrol.cxx:208
OUString getSubStorageName() const
Returns the name of the substorage for the container control data.
Definition: vbacontrol.cxx:224
bool importBinaryModel(BinaryInputStream &rInStrm)
Imports the site model data from the passed input stream.
Definition: vbacontrol.cxx:187
OUString maControlSource
Linked cell for the control value in a spreadsheet.
Definition: vbacontrol.hxx:94
sal_Int16 mnTabIndex
Tab order index.
Definition: vbacontrol.hxx:102
OUString maName
Name of the control.
Definition: vbacontrol.hxx:91
VbaUserForm(const css::uno::Reference< css::uno::XComponentContext > &rxContext, const css::uno::Reference< css::frame::XModel > &rxDocModel, const GraphicHelper &rGraphicHelper, bool bDefaultColorBgr)
Definition: vbacontrol.cxx:782
css::uno::Reference< css::frame::XModel > mxDocModel
Definition: vbacontrol.hxx:205
css::uno::Reference< css::uno::XComponentContext > mxContext
Definition: vbacontrol.hxx:204
ControlConverter maConverter
Definition: vbacontrol.hxx:206
void importForm(const css::uno::Reference< css::container::XNameContainer > &rxDialogLib, StorageBase &rVbaFormStrg, const OUString &rModuleName, rtl_TextEncoding eTextEnc)
Imports the form and its embedded controls, and inserts the form with all its controls into the passe...
Definition: vbacontrol.cxx:792
sal_uInt16 mnId
Definition: dffdumper.cxx:163
uno::Reference< uno::XComponentContext > mxContext
float u
Reference< XSingleServiceFactory > xFactory
FuncFlags mnFlags
sal_Int32 nIndex
OUString aName
#define SAL_WARN(area, stream)
@ Exception
bool extractKeyValue(OUString &rKey, OUString &rValue, std::u16string_view rKeyValue)
Extracts a key/value pair from a string separated by an equality sign.
Definition: vbahelper.cxx:45
::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.
Definition: axcontrol.hxx:152
@ API_CONTROL_PAGE
Definition: axcontrol.hxx:168
@ API_CONTROL_TABSTRIP
Definition: axcontrol.hxx:164
@ API_CONTROL_FRAME
Definition: axcontrol.hxx:167
@ API_CONTROL_MULTIPAGE
Definition: axcontrol.hxx:169
@ API_CONTROL_DIALOG
Definition: axcontrol.hxx:170
@ API_CONTROL_GROUPBOX
Definition: axcontrol.hxx:166
@ API_CONTROL_PROGRESSBAR
Definition: axcontrol.hxx:165
std::shared_ptr< VbaSiteModel > VbaSiteModelRef
Definition: vbacontrol.hxx:107
std::shared_ptr< ControlModelBase > ControlModelRef
Definition: axcontrol.hxx:388
::std::vector< OUString > AxClassTable
Definition: axcontrol.hxx:794
::std::vector< OUString > AxArrayString
An array of string values as a property.
std::shared_ptr< StorageBase > StorageRef
Definition: storagebase.hxx:42
bool getFlag(Type nBitField, Type nMask)
Returns true, if at least one of the bits set in nMask is set in nBitField.
Definition: helper.hxx:137
o3tl::enumarray< SvxBoxItemLine, sal_uInt16 > aDistance
unsigned char sal_uInt8
#define SAL_MAX_INT32
#define SAL_MAX_INT16
sal_uInt16 sal_Unicode
::std::set< OUString > maCtrlNames
Definition: vbacontrol.cxx:100
VbaControlNamesSet & mrCtrlNames
Definition: vbacontrol.cxx:134
sal_Int32 mnIndex
Definition: vbacontrol.cxx:101
std::unique_ptr< char[]> aBuffer