diff options
author | Noel Power <noel.power@suse.com> | 2012-09-13 12:49:08 +0100 |
---|---|---|
committer | Michael Meeks <michael.meeks@suse.com> | 2012-09-13 12:49:32 +0100 |
commit | a6c18caef16b9eb0742c2a2cbb724e66bb31c3c3 (patch) | |
tree | 273b82d875f1b55db73b56bb2fd147c7abe43917 /oox/source/ole/vbacontrol.cxx | |
parent | 41747c962603222b2d6221a9f5fca28cd71c103a (diff) |
targetted container_controls rework.
Diffstat (limited to 'oox/source/ole/vbacontrol.cxx')
-rw-r--r-- | oox/source/ole/vbacontrol.cxx | 308 |
1 files changed, 135 insertions, 173 deletions
diff --git a/oox/source/ole/vbacontrol.cxx b/oox/source/ole/vbacontrol.cxx index 903874ac477a..8f684916f239 100644 --- a/oox/source/ole/vbacontrol.cxx +++ b/oox/source/ole/vbacontrol.cxx @@ -216,6 +216,12 @@ bool VbaSiteModel::importBinaryModel( BinaryInputStream& rInStrm ) return aReader.finalizeImport(); } +void VbaSiteModel::moveRelative( const AxPairData& rDistance ) +{ + maPos.first += rDistance.first; + maPos.second += rDistance.second; +} + bool VbaSiteModel::isContainer() const { return !getFlag( mnFlags, VBA_SITE_OSTREAM ); @@ -260,10 +266,10 @@ ControlModelRef VbaSiteModel::createControlModel( const AxClassTable& rClassTabl case VBA_SITE_COMBOBOX: xCtrlModel.reset( new AxComboBoxModel ); break; case VBA_SITE_SPINBUTTON: xCtrlModel.reset( new AxSpinButtonModel ); break; case VBA_SITE_SCROLLBAR: xCtrlModel.reset( new AxScrollBarModel ); break; - case VBA_SITE_TABSTRIP: xCtrlModel.reset( new AxTabStripModel ); break; + case VBA_SITE_TABSTRIP: break; case VBA_SITE_FRAME: xCtrlModel.reset( new AxFrameModel ); break; - case VBA_SITE_MULTIPAGE: xCtrlModel.reset( new AxMultiPageModel ); break; - case VBA_SITE_FORM: xCtrlModel.reset( new AxFormPageModel ); break; + case VBA_SITE_MULTIPAGE: break; + case VBA_SITE_FORM: break; default: OSL_FAIL( "VbaSiteModel::createControlModel - unknown type index" ); } } @@ -428,9 +434,11 @@ void VbaFormControl::importStorage( StorageBase& rStrg, const AxClassTable& rCla maControls.forEachMem( &VbaFormControl::importModelOrStorage, ::boost::ref( aOStrm ), ::boost::ref( rStrg ), ::boost::cref( maClassTable ) ); - /** Final processing on the control and all embedded controls, - depending on the type of this control. */ - finalizeEmbeddedControls( rStrg ); + /* Reorder the controls (sorts all option buttons of an option + group together), and move all children of all embedded frames + (group boxes) to this control (UNO group boxes cannot contain + other controls). */ + finalizeEmbeddedControls(); } } } @@ -537,182 +545,138 @@ bool VbaFormControl::importEmbeddedSiteModels( BinaryInputStream& rInStrm ) return bValid; } -void VbaFormControl::finalizeEmbeddedControls( StorageBase& rStrg ) -{ - /* Store all embedded controls in a temporary vector, so "exit on error" - will leave this control empty. */ - VbaFormControlVector aControls; - aControls.swap( maControls ); - - /* If this is a multipage control, it stores additional data in the 'x' - stream of its storage. It contains the control identifiers of the form - page controls that contain the embedded controls of each page. - Additionally, the order of these pages is stored there (they are not - nessecarily in the order they are persisted in). */ - if( AxMultiPageModel* pMultiPageModel = dynamic_cast< AxMultiPageModel* >( mxCtrlModel.get() ) ) +void VbaFormControl::finalizeEmbeddedControls() +{ + /* This function performs two tasks: + + 1) Reorder the controls appropriately (sort all option buttons of an + option group together to make grouping work). + 2) Move all children of all embedded frames (group boxes) to this + control (UNO group boxes cannot contain other controls). + */ + + // first, sort all controls by original tab index + ::std::sort( maControls.begin(), maControls.end(), &compareByTabIndex ); + + /* Collect the programmatical names of all embedded controls (needed to be + able to set unused names to new dummy controls created below). Also + collect the names of all children of embedded frames (group boxes). + Luckily, names of controls must be unique in the entire form, not just + in the current container. */ + VbaControlNamesSet aControlNames; + VbaControlNameInserter aInserter( aControlNames ); + maControls.forEach( aInserter ); + for( VbaFormControlVector::iterator aIt = maControls.begin(), aEnd = maControls.end(); aIt != aEnd; ++aIt ) + if( (*aIt)->mxCtrlModel.get() && ((*aIt)->mxCtrlModel->getControlType() == API_CONTROL_GROUPBOX) ) + (*aIt)->maControls.forEach( aInserter ); + + /* Reprocess the sorted list and collect all option button controls that + are part of the same option group (determined by group name). All + controls will be stored in a vector of vectors, that collects every + option button group in one vector element, and other controls between + these option groups (or leading or trailing controls) in other vector + elements. If an option button group follows another group, a dummy + separator control has to be inserted. */ + typedef RefVector< VbaFormControlVector > VbaFormControlVectorVector; + VbaFormControlVectorVector aControlGroups; + + typedef RefMap< OUString, VbaFormControlVector > VbaFormControlVectorMap; + VbaFormControlVectorMap aOptionGroups; + + typedef VbaFormControlVectorMap::mapped_type VbaFormControlVectorRef; + bool bLastWasOptionButton = false; + for( VbaFormControlVector::iterator aIt = maControls.begin(), aEnd = maControls.end(); aIt != aEnd; ++aIt ) { - // read additional attributes from the 'x' stream - BinaryXInputStream aXStrm( rStrg.openInputStream( CREATE_OUSTRING( "x" ) ), true ); - OSL_ENSURE( !aXStrm.isEof(), "VbaFormControl::finalizeEmbeddedControls - missing 'x' stream" ); - if( aXStrm.isEof() ) return; + VbaFormControlRef xControl = *aIt; + const ControlModelBase* pCtrlModel = xControl->mxCtrlModel.get(); - // skip the page property structures related to all controls - for( size_t nSiteIdx = 0, nSiteCount = aControls.size(); nSiteIdx < nSiteCount; ++nSiteIdx ) - { - AxBinaryPropertyReader aReader( aXStrm ); - aReader.skipUndefinedProperty(); - aReader.skipIntProperty< sal_uInt32 >(); // transition effect - aReader.skipIntProperty< sal_uInt32 >(); // transition period - if( !aReader.finalizeImport() ) return; - } - - // read the multipage property structure containing a list of page IDs - sal_Int32 nPageCount = 0; - sal_Int32 nTabStripId = 0; - AxBinaryPropertyReader aReader( aXStrm ); - aReader.skipUndefinedProperty(); - aReader.readIntProperty< sal_Int32 >( nPageCount ); - aReader.readIntProperty< sal_Int32 >( nTabStripId ); - if( !aReader.finalizeImport() ) return; - // read the array containing all page identifiers in current order - typedef ::std::vector< sal_Int32 > AxPageIdVector; - AxPageIdVector aPageIds; - for( sal_Int32 nPage = 0; !aXStrm.isEof() && (nPage < nPageCount); ++nPage ) - aPageIds.push_back( aXStrm.readInt32() ); - if( aXStrm.isEof() ) return; - - // check the page count value - bool bValidPageCount = (0 < nPageCount) && (static_cast< size_t >( nPageCount + 1 ) == aControls.size()); - OSL_ENSURE( bValidPageCount, "VbaFormControl::finalizeEmbeddedControls - invalid number of pages" ); - if( !bValidPageCount ) return; - - /* Check that this multipage contains the expected controls: - - a tabstrip control, specified by nTabStripId, - - form page controls (containing the embedded controls of each page). */ - - // the controls may be in arbitrary order, first map them by ID - RefMap< sal_Int32, VbaFormControl > aControlsById; - for( VbaFormControlVector::iterator aIt = aControls.begin(), aEnd = aControls.end(); aIt != aEnd; ++aIt ) - { - VbaFormControlRef xControl = *aIt; - sal_Int32 nId = xControl->getControlId(); - OSL_ENSURE( (nId > 0) && !aControlsById.has( nId ), "VbaFormControl::finalizeEmbeddedControls - invalid control ID" ); - aControlsById[ nId ] = xControl; - } - // store tabstrip in the multipage, it will care about property conversion - AxTabStripModelRef xTabStripModel; - VbaFormControlRef xControl = aControlsById.get( nTabStripId ); - if( xControl.get() ) - xTabStripModel = ::boost::dynamic_pointer_cast< AxTabStripModel >( xControl->mxCtrlModel ); - OSL_ENSURE( xTabStripModel.get(), "VbaFormControl::finalizeEmbeddedControls - missing tabstrip control" ); - if( !xTabStripModel ) return; - pMultiPageModel->setTabStripModel( xTabStripModel ); - aControlsById.erase( nTabStripId ); - // store all pages in maControls in the correct order specified by aPageIds - sal_Int32 nTabIndex = 0; - for( AxPageIdVector::iterator aIt = aPageIds.begin(), aEnd = aPageIds.end(); aIt != aEnd; ++aIt, ++nTabIndex ) + if( const AxOptionButtonModel* pOptButtonModel = dynamic_cast< const AxOptionButtonModel* >( pCtrlModel ) ) { - VbaFormControlRef rControl = aControlsById.get( *aIt ); - AxFormPageModel* pFormPageModel = rControl.get() ? dynamic_cast< AxFormPageModel* >( rControl->mxCtrlModel.get() ) : 0; - OSL_ENSURE( pFormPageModel, "VbaFormControl::finalizeEmbeddedControls - missing formpage control" ); - // do not exit on error but try to collect as much pages as possible - if( pFormPageModel ) + // check if a new option group needs to be created + const OUString& rGroupName = pOptButtonModel->getGroupName(); + VbaFormControlVectorRef& rxOptionGroup = aOptionGroups[ rGroupName ]; + if( !rxOptionGroup ) { - // get the tab caption from tabstrip control and set it at the formpage - OUString aCaption = xTabStripModel->getCaption( nTabIndex ); - pFormPageModel->importProperty( XML_Caption, aCaption ); - // store the control in maControls - maControls.push_back( rControl ); - aControlsById.erase( *aIt ); + /* If last control was an option button too, we have two + option groups following each other, so a dummy separator + control is needed. */ + if( bLastWasOptionButton ) + { + VbaFormControlVectorRef xDummyGroup( new VbaFormControlVector ); + aControlGroups.push_back( xDummyGroup ); + OUString aName = aControlNames.generateDummyName(); + VbaFormControlRef xDummyControl( new VbaDummyFormControl( aName ) ); + xDummyGroup->push_back( xDummyControl ); + } + rxOptionGroup.reset( new VbaFormControlVector ); + aControlGroups.push_back( rxOptionGroup ); } + /* Append the option button to the control group (which is now + referred by the vector aControlGroups and by the map + aOptionGroups). */ + rxOptionGroup->push_back( xControl ); + bLastWasOptionButton = true; } - } - else - { - /* Reorder the controls appropriately (sort all option buttons of an - option group together to make grouping work), and erase all plain - tabstrip controls (currently not supported in UNO dialogs). */ - - // first, sort all controls by original tab index - ::std::sort( aControls.begin(), aControls.end(), &compareByTabIndex ); - - /* Collect the programmatical names of all embedded controls (needed to be - able to set unused names to new dummy controls created below). */ - VbaControlNamesSet aControlNames; - VbaControlNameInserter aInserter( aControlNames ); - aControls.forEach( aInserter ); - - /* Reprocess the sorted list and collect all option button controls that - are part of the same option group (determined by group name). All - controls will be stored in a vector of vectors, that collects every - option button group in one vector element, and other controls between - these option groups (or leading or trailing controls) in other vector - elements. If an option button group follows another group, a dummy - separator control has to be inserted. */ - typedef RefVector< VbaFormControlVector > VbaFormControlVectorVector; - VbaFormControlVectorVector aControlGroups; - - typedef RefMap< OUString, VbaFormControlVector > VbaFormControlVectorMap; - VbaFormControlVectorMap aOptionGroups; - - typedef VbaFormControlVectorMap::mapped_type VbaFormControlVectorRef; - bool bLastWasOptionButton = false; - for( VbaFormControlVector::iterator aIt = aControls.begin(), aEnd = aControls.end(); aIt != aEnd; ++aIt ) + else { - VbaFormControlRef xControl = *aIt; - const ControlModelBase* pCtrlModel = xControl->mxCtrlModel.get(); - if ( !pCtrlModel ) // skip unsupported controls - continue; - if( const AxOptionButtonModel* pOptButtonModel = dynamic_cast< const AxOptionButtonModel* >( pCtrlModel ) ) + // open a new control group, if the last group is an option group + if( bLastWasOptionButton || aControlGroups.empty() ) { - // check if a new option group needs to be created - const OUString& rGroupName = pOptButtonModel->getGroupName(); - VbaFormControlVectorRef& rxOptionGroup = aOptionGroups[ rGroupName ]; - if( !rxOptionGroup ) - { - /* If last control was an option button too, we have two - option groups following each other, so a dummy separator - control is needed. */ - if( bLastWasOptionButton ) - { - VbaFormControlVectorRef xDummyGroup( new VbaFormControlVector ); - aControlGroups.push_back( xDummyGroup ); - OUString aName = aControlNames.generateDummyName(); - VbaFormControlRef xDummyControl( new VbaDummyFormControl( aName ) ); - xDummyGroup->push_back( xDummyControl ); - } - rxOptionGroup.reset( new VbaFormControlVector ); - aControlGroups.push_back( rxOptionGroup ); - } - /* Append the option button to the control group (which is now - referred by the vector aControlGroups and by the map - aOptionGroups). */ - rxOptionGroup->push_back( xControl ); - bLastWasOptionButton = true; + VbaFormControlVectorRef xControlGroup( new VbaFormControlVector ); + aControlGroups.push_back( xControlGroup ); } - else + // append the control to the last control group + VbaFormControlVector& rLastGroup = *aControlGroups.back(); + rLastGroup.push_back( xControl ); + bLastWasOptionButton = false; + + // if control is a group box, move all its children to this control + if( pCtrlModel && (pCtrlModel->getControlType() == API_CONTROL_GROUPBOX) ) { - // skip unsupported controls (tabstrips and page controls) - ApiControlType eCtrlType = pCtrlModel->getControlType(); - if( (eCtrlType != API_CONTROL_TABSTRIP) && (eCtrlType != API_CONTROL_PAGE) ) - { - // open a new control group, if the last group is an option group - if( bLastWasOptionButton || aControlGroups.empty() ) - { - VbaFormControlVectorRef xControlGroup( new VbaFormControlVector ); - aControlGroups.push_back( xControlGroup ); - } - // append the control to the last control group - VbaFormControlVector& rLastGroup = *aControlGroups.back(); - rLastGroup.push_back( xControl ); - bLastWasOptionButton = false; - } + /* Move all embedded controls of the group box relative to the + position of the group box. */ + xControl->moveEmbeddedToAbsoluteParent(); + /* Insert all children of the group box into the last control + group (following the group box). */ + rLastGroup.insert( rLastGroup.end(), xControl->maControls.begin(), xControl->maControls.end() ); + xControl->maControls.clear(); + // check if last control of the group box is an option button + bLastWasOptionButton = dynamic_cast< const AxOptionButtonModel* >( rLastGroup.back()->mxCtrlModel.get() ) != 0; } } + } + + // flatten the vector of vectors of form controls to a single vector + maControls.clear(); + for( VbaFormControlVectorVector::iterator aIt = aControlGroups.begin(), aEnd = aControlGroups.end(); aIt != aEnd; ++aIt ) + maControls.insert( maControls.end(), (*aIt)->begin(), (*aIt)->end() ); +} + +void VbaFormControl::moveRelative( const AxPairData& rDistance ) +{ + if( mxSiteModel.get() ) + mxSiteModel->moveRelative( rDistance ); +} + +void VbaFormControl::moveEmbeddedToAbsoluteParent() +{ + if( mxSiteModel.get() && !maControls.empty() ) + { + // distance to move is equal to position of this control in its parent + AxPairData aDistance = mxSiteModel->getPosition(); + + /* For group boxes: add half of the font height to Y position (VBA + positions relative to frame border line, not to 'top' of frame). */ + const AxFontDataModel* pFontModel = dynamic_cast< const AxFontDataModel* >( mxCtrlModel.get() ); + if( pFontModel && (pFontModel->getControlType() == API_CONTROL_GROUPBOX) ) + { + // convert points to 1/100 mm (1 pt = 1/72 inch = 2.54/72 cm = 2540/72 1/100 mm) + sal_Int32 nFontHeight = static_cast< sal_Int32 >( pFontModel->getFontHeight() * 2540 / 72 ); + aDistance.second += nFontHeight / 2; + } - // flatten the vector of vectors of form controls to a single vector - for( VbaFormControlVectorVector::iterator aIt = aControlGroups.begin(), aEnd = aControlGroups.end(); aIt != aEnd; ++aIt ) - maControls.insert( maControls.end(), (*aIt)->begin(), (*aIt)->end() ); + // move the embedded controls + maControls.forEachMem( &VbaFormControl::moveRelative, ::boost::cref( aDistance ) ); } } @@ -790,9 +754,7 @@ VbaUserForm::VbaUserForm( const Reference< XComponentContext >& rxContext, OSL_ENSURE( mxDocModel.is(), "VbaUserForm::VbaUserForm - missing document model" ); } -void VbaUserForm::importForm( - const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel >& rxDocModel, - const Reference< XNameContainer >& rxDialogLib, +void VbaUserForm::importForm( const Reference< XNameContainer >& rxDialogLib, StorageBase& rVbaFormStrg, const OUString& rModuleName, rtl_TextEncoding eTextEnc ) { OSL_ENSURE( rxDialogLib.is(), "VbaUserForm::importForm - missing dialog library" ); @@ -862,7 +824,7 @@ void VbaUserForm::importForm( if( convertProperties( xDialogModel, maConverter, 0 ) ) { // export the dialog to XML and insert it into the dialog library - Reference< XInputStreamProvider > xDialogSource( ::xmlscript::exportDialogModel( xDialogNC, mxContext, rxDocModel ), UNO_SET_THROW ); + Reference< XInputStreamProvider > xDialogSource( ::xmlscript::exportDialogModel( xDialogNC, mxContext, mxDocModel ), UNO_SET_THROW ); OSL_ENSURE( !rxDialogLib->hasByName( aFormName ), "VbaUserForm::importForm - multiple dialogs with equal name" ); ContainerHelper::insertByName( rxDialogLib, aFormName, Any( xDialogSource ) ); } |