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