1*ca5ec200SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*ca5ec200SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*ca5ec200SAndrew Rist * or more contributor license agreements. See the NOTICE file 5*ca5ec200SAndrew Rist * distributed with this work for additional information 6*ca5ec200SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*ca5ec200SAndrew Rist * to you under the Apache License, Version 2.0 (the 8*ca5ec200SAndrew Rist * "License"); you may not use this file except in compliance 9*ca5ec200SAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*ca5ec200SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*ca5ec200SAndrew Rist * Unless required by applicable law or agreed to in writing, 14*ca5ec200SAndrew Rist * software distributed under the License is distributed on an 15*ca5ec200SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*ca5ec200SAndrew Rist * KIND, either express or implied. See the License for the 17*ca5ec200SAndrew Rist * specific language governing permissions and limitations 18*ca5ec200SAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*ca5ec200SAndrew Rist *************************************************************/ 21*ca5ec200SAndrew Rist 22*ca5ec200SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir #include "oox/ole/vbacontrol.hxx" 25cdf0e10cSrcweir 26cdf0e10cSrcweir #include <algorithm> 27cdf0e10cSrcweir #include <set> 28cdf0e10cSrcweir #include <com/sun/star/awt/XControlModel.hpp> 29cdf0e10cSrcweir #include <com/sun/star/container/XNameContainer.hpp> 30cdf0e10cSrcweir #include <com/sun/star/io/XInputStreamProvider.hpp> 31cdf0e10cSrcweir #include <com/sun/star/lang/XMultiServiceFactory.hpp> 32cdf0e10cSrcweir #include <com/sun/star/uno/XComponentContext.hpp> 33cdf0e10cSrcweir #include <rtl/ustrbuf.hxx> 34cdf0e10cSrcweir #include <xmlscript/xmldlg_imexp.hxx> 35cdf0e10cSrcweir #include "oox/helper/attributelist.hxx" 36cdf0e10cSrcweir #include "oox/helper/binaryinputstream.hxx" 37cdf0e10cSrcweir #include "oox/helper/containerhelper.hxx" 38cdf0e10cSrcweir #include "oox/helper/propertymap.hxx" 39cdf0e10cSrcweir #include "oox/helper/propertyset.hxx" 40cdf0e10cSrcweir #include "oox/helper/storagebase.hxx" 41cdf0e10cSrcweir #include "oox/helper/textinputstream.hxx" 42cdf0e10cSrcweir #include "oox/ole/vbahelper.hxx" 43cdf0e10cSrcweir 44cdf0e10cSrcweir namespace oox { 45cdf0e10cSrcweir namespace ole { 46cdf0e10cSrcweir 47cdf0e10cSrcweir // ============================================================================ 48cdf0e10cSrcweir 49cdf0e10cSrcweir using namespace ::com::sun::star::awt; 50cdf0e10cSrcweir using namespace ::com::sun::star::container; 51cdf0e10cSrcweir using namespace ::com::sun::star::frame; 52cdf0e10cSrcweir using namespace ::com::sun::star::io; 53cdf0e10cSrcweir using namespace ::com::sun::star::lang; 54cdf0e10cSrcweir using namespace ::com::sun::star::uno; 55cdf0e10cSrcweir 56cdf0e10cSrcweir using ::rtl::OUString; 57cdf0e10cSrcweir using ::rtl::OUStringBuffer; 58cdf0e10cSrcweir 59cdf0e10cSrcweir // ============================================================================ 60cdf0e10cSrcweir 61cdf0e10cSrcweir namespace { 62cdf0e10cSrcweir 63cdf0e10cSrcweir const sal_uInt16 VBA_SITE_CLASSIDINDEX = 0x8000; 64cdf0e10cSrcweir const sal_uInt16 VBA_SITE_INDEXMASK = 0x7FFF; 65cdf0e10cSrcweir const sal_uInt16 VBA_SITE_FORM = 7; 66cdf0e10cSrcweir const sal_uInt16 VBA_SITE_IMAGE = 12; 67cdf0e10cSrcweir const sal_uInt16 VBA_SITE_FRAME = 14; 68cdf0e10cSrcweir const sal_uInt16 VBA_SITE_SPINBUTTON = 16; 69cdf0e10cSrcweir const sal_uInt16 VBA_SITE_COMMANDBUTTON = 17; 70cdf0e10cSrcweir const sal_uInt16 VBA_SITE_TABSTRIP = 18; 71cdf0e10cSrcweir const sal_uInt16 VBA_SITE_LABEL = 21; 72cdf0e10cSrcweir const sal_uInt16 VBA_SITE_TEXTBOX = 23; 73cdf0e10cSrcweir const sal_uInt16 VBA_SITE_LISTBOX = 24; 74cdf0e10cSrcweir const sal_uInt16 VBA_SITE_COMBOBOX = 25; 75cdf0e10cSrcweir const sal_uInt16 VBA_SITE_CHECKBOX = 26; 76cdf0e10cSrcweir const sal_uInt16 VBA_SITE_OPTIONBUTTON = 27; 77cdf0e10cSrcweir const sal_uInt16 VBA_SITE_TOGGLEBUTTON = 28; 78cdf0e10cSrcweir const sal_uInt16 VBA_SITE_SCROLLBAR = 47; 79cdf0e10cSrcweir const sal_uInt16 VBA_SITE_MULTIPAGE = 57; 80cdf0e10cSrcweir const sal_uInt16 VBA_SITE_UNKNOWN = 0x7FFF; 81cdf0e10cSrcweir 82cdf0e10cSrcweir const sal_uInt32 VBA_SITE_TABSTOP = 0x00000001; 83cdf0e10cSrcweir const sal_uInt32 VBA_SITE_VISIBLE = 0x00000002; 84cdf0e10cSrcweir const sal_uInt32 VBA_SITE_DEFAULTBUTTON = 0x00000004; 85cdf0e10cSrcweir const sal_uInt32 VBA_SITE_CANCELBUTTON = 0x00000008; 86cdf0e10cSrcweir const sal_uInt32 VBA_SITE_OSTREAM = 0x00000010; 87cdf0e10cSrcweir const sal_uInt32 VBA_SITE_DEFFLAGS = 0x00000033; 88cdf0e10cSrcweir 89cdf0e10cSrcweir const sal_uInt8 VBA_SITEINFO_COUNT = 0x80; 90cdf0e10cSrcweir const sal_uInt8 VBA_SITEINFO_MASK = 0x7F; 91cdf0e10cSrcweir 92cdf0e10cSrcweir // ---------------------------------------------------------------------------- 93cdf0e10cSrcweir 94cdf0e10cSrcweir /** Collects names of all controls in a user form or container control. Allows 95cdf0e10cSrcweir to generate unused names for dummy controls separating option groups. 96cdf0e10cSrcweir */ 97cdf0e10cSrcweir class VbaControlNamesSet 98cdf0e10cSrcweir { 99cdf0e10cSrcweir public: 100cdf0e10cSrcweir explicit VbaControlNamesSet(); 101cdf0e10cSrcweir 102cdf0e10cSrcweir /** Inserts the name of the passed control. */ 103cdf0e10cSrcweir void insertName( const VbaFormControl& rControl ); 104cdf0e10cSrcweir /** Returns a name that is not contained in this set. */ 105cdf0e10cSrcweir OUString generateDummyName(); 106cdf0e10cSrcweir 107cdf0e10cSrcweir private: 108cdf0e10cSrcweir typedef ::std::set< OUString > OUStringSet; 109cdf0e10cSrcweir OUStringSet maCtrlNames; 110cdf0e10cSrcweir const OUString maDummyBaseName; 111cdf0e10cSrcweir sal_Int32 mnIndex; 112cdf0e10cSrcweir }; 113cdf0e10cSrcweir 114cdf0e10cSrcweir VbaControlNamesSet::VbaControlNamesSet() : 115cdf0e10cSrcweir maDummyBaseName( CREATE_OUSTRING( "DummyGroupSep" ) ), 116cdf0e10cSrcweir mnIndex( 0 ) 117cdf0e10cSrcweir { 118cdf0e10cSrcweir } 119cdf0e10cSrcweir 120cdf0e10cSrcweir void VbaControlNamesSet::insertName( const VbaFormControl& rControl ) 121cdf0e10cSrcweir { 122cdf0e10cSrcweir OUString aName = rControl.getControlName(); 123cdf0e10cSrcweir if( aName.getLength() > 0 ) 124cdf0e10cSrcweir maCtrlNames.insert( aName ); 125cdf0e10cSrcweir } 126cdf0e10cSrcweir 127cdf0e10cSrcweir OUString VbaControlNamesSet::generateDummyName() 128cdf0e10cSrcweir { 129cdf0e10cSrcweir OUString aCtrlName; 130cdf0e10cSrcweir do 131cdf0e10cSrcweir { 132cdf0e10cSrcweir aCtrlName = OUStringBuffer( maDummyBaseName ).append( ++mnIndex ).makeStringAndClear(); 133cdf0e10cSrcweir } 134cdf0e10cSrcweir while( maCtrlNames.count( aCtrlName ) > 0 ); 135cdf0e10cSrcweir maCtrlNames.insert( aCtrlName ); 136cdf0e10cSrcweir return aCtrlName; 137cdf0e10cSrcweir } 138cdf0e10cSrcweir 139cdf0e10cSrcweir // ---------------------------------------------------------------------------- 140cdf0e10cSrcweir 141cdf0e10cSrcweir /** Functor that inserts the name of a control into a VbaControlNamesSet. */ 142cdf0e10cSrcweir struct VbaControlNameInserter 143cdf0e10cSrcweir { 144cdf0e10cSrcweir public: 145cdf0e10cSrcweir VbaControlNamesSet& mrCtrlNames; 146cdf0e10cSrcweir inline explicit VbaControlNameInserter( VbaControlNamesSet& rCtrlNames ) : mrCtrlNames( rCtrlNames ) {} 147cdf0e10cSrcweir inline void operator()( const VbaFormControl& rControl ) { mrCtrlNames.insertName( rControl ); } 148cdf0e10cSrcweir }; 149cdf0e10cSrcweir 150cdf0e10cSrcweir // ---------------------------------------------------------------------------- 151cdf0e10cSrcweir 152cdf0e10cSrcweir /** A dummy invisible form control (fixed label without text) that is used to 153cdf0e10cSrcweir separate two groups of option buttons. 154cdf0e10cSrcweir */ 155cdf0e10cSrcweir class VbaDummyFormControl : public VbaFormControl 156cdf0e10cSrcweir { 157cdf0e10cSrcweir public: 158cdf0e10cSrcweir explicit VbaDummyFormControl( const OUString& rName ); 159cdf0e10cSrcweir }; 160cdf0e10cSrcweir 161cdf0e10cSrcweir VbaDummyFormControl::VbaDummyFormControl( const OUString& rName ) 162cdf0e10cSrcweir { 163cdf0e10cSrcweir mxSiteModel.reset( new VbaSiteModel ); 164cdf0e10cSrcweir mxSiteModel->importProperty( XML_Name, rName ); 165cdf0e10cSrcweir mxSiteModel->importProperty( XML_VariousPropertyBits, OUString( sal_Unicode( '0' ) ) ); 166cdf0e10cSrcweir 167cdf0e10cSrcweir mxCtrlModel.reset( new AxLabelModel ); 168cdf0e10cSrcweir mxCtrlModel->setAwtModelMode(); 169cdf0e10cSrcweir mxCtrlModel->importProperty( XML_Size, CREATE_OUSTRING( "10;10" ) ); 170cdf0e10cSrcweir } 171cdf0e10cSrcweir 172cdf0e10cSrcweir } // namespace 173cdf0e10cSrcweir 174cdf0e10cSrcweir // ============================================================================ 175cdf0e10cSrcweir 176cdf0e10cSrcweir VbaSiteModel::VbaSiteModel() : 177cdf0e10cSrcweir maPos( 0, 0 ), 178cdf0e10cSrcweir mnId( 0 ), 179cdf0e10cSrcweir mnHelpContextId( 0 ), 180cdf0e10cSrcweir mnFlags( VBA_SITE_DEFFLAGS ), 181cdf0e10cSrcweir mnStreamLen( 0 ), 182cdf0e10cSrcweir mnTabIndex( -1 ), 183cdf0e10cSrcweir mnClassIdOrCache( VBA_SITE_UNKNOWN ), 184cdf0e10cSrcweir mnGroupId( 0 ) 185cdf0e10cSrcweir { 186cdf0e10cSrcweir } 187cdf0e10cSrcweir 188cdf0e10cSrcweir VbaSiteModel::~VbaSiteModel() 189cdf0e10cSrcweir { 190cdf0e10cSrcweir } 191cdf0e10cSrcweir 192cdf0e10cSrcweir void VbaSiteModel::importProperty( sal_Int32 nPropId, const OUString& rValue ) 193cdf0e10cSrcweir { 194cdf0e10cSrcweir switch( nPropId ) 195cdf0e10cSrcweir { 196cdf0e10cSrcweir case XML_Name: maName = rValue; break; 197cdf0e10cSrcweir case XML_Tag: maTag = rValue; break; 198cdf0e10cSrcweir case XML_VariousPropertyBits: mnFlags = AttributeConversion::decodeUnsigned( rValue ); break; 199cdf0e10cSrcweir } 200cdf0e10cSrcweir } 201cdf0e10cSrcweir 202cdf0e10cSrcweir bool VbaSiteModel::importBinaryModel( BinaryInputStream& rInStrm ) 203cdf0e10cSrcweir { 204cdf0e10cSrcweir AxBinaryPropertyReader aReader( rInStrm ); 205cdf0e10cSrcweir aReader.readStringProperty( maName ); 206cdf0e10cSrcweir aReader.readStringProperty( maTag ); 207cdf0e10cSrcweir aReader.readIntProperty< sal_Int32 >( mnId ); 208cdf0e10cSrcweir aReader.readIntProperty< sal_Int32 >( mnHelpContextId ); 209cdf0e10cSrcweir aReader.readIntProperty< sal_uInt32 >( mnFlags ); 210cdf0e10cSrcweir aReader.readIntProperty< sal_uInt32 >( mnStreamLen ); 211cdf0e10cSrcweir aReader.readIntProperty< sal_Int16 >( mnTabIndex ); 212cdf0e10cSrcweir aReader.readIntProperty< sal_uInt16 >( mnClassIdOrCache ); 213cdf0e10cSrcweir aReader.readPairProperty( maPos ); 214cdf0e10cSrcweir aReader.readIntProperty< sal_uInt16 >( mnGroupId ); 215cdf0e10cSrcweir aReader.skipUndefinedProperty(); 216cdf0e10cSrcweir aReader.readStringProperty( maToolTip ); 217cdf0e10cSrcweir aReader.skipStringProperty(); // license key 218cdf0e10cSrcweir aReader.readStringProperty( maControlSource ); 219cdf0e10cSrcweir aReader.readStringProperty( maRowSource ); 220cdf0e10cSrcweir return aReader.finalizeImport(); 221cdf0e10cSrcweir } 222cdf0e10cSrcweir 223cdf0e10cSrcweir void VbaSiteModel::moveRelative( const AxPairData& rDistance ) 224cdf0e10cSrcweir { 225cdf0e10cSrcweir maPos.first += rDistance.first; 226cdf0e10cSrcweir maPos.second += rDistance.second; 227cdf0e10cSrcweir } 228cdf0e10cSrcweir 229cdf0e10cSrcweir bool VbaSiteModel::isVisible() const 230cdf0e10cSrcweir { 231cdf0e10cSrcweir return getFlag( mnFlags, VBA_SITE_VISIBLE ); 232cdf0e10cSrcweir } 233cdf0e10cSrcweir 234cdf0e10cSrcweir bool VbaSiteModel::isContainer() const 235cdf0e10cSrcweir { 236cdf0e10cSrcweir return !getFlag( mnFlags, VBA_SITE_OSTREAM ); 237cdf0e10cSrcweir } 238cdf0e10cSrcweir 239cdf0e10cSrcweir sal_uInt32 VbaSiteModel::getStreamLength() const 240cdf0e10cSrcweir { 241cdf0e10cSrcweir return isContainer() ? 0 : mnStreamLen; 242cdf0e10cSrcweir } 243cdf0e10cSrcweir 244cdf0e10cSrcweir OUString VbaSiteModel::getSubStorageName() const 245cdf0e10cSrcweir { 246cdf0e10cSrcweir if( mnId >= 0 ) 247cdf0e10cSrcweir { 248cdf0e10cSrcweir OUStringBuffer aBuffer; 249cdf0e10cSrcweir aBuffer.append( sal_Unicode( 'i' ) ); 250cdf0e10cSrcweir if( mnId < 10 ) 251cdf0e10cSrcweir aBuffer.append( sal_Unicode( '0' ) ); 252cdf0e10cSrcweir aBuffer.append( mnId ); 253cdf0e10cSrcweir return aBuffer.makeStringAndClear(); 254cdf0e10cSrcweir } 255cdf0e10cSrcweir return OUString(); 256cdf0e10cSrcweir } 257cdf0e10cSrcweir 258cdf0e10cSrcweir ControlModelRef VbaSiteModel::createControlModel( const AxClassTable& rClassTable ) const 259cdf0e10cSrcweir { 260cdf0e10cSrcweir ControlModelRef xCtrlModel; 261cdf0e10cSrcweir 262cdf0e10cSrcweir sal_Int32 nTypeIndex = static_cast< sal_Int32 >( mnClassIdOrCache & VBA_SITE_INDEXMASK ); 263cdf0e10cSrcweir if( !getFlag( mnClassIdOrCache, VBA_SITE_CLASSIDINDEX ) ) 264cdf0e10cSrcweir { 265cdf0e10cSrcweir switch( nTypeIndex ) 266cdf0e10cSrcweir { 267cdf0e10cSrcweir case VBA_SITE_COMMANDBUTTON: xCtrlModel.reset( new AxCommandButtonModel ); break; 268cdf0e10cSrcweir case VBA_SITE_LABEL: xCtrlModel.reset( new AxLabelModel ); break; 269cdf0e10cSrcweir case VBA_SITE_IMAGE: xCtrlModel.reset( new AxImageModel ); break; 270cdf0e10cSrcweir case VBA_SITE_TOGGLEBUTTON: xCtrlModel.reset( new AxToggleButtonModel ); break; 271cdf0e10cSrcweir case VBA_SITE_CHECKBOX: xCtrlModel.reset( new AxCheckBoxModel ); break; 272cdf0e10cSrcweir case VBA_SITE_OPTIONBUTTON: xCtrlModel.reset( new AxOptionButtonModel ); break; 273cdf0e10cSrcweir case VBA_SITE_TEXTBOX: xCtrlModel.reset( new AxTextBoxModel ); break; 274cdf0e10cSrcweir case VBA_SITE_LISTBOX: xCtrlModel.reset( new AxListBoxModel ); break; 275cdf0e10cSrcweir case VBA_SITE_COMBOBOX: xCtrlModel.reset( new AxComboBoxModel ); break; 276cdf0e10cSrcweir case VBA_SITE_SPINBUTTON: /*xCtrlModel.reset( new AxSpinButtonModel );*/ break; // not supported (?) 277cdf0e10cSrcweir case VBA_SITE_SCROLLBAR: xCtrlModel.reset( new AxScrollBarModel ); break; 278cdf0e10cSrcweir case VBA_SITE_TABSTRIP: break; // not supported 279cdf0e10cSrcweir case VBA_SITE_FRAME: xCtrlModel.reset( new AxFrameModel ); break; 280cdf0e10cSrcweir case VBA_SITE_MULTIPAGE: break; // not supported 281cdf0e10cSrcweir case VBA_SITE_FORM: break; // not supported 282cdf0e10cSrcweir default: OSL_ENSURE( false, "VbaSiteModel::createControlModel - unknown type index" ); 283cdf0e10cSrcweir } 284cdf0e10cSrcweir } 285cdf0e10cSrcweir else 286cdf0e10cSrcweir { 287cdf0e10cSrcweir const OUString* pGuid = ContainerHelper::getVectorElement( rClassTable, nTypeIndex ); 288cdf0e10cSrcweir OSL_ENSURE( pGuid, "VbaSiteModel::createControlModel - invalid class table index" ); 289cdf0e10cSrcweir if( pGuid ) 290cdf0e10cSrcweir { 291cdf0e10cSrcweir if( pGuid->equalsAscii( COMCTL_GUID_SCROLLBAR_60 ) ) 292cdf0e10cSrcweir xCtrlModel.reset( new ComCtlScrollBarModel( 6 ) ); 293cdf0e10cSrcweir else if( pGuid->equalsAscii( COMCTL_GUID_PROGRESSBAR_50 ) ) 294cdf0e10cSrcweir xCtrlModel.reset( new ComCtlProgressBarModel( 5 ) ); 295cdf0e10cSrcweir else if( pGuid->equalsAscii( COMCTL_GUID_PROGRESSBAR_60 ) ) 296cdf0e10cSrcweir xCtrlModel.reset( new ComCtlProgressBarModel( 6 ) ); 297cdf0e10cSrcweir } 298cdf0e10cSrcweir } 299cdf0e10cSrcweir 300cdf0e10cSrcweir if( xCtrlModel.get() ) 301cdf0e10cSrcweir { 302cdf0e10cSrcweir // user form controls are AWT models 303cdf0e10cSrcweir xCtrlModel->setAwtModelMode(); 304cdf0e10cSrcweir 305cdf0e10cSrcweir // check that container model matches container flag in site data 306cdf0e10cSrcweir bool bModelIsContainer = dynamic_cast< const AxContainerModelBase* >( xCtrlModel.get() ) != 0; 307cdf0e10cSrcweir bool bTypeMatch = bModelIsContainer == isContainer(); 308cdf0e10cSrcweir OSL_ENSURE( bTypeMatch, "VbaSiteModel::createControlModel - container type does not match container flag" ); 309cdf0e10cSrcweir if( !bTypeMatch ) 310cdf0e10cSrcweir xCtrlModel.reset(); 311cdf0e10cSrcweir } 312cdf0e10cSrcweir return xCtrlModel; 313cdf0e10cSrcweir } 314cdf0e10cSrcweir 315cdf0e10cSrcweir void VbaSiteModel::convertProperties( PropertyMap& rPropMap, 316cdf0e10cSrcweir const ControlConverter& rConv, ApiControlType eCtrlType, sal_Int32 nCtrlIndex ) const 317cdf0e10cSrcweir { 318cdf0e10cSrcweir rPropMap.setProperty( PROP_Name, maName ); 319cdf0e10cSrcweir rPropMap.setProperty( PROP_Tag, maTag ); 320cdf0e10cSrcweir 321cdf0e10cSrcweir if( eCtrlType != API_CONTROL_DIALOG ) 322cdf0e10cSrcweir { 323cdf0e10cSrcweir rPropMap.setProperty( PROP_HelpText, maToolTip ); 324cdf0e10cSrcweir rPropMap.setProperty( PROP_EnableVisible, getFlag( mnFlags, VBA_SITE_VISIBLE ) ); 325cdf0e10cSrcweir // we need to set the passed control index to make option button groups work 326cdf0e10cSrcweir if( (0 <= nCtrlIndex) && (nCtrlIndex <= SAL_MAX_INT16) ) 327cdf0e10cSrcweir rPropMap.setProperty( PROP_TabIndex, static_cast< sal_Int16 >( nCtrlIndex ) ); 328cdf0e10cSrcweir // progress bar and group box support TabIndex, but not Tabstop... 329cdf0e10cSrcweir if( (eCtrlType != API_CONTROL_PROGRESSBAR) && (eCtrlType != API_CONTROL_GROUPBOX) && (eCtrlType != API_CONTROL_FRAME) && (eCtrlType != API_CONTROL_PAGE) ) 330cdf0e10cSrcweir rPropMap.setProperty( PROP_Tabstop, getFlag( mnFlags, VBA_SITE_TABSTOP ) ); 331cdf0e10cSrcweir rConv.convertPosition( rPropMap, maPos ); 332cdf0e10cSrcweir } 333cdf0e10cSrcweir } 334cdf0e10cSrcweir 335cdf0e10cSrcweir void VbaSiteModel::bindToSources( const Reference< XControlModel >& rxCtrlModel, const ControlConverter& rConv ) const 336cdf0e10cSrcweir { 337cdf0e10cSrcweir rConv.bindToSources( rxCtrlModel, maControlSource, maRowSource ); 338cdf0e10cSrcweir } 339cdf0e10cSrcweir 340cdf0e10cSrcweir // ============================================================================ 341cdf0e10cSrcweir 342cdf0e10cSrcweir VbaFormControl::VbaFormControl() 343cdf0e10cSrcweir { 344cdf0e10cSrcweir } 345cdf0e10cSrcweir 346cdf0e10cSrcweir VbaFormControl::~VbaFormControl() 347cdf0e10cSrcweir { 348cdf0e10cSrcweir } 349cdf0e10cSrcweir 350cdf0e10cSrcweir void VbaFormControl::importModelOrStorage( BinaryInputStream& rInStrm, StorageBase& rStrg, const AxClassTable& rClassTable ) 351cdf0e10cSrcweir { 352cdf0e10cSrcweir if( mxSiteModel.get() ) 353cdf0e10cSrcweir { 354cdf0e10cSrcweir if( mxSiteModel->isContainer() ) 355cdf0e10cSrcweir { 356cdf0e10cSrcweir StorageRef xSubStrg = rStrg.openSubStorage( mxSiteModel->getSubStorageName(), false ); 357cdf0e10cSrcweir OSL_ENSURE( xSubStrg.get(), "VbaFormControl::importModelOrStorage - cannot find storage for embedded control" ); 358cdf0e10cSrcweir if( xSubStrg.get() ) 359cdf0e10cSrcweir importStorage( *xSubStrg, rClassTable ); 360cdf0e10cSrcweir } 361cdf0e10cSrcweir else if( !rInStrm.isEof() ) 362cdf0e10cSrcweir { 363cdf0e10cSrcweir sal_Int64 nNextStrmPos = rInStrm.tell() + mxSiteModel->getStreamLength(); 364cdf0e10cSrcweir importControlModel( rInStrm, rClassTable ); 365cdf0e10cSrcweir rInStrm.seek( nNextStrmPos ); 366cdf0e10cSrcweir } 367cdf0e10cSrcweir } 368cdf0e10cSrcweir } 369cdf0e10cSrcweir 370cdf0e10cSrcweir OUString VbaFormControl::getControlName() const 371cdf0e10cSrcweir { 372cdf0e10cSrcweir return mxSiteModel.get() ? mxSiteModel->getName() : OUString(); 373cdf0e10cSrcweir } 374cdf0e10cSrcweir 375cdf0e10cSrcweir sal_Int32 VbaFormControl::getControlId() const 376cdf0e10cSrcweir { 377cdf0e10cSrcweir return mxSiteModel.get() ? mxSiteModel->getId() : -1; 378cdf0e10cSrcweir } 379cdf0e10cSrcweir 380cdf0e10cSrcweir void VbaFormControl::createAndConvert( sal_Int32 nCtrlIndex, 381cdf0e10cSrcweir const Reference< XNameContainer >& rxParentNC, const ControlConverter& rConv ) const 382cdf0e10cSrcweir { 383cdf0e10cSrcweir if( rxParentNC.is() && mxSiteModel.get() && mxCtrlModel.get() ) try 384cdf0e10cSrcweir { 385cdf0e10cSrcweir // create the control model 386cdf0e10cSrcweir OUString aServiceName = mxCtrlModel->getServiceName(); 387cdf0e10cSrcweir Reference< XMultiServiceFactory > xModelFactory( rxParentNC, UNO_QUERY_THROW ); 388cdf0e10cSrcweir Reference< XControlModel > xCtrlModel( xModelFactory->createInstance( aServiceName ), UNO_QUERY_THROW ); 389cdf0e10cSrcweir 390cdf0e10cSrcweir // convert all properties and embedded controls 391cdf0e10cSrcweir if( convertProperties( xCtrlModel, rConv, nCtrlIndex ) ) 392cdf0e10cSrcweir { 393cdf0e10cSrcweir // insert into parent container 394cdf0e10cSrcweir const OUString& rCtrlName = mxSiteModel->getName(); 395cdf0e10cSrcweir OSL_ENSURE( !rxParentNC->hasByName( rCtrlName ), "VbaFormControl::createAndConvert - multiple controls with equal name" ); 396cdf0e10cSrcweir ContainerHelper::insertByName( rxParentNC, rCtrlName, Any( xCtrlModel ) ); 397cdf0e10cSrcweir } 398cdf0e10cSrcweir } 399cdf0e10cSrcweir catch( Exception& ) 400cdf0e10cSrcweir { 401cdf0e10cSrcweir } 402cdf0e10cSrcweir } 403cdf0e10cSrcweir 404cdf0e10cSrcweir // protected ------------------------------------------------------------------ 405cdf0e10cSrcweir 406cdf0e10cSrcweir void VbaFormControl::importControlModel( BinaryInputStream& rInStrm, const AxClassTable& rClassTable ) 407cdf0e10cSrcweir { 408cdf0e10cSrcweir createControlModel( rClassTable ); 409cdf0e10cSrcweir if( mxCtrlModel.get() ) 410cdf0e10cSrcweir mxCtrlModel->importBinaryModel( rInStrm ); 411cdf0e10cSrcweir } 412cdf0e10cSrcweir 413cdf0e10cSrcweir void VbaFormControl::importStorage( StorageBase& rStrg, const AxClassTable& rClassTable ) 414cdf0e10cSrcweir { 415cdf0e10cSrcweir createControlModel( rClassTable ); 416cdf0e10cSrcweir AxContainerModelBase* pContainerModel = dynamic_cast< AxContainerModelBase* >( mxCtrlModel.get() ); 417cdf0e10cSrcweir OSL_ENSURE( pContainerModel, "VbaFormControl::importStorage - missing container control model" ); 418cdf0e10cSrcweir if( pContainerModel ) 419cdf0e10cSrcweir { 420cdf0e10cSrcweir /* Open the 'f' stream containing the model of this control and a list 421cdf0e10cSrcweir of site models for all child controls. */ 422cdf0e10cSrcweir BinaryXInputStream aFStrm( rStrg.openInputStream( CREATE_OUSTRING( "f" ) ), true ); 423cdf0e10cSrcweir OSL_ENSURE( !aFStrm.isEof(), "VbaFormControl::importStorage - missing 'f' stream" ); 424cdf0e10cSrcweir 425cdf0e10cSrcweir /* Read the properties of this container control and the class table 426cdf0e10cSrcweir (into the maClassTable vector) containing a list of GUIDs for 427cdf0e10cSrcweir exotic embedded controls. */ 428cdf0e10cSrcweir if( !aFStrm.isEof() && pContainerModel->importBinaryModel( aFStrm ) && pContainerModel->importClassTable( aFStrm, maClassTable ) ) 429cdf0e10cSrcweir { 430cdf0e10cSrcweir /* Read the site models of all embedded controls (this fills the 431cdf0e10cSrcweir maControls vector). Ignore failure of importSiteModels() but 432cdf0e10cSrcweir try to import as much controls as possible. */ 433cdf0e10cSrcweir importEmbeddedSiteModels( aFStrm ); 434cdf0e10cSrcweir 435cdf0e10cSrcweir /* Open the 'o' stream containing models of embedded simple 436cdf0e10cSrcweir controls. Stream may be empty or missing, if this control 437cdf0e10cSrcweir contains no controls or only container controls. */ 438cdf0e10cSrcweir BinaryXInputStream aOStrm( rStrg.openInputStream( CREATE_OUSTRING( "o" ) ), true ); 439cdf0e10cSrcweir 440cdf0e10cSrcweir /* Iterate over all embedded controls, import model from 'o' 441cdf0e10cSrcweir stream (for embedded simple controls) or from the substorage 442cdf0e10cSrcweir (for embedded container controls). */ 443cdf0e10cSrcweir maControls.forEachMem( &VbaFormControl::importModelOrStorage, 444cdf0e10cSrcweir ::boost::ref( aOStrm ), ::boost::ref( rStrg ), ::boost::cref( maClassTable ) ); 445cdf0e10cSrcweir 446cdf0e10cSrcweir /* Reorder the controls (sorts all option buttons of an option 447cdf0e10cSrcweir group together), and move all children of all embedded frames 448cdf0e10cSrcweir (group boxes) to this control (UNO group boxes cannot contain 449cdf0e10cSrcweir other controls). */ 450cdf0e10cSrcweir finalizeEmbeddedControls(); 451cdf0e10cSrcweir } 452cdf0e10cSrcweir } 453cdf0e10cSrcweir } 454cdf0e10cSrcweir 455cdf0e10cSrcweir bool VbaFormControl::convertProperties( const Reference< XControlModel >& rxCtrlModel, 456cdf0e10cSrcweir const ControlConverter& rConv, sal_Int32 nCtrlIndex ) const 457cdf0e10cSrcweir { 458cdf0e10cSrcweir if( rxCtrlModel.is() && mxSiteModel.get() && mxCtrlModel.get() ) 459cdf0e10cSrcweir { 460cdf0e10cSrcweir const OUString& rCtrlName = mxSiteModel->getName(); 461cdf0e10cSrcweir OSL_ENSURE( rCtrlName.getLength() > 0, "VbaFormControl::convertProperties - control without name" ); 462cdf0e10cSrcweir if( rCtrlName.getLength() > 0 ) 463cdf0e10cSrcweir { 464cdf0e10cSrcweir // convert all properties 465cdf0e10cSrcweir PropertyMap aPropMap; 466cdf0e10cSrcweir mxSiteModel->convertProperties( aPropMap, rConv, mxCtrlModel->getControlType(), nCtrlIndex ); 467cdf0e10cSrcweir mxCtrlModel->convertProperties( aPropMap, rConv ); 468cdf0e10cSrcweir mxCtrlModel->convertSize( aPropMap, rConv ); 469cdf0e10cSrcweir PropertySet aPropSet( rxCtrlModel ); 470cdf0e10cSrcweir aPropSet.setProperties( aPropMap ); 471cdf0e10cSrcweir 472cdf0e10cSrcweir // create and convert all embedded controls 473cdf0e10cSrcweir if( !maControls.empty() ) try 474cdf0e10cSrcweir { 475cdf0e10cSrcweir Reference< XNameContainer > xCtrlModelNC( rxCtrlModel, UNO_QUERY_THROW ); 476cdf0e10cSrcweir /* Call conversion for all controls. Pass vector index as new 477cdf0e10cSrcweir tab order to make option button groups work correctly. */ 478cdf0e10cSrcweir maControls.forEachMemWithIndex( &VbaFormControl::createAndConvert, 479cdf0e10cSrcweir ::boost::cref( xCtrlModelNC ), ::boost::cref( rConv ) ); 480cdf0e10cSrcweir } 481cdf0e10cSrcweir catch( Exception& ) 482cdf0e10cSrcweir { 483cdf0e10cSrcweir OSL_ENSURE( false, "VbaFormControl::convertProperties - cannot get control container interface" ); 484cdf0e10cSrcweir } 485cdf0e10cSrcweir 486cdf0e10cSrcweir return true; 487cdf0e10cSrcweir } 488cdf0e10cSrcweir } 489cdf0e10cSrcweir return false; 490cdf0e10cSrcweir } 491cdf0e10cSrcweir 492cdf0e10cSrcweir // private -------------------------------------------------------------------- 493cdf0e10cSrcweir 494cdf0e10cSrcweir void VbaFormControl::createControlModel( const AxClassTable& rClassTable ) 495cdf0e10cSrcweir { 496cdf0e10cSrcweir // derived classes may have created their own control model 497cdf0e10cSrcweir if( !mxCtrlModel && mxSiteModel.get() ) 498cdf0e10cSrcweir mxCtrlModel = mxSiteModel->createControlModel( rClassTable ); 499cdf0e10cSrcweir } 500cdf0e10cSrcweir 501cdf0e10cSrcweir bool VbaFormControl::importSiteModel( BinaryInputStream& rInStrm ) 502cdf0e10cSrcweir { 503cdf0e10cSrcweir mxSiteModel.reset( new VbaSiteModel ); 504cdf0e10cSrcweir return mxSiteModel->importBinaryModel( rInStrm ); 505cdf0e10cSrcweir } 506cdf0e10cSrcweir 507cdf0e10cSrcweir bool VbaFormControl::importEmbeddedSiteModels( BinaryInputStream& rInStrm ) 508cdf0e10cSrcweir { 509cdf0e10cSrcweir sal_uInt64 nAnchorPos = rInStrm.tell(); 510cdf0e10cSrcweir sal_uInt32 nSiteCount, nSiteDataSize; 511cdf0e10cSrcweir rInStrm >> nSiteCount >> nSiteDataSize; 512cdf0e10cSrcweir sal_Int64 nSiteEndPos = rInStrm.tell() + nSiteDataSize; 513cdf0e10cSrcweir 514cdf0e10cSrcweir // skip the site info structure 515cdf0e10cSrcweir sal_uInt32 nSiteIndex = 0; 516cdf0e10cSrcweir while( !rInStrm.isEof() && (nSiteIndex < nSiteCount) ) 517cdf0e10cSrcweir { 518cdf0e10cSrcweir rInStrm.skip( 1 ); // site depth 519cdf0e10cSrcweir sal_uInt8 nTypeCount = rInStrm.readuInt8(); // 'type-or-count' byte 520cdf0e10cSrcweir if( getFlag( nTypeCount, VBA_SITEINFO_COUNT ) ) 521cdf0e10cSrcweir { 522cdf0e10cSrcweir /* Count flag is set: the 'type-or-count' byte contains the number 523cdf0e10cSrcweir of controls in the lower bits, the type specifier follows in 524cdf0e10cSrcweir the next byte. The type specifier should always be 1 according 525cdf0e10cSrcweir to the specification. */ 526cdf0e10cSrcweir rInStrm.skip( 1 ); 527cdf0e10cSrcweir nSiteIndex += (nTypeCount & VBA_SITEINFO_MASK); 528cdf0e10cSrcweir } 529cdf0e10cSrcweir else 530cdf0e10cSrcweir { 531cdf0e10cSrcweir /* Count flag is not set: the 'type-or-count' byte contains the 532cdf0e10cSrcweir type specifier of *one* control in the lower bits (this type 533cdf0e10cSrcweir should be 1, see above). */ 534cdf0e10cSrcweir ++nSiteIndex; 535cdf0e10cSrcweir } 536cdf0e10cSrcweir } 537cdf0e10cSrcweir // align the stream to 32bit, relative to start of entire site info 538cdf0e10cSrcweir rInStrm.alignToBlock( 4, nAnchorPos ); 539cdf0e10cSrcweir 540cdf0e10cSrcweir // import the site models for all embedded controls 541cdf0e10cSrcweir maControls.clear(); 542cdf0e10cSrcweir bool bValid = !rInStrm.isEof(); 543cdf0e10cSrcweir for( nSiteIndex = 0; bValid && (nSiteIndex < nSiteCount); ++nSiteIndex ) 544cdf0e10cSrcweir { 545cdf0e10cSrcweir VbaFormControlRef xControl( new VbaFormControl ); 546cdf0e10cSrcweir maControls.push_back( xControl ); 547cdf0e10cSrcweir bValid = xControl->importSiteModel( rInStrm ); 548cdf0e10cSrcweir } 549cdf0e10cSrcweir 550cdf0e10cSrcweir rInStrm.seek( nSiteEndPos ); 551cdf0e10cSrcweir return bValid; 552cdf0e10cSrcweir } 553cdf0e10cSrcweir 554cdf0e10cSrcweir void VbaFormControl::finalizeEmbeddedControls() 555cdf0e10cSrcweir { 556cdf0e10cSrcweir /* This function performs two tasks: 557cdf0e10cSrcweir 558cdf0e10cSrcweir 1) Reorder the controls appropriately (sort all option buttons of an 559cdf0e10cSrcweir option group together to make grouping work). 560cdf0e10cSrcweir 2) Move all children of all embedded frames (group boxes) to this 561cdf0e10cSrcweir control (UNO group boxes cannot contain other controls). 562cdf0e10cSrcweir */ 563cdf0e10cSrcweir 564cdf0e10cSrcweir // first, sort all controls by original tab index 565cdf0e10cSrcweir ::std::sort( maControls.begin(), maControls.end(), &compareByTabIndex ); 566cdf0e10cSrcweir 567cdf0e10cSrcweir /* Collect the programmatical names of all embedded controls (needed to be 568cdf0e10cSrcweir able to set unused names to new dummy controls created below). Also 569cdf0e10cSrcweir collect the names of all children of embedded frames (group boxes). 570cdf0e10cSrcweir Luckily, names of controls must be unique in the entire form, not just 571cdf0e10cSrcweir in the current container. */ 572cdf0e10cSrcweir VbaControlNamesSet aControlNames; 573cdf0e10cSrcweir VbaControlNameInserter aInserter( aControlNames ); 574cdf0e10cSrcweir maControls.forEach( aInserter ); 575cdf0e10cSrcweir for( VbaFormControlVector::iterator aIt = maControls.begin(), aEnd = maControls.end(); aIt != aEnd; ++aIt ) 576cdf0e10cSrcweir if( (*aIt)->mxCtrlModel.get() && ((*aIt)->mxCtrlModel->getControlType() == API_CONTROL_GROUPBOX) ) 577cdf0e10cSrcweir (*aIt)->maControls.forEach( aInserter ); 578cdf0e10cSrcweir 579cdf0e10cSrcweir /* Reprocess the sorted list and collect all option button controls that 580cdf0e10cSrcweir are part of the same option group (determined by group name). All 581cdf0e10cSrcweir controls will be stored in a vector of vectors, that collects every 582cdf0e10cSrcweir option button group in one vector element, and other controls between 583cdf0e10cSrcweir these option groups (or leading or trailing controls) in other vector 584cdf0e10cSrcweir elements. If an option button group follows another group, a dummy 585cdf0e10cSrcweir separator control has to be inserted. */ 586cdf0e10cSrcweir typedef RefVector< VbaFormControlVector > VbaFormControlVectorVector; 587cdf0e10cSrcweir VbaFormControlVectorVector aControlGroups; 588cdf0e10cSrcweir 589cdf0e10cSrcweir typedef RefMap< OUString, VbaFormControlVector > VbaFormControlVectorMap; 590cdf0e10cSrcweir VbaFormControlVectorMap aOptionGroups; 591cdf0e10cSrcweir 592cdf0e10cSrcweir typedef VbaFormControlVectorMap::mapped_type VbaFormControlVectorRef; 593cdf0e10cSrcweir bool bLastWasOptionButton = false; 594cdf0e10cSrcweir for( VbaFormControlVector::iterator aIt = maControls.begin(), aEnd = maControls.end(); aIt != aEnd; ++aIt ) 595cdf0e10cSrcweir { 596cdf0e10cSrcweir VbaFormControlRef xControl = *aIt; 597cdf0e10cSrcweir const ControlModelBase* pCtrlModel = xControl->mxCtrlModel.get(); 598cdf0e10cSrcweir 599cdf0e10cSrcweir if( const AxOptionButtonModel* pOptButtonModel = dynamic_cast< const AxOptionButtonModel* >( pCtrlModel ) ) 600cdf0e10cSrcweir { 601cdf0e10cSrcweir // check if a new option group needs to be created 602cdf0e10cSrcweir const OUString& rGroupName = pOptButtonModel->getGroupName(); 603cdf0e10cSrcweir VbaFormControlVectorRef& rxOptionGroup = aOptionGroups[ rGroupName ]; 604cdf0e10cSrcweir if( !rxOptionGroup ) 605cdf0e10cSrcweir { 606cdf0e10cSrcweir /* If last control was an option button too, we have two 607cdf0e10cSrcweir option groups following each other, so a dummy separator 608cdf0e10cSrcweir control is needed. */ 609cdf0e10cSrcweir if( bLastWasOptionButton ) 610cdf0e10cSrcweir { 611cdf0e10cSrcweir VbaFormControlVectorRef xDummyGroup( new VbaFormControlVector ); 612cdf0e10cSrcweir aControlGroups.push_back( xDummyGroup ); 613cdf0e10cSrcweir OUString aName = aControlNames.generateDummyName(); 614cdf0e10cSrcweir VbaFormControlRef xDummyControl( new VbaDummyFormControl( aName ) ); 615cdf0e10cSrcweir xDummyGroup->push_back( xDummyControl ); 616cdf0e10cSrcweir } 617cdf0e10cSrcweir rxOptionGroup.reset( new VbaFormControlVector ); 618cdf0e10cSrcweir aControlGroups.push_back( rxOptionGroup ); 619cdf0e10cSrcweir } 620cdf0e10cSrcweir /* Append the option button to the control group (which is now 621cdf0e10cSrcweir referred by the vector aControlGroups and by the map 622cdf0e10cSrcweir aOptionGroups). */ 623cdf0e10cSrcweir rxOptionGroup->push_back( xControl ); 624cdf0e10cSrcweir bLastWasOptionButton = true; 625cdf0e10cSrcweir } 626cdf0e10cSrcweir else 627cdf0e10cSrcweir { 628cdf0e10cSrcweir // open a new control group, if the last group is an option group 629cdf0e10cSrcweir if( bLastWasOptionButton || aControlGroups.empty() ) 630cdf0e10cSrcweir { 631cdf0e10cSrcweir VbaFormControlVectorRef xControlGroup( new VbaFormControlVector ); 632cdf0e10cSrcweir aControlGroups.push_back( xControlGroup ); 633cdf0e10cSrcweir } 634cdf0e10cSrcweir // append the control to the last control group 635cdf0e10cSrcweir VbaFormControlVector& rLastGroup = *aControlGroups.back(); 636cdf0e10cSrcweir rLastGroup.push_back( xControl ); 637cdf0e10cSrcweir bLastWasOptionButton = false; 638cdf0e10cSrcweir 639cdf0e10cSrcweir // if control is a group box, move all its children to this control 640cdf0e10cSrcweir if( pCtrlModel && (pCtrlModel->getControlType() == API_CONTROL_GROUPBOX) ) 641cdf0e10cSrcweir { 642cdf0e10cSrcweir /* Move all embedded controls of the group box relative to the 643cdf0e10cSrcweir position of the group box. */ 644cdf0e10cSrcweir xControl->moveEmbeddedToAbsoluteParent(); 645cdf0e10cSrcweir /* Insert all children of the group box into the last control 646cdf0e10cSrcweir group (following the group box). */ 647cdf0e10cSrcweir rLastGroup.insert( rLastGroup.end(), xControl->maControls.begin(), xControl->maControls.end() ); 648cdf0e10cSrcweir xControl->maControls.clear(); 649cdf0e10cSrcweir // check if last control of the group box is an option button 650cdf0e10cSrcweir bLastWasOptionButton = dynamic_cast< const AxOptionButtonModel* >( rLastGroup.back()->mxCtrlModel.get() ) != 0; 651cdf0e10cSrcweir } 652cdf0e10cSrcweir } 653cdf0e10cSrcweir } 654cdf0e10cSrcweir 655cdf0e10cSrcweir // flatten the vector of vectors of form controls to a single vector 656cdf0e10cSrcweir maControls.clear(); 657cdf0e10cSrcweir for( VbaFormControlVectorVector::iterator aIt = aControlGroups.begin(), aEnd = aControlGroups.end(); aIt != aEnd; ++aIt ) 658cdf0e10cSrcweir maControls.insert( maControls.end(), (*aIt)->begin(), (*aIt)->end() ); 659cdf0e10cSrcweir } 660cdf0e10cSrcweir 661cdf0e10cSrcweir void VbaFormControl::moveRelative( const AxPairData& rDistance ) 662cdf0e10cSrcweir { 663cdf0e10cSrcweir if( mxSiteModel.get() ) 664cdf0e10cSrcweir mxSiteModel->moveRelative( rDistance ); 665cdf0e10cSrcweir } 666cdf0e10cSrcweir 667cdf0e10cSrcweir void VbaFormControl::moveEmbeddedToAbsoluteParent() 668cdf0e10cSrcweir { 669cdf0e10cSrcweir if( mxSiteModel.get() && !maControls.empty() ) 670cdf0e10cSrcweir { 671cdf0e10cSrcweir // distance to move is equal to position of this control in its parent 672cdf0e10cSrcweir AxPairData aDistance = mxSiteModel->getPosition(); 673cdf0e10cSrcweir 674cdf0e10cSrcweir /* For group boxes: add half of the font height to Y position (VBA 675cdf0e10cSrcweir positions relative to frame border line, not to 'top' of frame). */ 676cdf0e10cSrcweir const AxFontDataModel* pFontModel = dynamic_cast< const AxFontDataModel* >( mxCtrlModel.get() ); 677cdf0e10cSrcweir if( pFontModel && (pFontModel->getControlType() == API_CONTROL_GROUPBOX) ) 678cdf0e10cSrcweir { 679cdf0e10cSrcweir // convert points to 1/100 mm (1 pt = 1/72 inch = 2.54/72 cm = 2540/72 1/100 mm) 680cdf0e10cSrcweir sal_Int32 nFontHeight = static_cast< sal_Int32 >( pFontModel->getFontHeight() * 2540 / 72 ); 681cdf0e10cSrcweir aDistance.second += nFontHeight / 2; 682cdf0e10cSrcweir } 683cdf0e10cSrcweir 684cdf0e10cSrcweir // move the embedded controls 685cdf0e10cSrcweir maControls.forEachMem( &VbaFormControl::moveRelative, ::boost::cref( aDistance ) ); 686cdf0e10cSrcweir } 687cdf0e10cSrcweir } 688cdf0e10cSrcweir 689cdf0e10cSrcweir /*static*/ bool VbaFormControl::compareByTabIndex( const VbaFormControlRef& rxLeft, const VbaFormControlRef& rxRight ) 690cdf0e10cSrcweir { 691cdf0e10cSrcweir // sort controls without model to the end 692cdf0e10cSrcweir sal_Int32 nLeftTabIndex = rxLeft->mxSiteModel.get() ? rxLeft->mxSiteModel->getTabIndex() : SAL_MAX_INT32; 693cdf0e10cSrcweir sal_Int32 nRightTabIndex = rxRight->mxSiteModel.get() ? rxRight->mxSiteModel->getTabIndex() : SAL_MAX_INT32; 694cdf0e10cSrcweir return nLeftTabIndex < nRightTabIndex; 695cdf0e10cSrcweir } 696cdf0e10cSrcweir 697cdf0e10cSrcweir // ============================================================================ 698cdf0e10cSrcweir 699cdf0e10cSrcweir namespace { 700cdf0e10cSrcweir 701cdf0e10cSrcweir OUString lclGetQuotedString( const OUString& rCodeLine ) 702cdf0e10cSrcweir { 703cdf0e10cSrcweir OUStringBuffer aBuffer; 704cdf0e10cSrcweir sal_Int32 nLen = rCodeLine.getLength(); 705cdf0e10cSrcweir if( (nLen > 0) && (rCodeLine[ 0 ] == '"') ) 706cdf0e10cSrcweir { 707cdf0e10cSrcweir bool bExitLoop = false; 708cdf0e10cSrcweir for( sal_Int32 nIndex = 1; !bExitLoop && (nIndex < nLen); ++nIndex ) 709cdf0e10cSrcweir { 710cdf0e10cSrcweir sal_Unicode cChar = rCodeLine[ nIndex ]; 711cdf0e10cSrcweir // exit on closing quote char (but check on double quote chars) 712cdf0e10cSrcweir bExitLoop = (cChar == '"') && ((nIndex + 1 == nLen) || (rCodeLine[ nIndex + 1 ] != '"')); 713cdf0e10cSrcweir if( !bExitLoop ) 714cdf0e10cSrcweir { 715cdf0e10cSrcweir aBuffer.append( cChar ); 716cdf0e10cSrcweir // skip second quote char 717cdf0e10cSrcweir if( cChar == '"' ) 718cdf0e10cSrcweir ++nIndex; 719cdf0e10cSrcweir } 720cdf0e10cSrcweir } 721cdf0e10cSrcweir } 722cdf0e10cSrcweir return aBuffer.makeStringAndClear(); 723cdf0e10cSrcweir } 724cdf0e10cSrcweir 725cdf0e10cSrcweir bool lclEatWhitespace( OUString& rCodeLine ) 726cdf0e10cSrcweir { 727cdf0e10cSrcweir sal_Int32 nIndex = 0; 728cdf0e10cSrcweir while( (nIndex < rCodeLine.getLength()) && ((rCodeLine[ nIndex ] == ' ') || (rCodeLine[ nIndex ] == '\t')) ) 729cdf0e10cSrcweir ++nIndex; 730cdf0e10cSrcweir if( nIndex > 0 ) 731cdf0e10cSrcweir { 732cdf0e10cSrcweir rCodeLine = rCodeLine.copy( nIndex ); 733cdf0e10cSrcweir return true; 734cdf0e10cSrcweir } 735cdf0e10cSrcweir return false; 736cdf0e10cSrcweir } 737cdf0e10cSrcweir 738cdf0e10cSrcweir bool lclEatKeyword( OUString& rCodeLine, const OUString& rKeyword ) 739cdf0e10cSrcweir { 740cdf0e10cSrcweir if( rCodeLine.matchIgnoreAsciiCase( rKeyword ) ) 741cdf0e10cSrcweir { 742cdf0e10cSrcweir rCodeLine = rCodeLine.copy( rKeyword.getLength() ); 743cdf0e10cSrcweir // success, if code line ends after keyword, or if whitespace follows 744cdf0e10cSrcweir return (rCodeLine.getLength() == 0) || lclEatWhitespace( rCodeLine ); 745cdf0e10cSrcweir } 746cdf0e10cSrcweir return false; 747cdf0e10cSrcweir } 748cdf0e10cSrcweir 749cdf0e10cSrcweir } // namespace 750cdf0e10cSrcweir 751cdf0e10cSrcweir // ---------------------------------------------------------------------------- 752cdf0e10cSrcweir 753cdf0e10cSrcweir VbaUserForm::VbaUserForm( const Reference< XComponentContext >& rxContext, 754cdf0e10cSrcweir const Reference< XModel >& rxDocModel, const GraphicHelper& rGraphicHelper, bool bDefaultColorBgr ) : 755cdf0e10cSrcweir mxContext( rxContext ), 756cdf0e10cSrcweir mxDocModel( rxDocModel ), 757cdf0e10cSrcweir maConverter( rxDocModel, rGraphicHelper, bDefaultColorBgr ) 758cdf0e10cSrcweir { 759cdf0e10cSrcweir OSL_ENSURE( mxContext.is(), "VbaUserForm::VbaUserForm - missing component context" ); 760cdf0e10cSrcweir OSL_ENSURE( mxDocModel.is(), "VbaUserForm::VbaUserForm - missing document model" ); 761cdf0e10cSrcweir } 762cdf0e10cSrcweir 763cdf0e10cSrcweir void VbaUserForm::importForm( const Reference< XNameContainer >& rxDialogLib, 764cdf0e10cSrcweir StorageBase& rVbaFormStrg, const OUString& rModuleName, rtl_TextEncoding eTextEnc ) 765cdf0e10cSrcweir { 766cdf0e10cSrcweir OSL_ENSURE( rxDialogLib.is(), "VbaUserForm::importForm - missing dialog library" ); 767cdf0e10cSrcweir if( !mxContext.is() || !mxDocModel.is() || !rxDialogLib.is() ) 768cdf0e10cSrcweir return; 769cdf0e10cSrcweir 770cdf0e10cSrcweir // check that the '03VBFrame' stream exists, this is required for forms 771cdf0e10cSrcweir BinaryXInputStream aInStrm( rVbaFormStrg.openInputStream( CREATE_OUSTRING( "\003VBFrame" ) ), true ); 772cdf0e10cSrcweir OSL_ENSURE( !aInStrm.isEof(), "VbaUserForm::importForm - missing \\003VBFrame stream" ); 773cdf0e10cSrcweir if( aInStrm.isEof() ) 774cdf0e10cSrcweir return; 775cdf0e10cSrcweir 776cdf0e10cSrcweir // scan for the line 'Begin {GUID} <FormName>' 777cdf0e10cSrcweir TextInputStream aFrameTextStrm( mxContext, aInStrm, eTextEnc ); 778cdf0e10cSrcweir const OUString aBegin = CREATE_OUSTRING( "Begin" ); 779cdf0e10cSrcweir OUString aLine; 780cdf0e10cSrcweir bool bBeginFound = false; 781cdf0e10cSrcweir while( !bBeginFound && !aFrameTextStrm.isEof() ) 782cdf0e10cSrcweir { 783cdf0e10cSrcweir aLine = aFrameTextStrm.readLine().trim(); 784cdf0e10cSrcweir bBeginFound = lclEatKeyword( aLine, aBegin ); 785cdf0e10cSrcweir } 786cdf0e10cSrcweir // check for the specific GUID that represents VBA forms 787cdf0e10cSrcweir if( !bBeginFound || !lclEatKeyword( aLine, CREATE_OUSTRING( "{C62A69F0-16DC-11CE-9E98-00AA00574A4F}" ) ) ) 788cdf0e10cSrcweir return; 789cdf0e10cSrcweir 790cdf0e10cSrcweir // remaining line is the form name 791cdf0e10cSrcweir OUString aFormName = aLine.trim(); 792cdf0e10cSrcweir OSL_ENSURE( aFormName.getLength() > 0, "VbaUserForm::importForm - missing form name" ); 793cdf0e10cSrcweir OSL_ENSURE( rModuleName.equalsIgnoreAsciiCase( aFormName ), "VbaUserForm::importFrameStream - form and module name mismatch" ); 794cdf0e10cSrcweir if( aFormName.getLength() == 0 ) 795cdf0e10cSrcweir aFormName = rModuleName; 796cdf0e10cSrcweir if( aFormName.getLength() == 0 ) 797cdf0e10cSrcweir return; 798cdf0e10cSrcweir mxSiteModel.reset( new VbaSiteModel ); 799cdf0e10cSrcweir mxSiteModel->importProperty( XML_Name, aFormName ); 800cdf0e10cSrcweir 801cdf0e10cSrcweir // read the form properties (caption is contained in this '03VBFrame' stream, not in the 'f' stream) 802cdf0e10cSrcweir mxCtrlModel.reset( new AxUserFormModel ); 803cdf0e10cSrcweir OUString aKey, aValue; 804cdf0e10cSrcweir bool bExitLoop = false; 805cdf0e10cSrcweir while( !bExitLoop && !aFrameTextStrm.isEof() ) 806cdf0e10cSrcweir { 807cdf0e10cSrcweir aLine = aFrameTextStrm.readLine().trim(); 808cdf0e10cSrcweir bExitLoop = aLine.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "End" ) ); 809cdf0e10cSrcweir if( !bExitLoop && VbaHelper::extractKeyValue( aKey, aValue, aLine ) ) 810cdf0e10cSrcweir { 811cdf0e10cSrcweir if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "Caption" ) ) ) 812cdf0e10cSrcweir mxCtrlModel->importProperty( XML_Caption, lclGetQuotedString( aValue ) ); 813cdf0e10cSrcweir else if( aKey.equalsIgnoreAsciiCaseAsciiL( RTL_CONSTASCII_STRINGPARAM( "Tag" ) ) ) 814cdf0e10cSrcweir mxSiteModel->importProperty( XML_Tag, lclGetQuotedString( aValue ) ); 815cdf0e10cSrcweir } 816cdf0e10cSrcweir } 817cdf0e10cSrcweir 818cdf0e10cSrcweir // use generic container control functionality to import the embedded controls 819cdf0e10cSrcweir importStorage( rVbaFormStrg, AxClassTable() ); 820cdf0e10cSrcweir 821cdf0e10cSrcweir try 822cdf0e10cSrcweir { 823cdf0e10cSrcweir // create the dialog model 824cdf0e10cSrcweir OUString aServiceName = mxCtrlModel->getServiceName(); 825cdf0e10cSrcweir Reference< XMultiServiceFactory > xFactory( mxContext->getServiceManager(), UNO_QUERY_THROW ); 826cdf0e10cSrcweir Reference< XControlModel > xDialogModel( xFactory->createInstance( aServiceName ), UNO_QUERY_THROW ); 827cdf0e10cSrcweir Reference< XNameContainer > xDialogNC( xDialogModel, UNO_QUERY_THROW ); 828cdf0e10cSrcweir 829cdf0e10cSrcweir // convert properties and embedded controls 830cdf0e10cSrcweir if( convertProperties( xDialogModel, maConverter, 0 ) ) 831cdf0e10cSrcweir { 832cdf0e10cSrcweir // export the dialog to XML and insert it into the dialog library 833cdf0e10cSrcweir Reference< XInputStreamProvider > xDialogSource( ::xmlscript::exportDialogModel( xDialogNC, mxContext ), UNO_SET_THROW ); 834cdf0e10cSrcweir OSL_ENSURE( !rxDialogLib->hasByName( aFormName ), "VbaUserForm::importForm - multiple dialogs with equal name" ); 835cdf0e10cSrcweir ContainerHelper::insertByName( rxDialogLib, aFormName, Any( xDialogSource ) ); 836cdf0e10cSrcweir } 837cdf0e10cSrcweir } 838cdf0e10cSrcweir catch( Exception& ) 839cdf0e10cSrcweir { 840cdf0e10cSrcweir } 841cdf0e10cSrcweir } 842cdf0e10cSrcweir 843cdf0e10cSrcweir // ============================================================================ 844cdf0e10cSrcweir 845cdf0e10cSrcweir } // namespace ole 846cdf0e10cSrcweir } // namespace oox 847