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