1*ca5ec200SAndrew Rist /**************************************************************
2*ca5ec200SAndrew Rist *
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
10*ca5ec200SAndrew Rist *
11*ca5ec200SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
12*ca5ec200SAndrew Rist *
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.
19*ca5ec200SAndrew Rist *
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
VbaControlNamesSet()114cdf0e10cSrcweir VbaControlNamesSet::VbaControlNamesSet() :
115cdf0e10cSrcweir maDummyBaseName( CREATE_OUSTRING( "DummyGroupSep" ) ),
116cdf0e10cSrcweir mnIndex( 0 )
117cdf0e10cSrcweir {
118cdf0e10cSrcweir }
119cdf0e10cSrcweir
insertName(const VbaFormControl & rControl)120cdf0e10cSrcweir void VbaControlNamesSet::insertName( const VbaFormControl& rControl )
121cdf0e10cSrcweir {
122cdf0e10cSrcweir OUString aName = rControl.getControlName();
123cdf0e10cSrcweir if( aName.getLength() > 0 )
124cdf0e10cSrcweir maCtrlNames.insert( aName );
125cdf0e10cSrcweir }
126cdf0e10cSrcweir
generateDummyName()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;
VbaControlNameInserteroox::ole::__anonb87a37450111::VbaControlNameInserter146cdf0e10cSrcweir inline explicit VbaControlNameInserter( VbaControlNamesSet& rCtrlNames ) : mrCtrlNames( rCtrlNames ) {}
operator ()oox::ole::__anonb87a37450111::VbaControlNameInserter147cdf0e10cSrcweir 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
VbaDummyFormControl(const OUString & rName)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
VbaSiteModel()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
~VbaSiteModel()188cdf0e10cSrcweir VbaSiteModel::~VbaSiteModel()
189cdf0e10cSrcweir {
190cdf0e10cSrcweir }
191cdf0e10cSrcweir
importProperty(sal_Int32 nPropId,const OUString & rValue)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
importBinaryModel(BinaryInputStream & rInStrm)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
moveRelative(const AxPairData & rDistance)223cdf0e10cSrcweir void VbaSiteModel::moveRelative( const AxPairData& rDistance )
224cdf0e10cSrcweir {
225cdf0e10cSrcweir maPos.first += rDistance.first;
226cdf0e10cSrcweir maPos.second += rDistance.second;
227cdf0e10cSrcweir }
228cdf0e10cSrcweir
isVisible() const229cdf0e10cSrcweir bool VbaSiteModel::isVisible() const
230cdf0e10cSrcweir {
231cdf0e10cSrcweir return getFlag( mnFlags, VBA_SITE_VISIBLE );
232cdf0e10cSrcweir }
233cdf0e10cSrcweir
isContainer() const234cdf0e10cSrcweir bool VbaSiteModel::isContainer() const
235cdf0e10cSrcweir {
236cdf0e10cSrcweir return !getFlag( mnFlags, VBA_SITE_OSTREAM );
237cdf0e10cSrcweir }
238cdf0e10cSrcweir
getStreamLength() const239cdf0e10cSrcweir sal_uInt32 VbaSiteModel::getStreamLength() const
240cdf0e10cSrcweir {
241cdf0e10cSrcweir return isContainer() ? 0 : mnStreamLen;
242cdf0e10cSrcweir }
243cdf0e10cSrcweir
getSubStorageName() const244cdf0e10cSrcweir 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
createControlModel(const AxClassTable & rClassTable) const258cdf0e10cSrcweir 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
convertProperties(PropertyMap & rPropMap,const ControlConverter & rConv,ApiControlType eCtrlType,sal_Int32 nCtrlIndex) const315cdf0e10cSrcweir 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
bindToSources(const Reference<XControlModel> & rxCtrlModel,const ControlConverter & rConv) const335cdf0e10cSrcweir void VbaSiteModel::bindToSources( const Reference< XControlModel >& rxCtrlModel, const ControlConverter& rConv ) const
336cdf0e10cSrcweir {
337cdf0e10cSrcweir rConv.bindToSources( rxCtrlModel, maControlSource, maRowSource );
338cdf0e10cSrcweir }
339cdf0e10cSrcweir
340cdf0e10cSrcweir // ============================================================================
341cdf0e10cSrcweir
VbaFormControl()342cdf0e10cSrcweir VbaFormControl::VbaFormControl()
343cdf0e10cSrcweir {
344cdf0e10cSrcweir }
345cdf0e10cSrcweir
~VbaFormControl()346cdf0e10cSrcweir VbaFormControl::~VbaFormControl()
347cdf0e10cSrcweir {
348cdf0e10cSrcweir }
349cdf0e10cSrcweir
importModelOrStorage(BinaryInputStream & rInStrm,StorageBase & rStrg,const AxClassTable & rClassTable)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
getControlName() const370cdf0e10cSrcweir OUString VbaFormControl::getControlName() const
371cdf0e10cSrcweir {
372cdf0e10cSrcweir return mxSiteModel.get() ? mxSiteModel->getName() : OUString();
373cdf0e10cSrcweir }
374cdf0e10cSrcweir
getControlId() const375cdf0e10cSrcweir sal_Int32 VbaFormControl::getControlId() const
376cdf0e10cSrcweir {
377cdf0e10cSrcweir return mxSiteModel.get() ? mxSiteModel->getId() : -1;
378cdf0e10cSrcweir }
379cdf0e10cSrcweir
createAndConvert(sal_Int32 nCtrlIndex,const Reference<XNameContainer> & rxParentNC,const ControlConverter & rConv) const380cdf0e10cSrcweir 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
importControlModel(BinaryInputStream & rInStrm,const AxClassTable & rClassTable)406cdf0e10cSrcweir void VbaFormControl::importControlModel( BinaryInputStream& rInStrm, const AxClassTable& rClassTable )
407cdf0e10cSrcweir {
408cdf0e10cSrcweir createControlModel( rClassTable );
409cdf0e10cSrcweir if( mxCtrlModel.get() )
410cdf0e10cSrcweir mxCtrlModel->importBinaryModel( rInStrm );
411cdf0e10cSrcweir }
412cdf0e10cSrcweir
importStorage(StorageBase & rStrg,const AxClassTable & rClassTable)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
convertProperties(const Reference<XControlModel> & rxCtrlModel,const ControlConverter & rConv,sal_Int32 nCtrlIndex) const455cdf0e10cSrcweir 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
createControlModel(const AxClassTable & rClassTable)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
importSiteModel(BinaryInputStream & rInStrm)501cdf0e10cSrcweir bool VbaFormControl::importSiteModel( BinaryInputStream& rInStrm )
502cdf0e10cSrcweir {
503cdf0e10cSrcweir mxSiteModel.reset( new VbaSiteModel );
504cdf0e10cSrcweir return mxSiteModel->importBinaryModel( rInStrm );
505cdf0e10cSrcweir }
506cdf0e10cSrcweir
importEmbeddedSiteModels(BinaryInputStream & rInStrm)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
finalizeEmbeddedControls()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
moveRelative(const AxPairData & rDistance)661cdf0e10cSrcweir void VbaFormControl::moveRelative( const AxPairData& rDistance )
662cdf0e10cSrcweir {
663cdf0e10cSrcweir if( mxSiteModel.get() )
664cdf0e10cSrcweir mxSiteModel->moveRelative( rDistance );
665cdf0e10cSrcweir }
666cdf0e10cSrcweir
moveEmbeddedToAbsoluteParent()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
compareByTabIndex(const VbaFormControlRef & rxLeft,const VbaFormControlRef & rxRight)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
lclGetQuotedString(const OUString & rCodeLine)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
lclEatWhitespace(OUString & rCodeLine)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
lclEatKeyword(OUString & rCodeLine,const OUString & rKeyword)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
VbaUserForm(const Reference<XComponentContext> & rxContext,const Reference<XModel> & rxDocModel,const GraphicHelper & rGraphicHelper,bool bDefaultColorBgr)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
importForm(const Reference<XNameContainer> & rxDialogLib,StorageBase & rVbaFormStrg,const OUString & rModuleName,rtl_TextEncoding eTextEnc)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