xref: /aoo41x/main/oox/source/ole/vbacontrol.cxx (revision ca5ec200)
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