/src/libreoffice/svx/source/form/fmpgeimp.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | |
21 | | #include <fmpgeimp.hxx> |
22 | | #include <fmundo.hxx> |
23 | | #include <svx/fmtools.hxx> |
24 | | #include <fmprop.hxx> |
25 | | #include <fmservs.hxx> |
26 | | #include <fmobj.hxx> |
27 | | #include <formcontrolfactory.hxx> |
28 | | #include <svx/svditer.hxx> |
29 | | #include <svx/strings.hrc> |
30 | | #include <treevisitor.hxx> |
31 | | |
32 | | #include <com/sun/star/sdb/CommandType.hpp> |
33 | | #include <com/sun/star/sdbc/XRowSet.hpp> |
34 | | #include <com/sun/star/container/EnumerableMap.hpp> |
35 | | #include <com/sun/star/drawing/XControlShape.hpp> |
36 | | #include <com/sun/star/form/Forms.hpp> |
37 | | #include <com/sun/star/form/FormComponentType.hpp> |
38 | | |
39 | | #include <sal/log.hxx> |
40 | | #include <sfx2/objsh.hxx> |
41 | | #include <svx/fmpage.hxx> |
42 | | #include <svx/fmmodel.hxx> |
43 | | #include <tools/debug.hxx> |
44 | | #include <comphelper/diagnose_ex.hxx> |
45 | | #include <svx/dialmgr.hxx> |
46 | | #include <comphelper/processfactory.hxx> |
47 | | #include <comphelper/types.hxx> |
48 | | #include <connectivity/dbtools.hxx> |
49 | | |
50 | | using namespace ::com::sun::star::uno; |
51 | | using namespace ::com::sun::star::lang; |
52 | | using namespace ::com::sun::star::sdbc; |
53 | | using namespace ::com::sun::star::sdb; |
54 | | using namespace ::com::sun::star::container; |
55 | | using namespace ::com::sun::star::beans; |
56 | | using namespace ::com::sun::star::form; |
57 | | using ::com::sun::star::awt::XControlModel; |
58 | | using ::com::sun::star::container::XMap; |
59 | | using ::com::sun::star::container::EnumerableMap; |
60 | | using ::com::sun::star::drawing::XControlShape; |
61 | | using namespace ::svxform; |
62 | | using namespace ::dbtools; |
63 | | |
64 | | |
65 | | FmFormPageImpl::FmFormPageImpl( FmFormPage& _rPage ) |
66 | 718k | :m_rPage( _rPage ) |
67 | 718k | ,m_bFirstActivation( true ) |
68 | 718k | ,m_bAttemptedFormCreation( false ) |
69 | 718k | { |
70 | 718k | } |
71 | | |
72 | | |
73 | | namespace |
74 | | { |
75 | | class FormComponentInfo |
76 | | { |
77 | | public: |
78 | | static size_t childCount( const Reference< XInterface >& _component ) |
79 | 0 | { |
80 | 0 | Reference< XIndexAccess > xContainer( _component, UNO_QUERY ); |
81 | 0 | if ( xContainer.is() ) |
82 | 0 | return xContainer->getCount(); |
83 | 0 | return 0; |
84 | 0 | } |
85 | | |
86 | | static Reference< XInterface > getChild( const Reference< XInterface >& _component, size_t _index ) |
87 | 0 | { |
88 | 0 | Reference< XIndexAccess > xContainer( _component, UNO_QUERY_THROW ); |
89 | 0 | return Reference< XInterface >( xContainer->getByIndex( _index ), UNO_QUERY ); |
90 | 0 | } |
91 | | }; |
92 | | |
93 | | typedef ::std::pair< Reference< XInterface >, Reference< XInterface > > FormComponentPair; |
94 | | |
95 | | class FormHierarchyComparator |
96 | | { |
97 | | public: |
98 | | FormHierarchyComparator() |
99 | 0 | { |
100 | 0 | } |
101 | | |
102 | | static size_t childCount( const FormComponentPair& _components ) |
103 | 0 | { |
104 | 0 | size_t lhsCount = FormComponentInfo::childCount( _components.first ); |
105 | 0 | size_t rhsCount = FormComponentInfo::childCount( _components.second ); |
106 | 0 | if ( lhsCount != rhsCount ) |
107 | 0 | throw RuntimeException( u"Found inconsistent form component hierarchies (1)!"_ustr ); |
108 | 0 | return lhsCount; |
109 | 0 | } |
110 | | |
111 | | static FormComponentPair getChild( const FormComponentPair& _components, size_t _index ) |
112 | 0 | { |
113 | 0 | return FormComponentPair( |
114 | 0 | FormComponentInfo::getChild( _components.first, _index ), |
115 | 0 | FormComponentInfo::getChild( _components.second, _index ) |
116 | 0 | ); |
117 | 0 | } |
118 | | }; |
119 | | |
120 | | typedef ::std::map< Reference< XControlModel >, Reference< XControlModel > > MapControlModels; |
121 | | |
122 | | class FormComponentAssignment |
123 | | { |
124 | | public: |
125 | | explicit FormComponentAssignment( MapControlModels& _out_controlModelMap ) |
126 | 0 | :m_rControlModelMap( _out_controlModelMap ) |
127 | 0 | { |
128 | 0 | } |
129 | | |
130 | | void process( const FormComponentPair& _component ) |
131 | 0 | { |
132 | 0 | Reference< XControlModel > lhsControlModel( _component.first, UNO_QUERY ); |
133 | 0 | Reference< XControlModel > rhsControlModel( _component.second, UNO_QUERY ); |
134 | 0 | if ( lhsControlModel.is() != rhsControlModel.is() ) |
135 | 0 | throw RuntimeException( u"Found inconsistent form component hierarchies (2)!"_ustr ); |
136 | | |
137 | 0 | if ( lhsControlModel.is() ) |
138 | 0 | m_rControlModelMap[ lhsControlModel ] = std::move(rhsControlModel); |
139 | 0 | } |
140 | | |
141 | | private: |
142 | | MapControlModels& m_rControlModelMap; |
143 | | }; |
144 | | } |
145 | | |
146 | | |
147 | | void FmFormPageImpl::initFrom( FmFormPageImpl& i_foreignImpl ) |
148 | 3.95k | { |
149 | | // clone the Forms collection |
150 | 3.95k | const Reference< css::form::XForms > xForeignForms( i_foreignImpl.getForms( false ) ); |
151 | | |
152 | 3.95k | if ( !xForeignForms.is() ) |
153 | 3.95k | return; |
154 | | |
155 | 0 | try |
156 | 0 | { |
157 | 0 | m_xForms.set( xForeignForms->createClone(), UNO_QUERY_THROW ); |
158 | | |
159 | | // create a mapping between the original control models and their clones |
160 | 0 | MapControlModels aModelAssignment; |
161 | |
|
162 | 0 | typedef TreeVisitor< FormComponentPair, FormHierarchyComparator, FormComponentAssignment > FormComponentVisitor; |
163 | 0 | FormComponentVisitor aVisitor{ FormHierarchyComparator() }; |
164 | |
|
165 | 0 | FormComponentAssignment aAssignmentProcessor( aModelAssignment ); |
166 | 0 | aVisitor.process( FormComponentPair( xForeignForms, m_xForms ), aAssignmentProcessor ); |
167 | | |
168 | | // assign the cloned models to their SdrObjects |
169 | 0 | SdrObjListIter aForeignIter( &i_foreignImpl.m_rPage ); |
170 | 0 | SdrObjListIter aOwnIter( &m_rPage ); |
171 | |
|
172 | 0 | OSL_ENSURE( aForeignIter.IsMore() == aOwnIter.IsMore(), "FmFormPageImpl::FmFormPageImpl: inconsistent number of objects (1)!" ); |
173 | 0 | while ( aForeignIter.IsMore() && aOwnIter.IsMore() ) |
174 | 0 | { |
175 | 0 | FmFormObj* pForeignObj = dynamic_cast< FmFormObj* >( aForeignIter.Next() ); |
176 | 0 | FmFormObj* pOwnObj = dynamic_cast< FmFormObj* >( aOwnIter.Next() ); |
177 | |
|
178 | 0 | bool bForeignIsForm = pForeignObj && ( pForeignObj->GetObjInventor() == SdrInventor::FmForm ); |
179 | 0 | bool bOwnIsForm = pOwnObj && ( pOwnObj->GetObjInventor() == SdrInventor::FmForm ); |
180 | |
|
181 | 0 | if ( bForeignIsForm != bOwnIsForm ) |
182 | 0 | { |
183 | | // if this fires, don't attempt to do further assignments, something's completely messed up |
184 | 0 | SAL_WARN( "svx.form", "FmFormPageImpl::FmFormPageImpl: inconsistent ordering of objects!" ); |
185 | 0 | break; |
186 | 0 | } |
187 | | |
188 | 0 | if ( !bForeignIsForm ) |
189 | | // no form control -> next round |
190 | 0 | continue; |
191 | | |
192 | 0 | Reference< XControlModel > xForeignModel( pForeignObj->GetUnoControlModel() ); |
193 | 0 | if ( !xForeignModel.is() ) |
194 | 0 | { |
195 | | // if this fires, the SdrObject does not have a UNO Control Model. This is pathological, but well ... |
196 | | // So the cloned SdrObject will also not have a UNO Control Model. |
197 | 0 | SAL_WARN( "svx.form", "FmFormPageImpl::FmFormPageImpl: control shape without control!" ); |
198 | 0 | continue; |
199 | 0 | } |
200 | | |
201 | 0 | MapControlModels::const_iterator assignment = aModelAssignment.find( xForeignModel ); |
202 | 0 | if ( assignment == aModelAssignment.end() ) |
203 | 0 | { |
204 | | // if this fires, the source SdrObject has a model, but it is not part of the model hierarchy in |
205 | | // i_foreignImpl.getForms(). |
206 | | // Pathological, too ... |
207 | 0 | SAL_WARN( "svx.form", "FmFormPageImpl::FmFormPageImpl: no clone found for this model!" ); |
208 | 0 | continue; |
209 | 0 | } |
210 | | |
211 | 0 | pOwnObj->SetUnoControlModel( assignment->second ); |
212 | 0 | } |
213 | 0 | OSL_ENSURE( aForeignIter.IsMore() == aOwnIter.IsMore(), "FmFormPageImpl::FmFormPageImpl: inconsistent number of objects (2)!" ); |
214 | 0 | } |
215 | 0 | catch( const Exception& ) |
216 | 0 | { |
217 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
218 | 0 | } |
219 | 0 | } |
220 | | |
221 | | |
222 | | Reference< XMap > FmFormPageImpl::getControlToShapeMap() |
223 | 0 | { |
224 | 0 | Reference< XMap > xControlShapeMap( m_aControlShapeMap.get(), UNO_QUERY ); |
225 | 0 | if ( xControlShapeMap.is() ) |
226 | 0 | return xControlShapeMap; |
227 | | |
228 | 0 | xControlShapeMap = impl_createControlShapeMap_nothrow(); |
229 | 0 | m_aControlShapeMap = xControlShapeMap; |
230 | 0 | return xControlShapeMap; |
231 | 0 | } |
232 | | |
233 | | |
234 | | namespace |
235 | | { |
236 | | void lcl_insertFormObject_throw( const FmFormObj& _object, const Reference< XMap >& _map ) |
237 | 0 | { |
238 | | // the control model |
239 | 0 | const Reference< XControlModel >& xControlModel = _object.GetUnoControlModel(); |
240 | 0 | OSL_ENSURE( xControlModel.is(), "lcl_insertFormObject_throw: suspicious: no control model!" ); |
241 | 0 | if ( !xControlModel.is() ) |
242 | 0 | return; |
243 | | |
244 | 0 | Reference< XControlShape > xControlShape( const_cast< FmFormObj& >( _object ).getUnoShape(), UNO_QUERY ); |
245 | 0 | OSL_ENSURE( xControlShape.is(), "lcl_insertFormObject_throw: suspicious: no control shape!" ); |
246 | 0 | if ( !xControlShape.is() ) |
247 | 0 | return; |
248 | | |
249 | 0 | _map->put( Any( xControlModel ), Any( xControlShape ) ); |
250 | 0 | } |
251 | | |
252 | | void lcl_removeFormObject_throw( const FmFormObj& _object, const Reference< XMap >& _map ) |
253 | 0 | { |
254 | | // the control model |
255 | 0 | const Reference< XControlModel >& xControlModel = _object.GetUnoControlModel(); |
256 | 0 | OSL_ENSURE( xControlModel.is(), "lcl_removeFormObject: suspicious: no control model!" ); |
257 | 0 | if ( !xControlModel.is() ) |
258 | 0 | { |
259 | 0 | return; |
260 | 0 | } |
261 | | |
262 | 0 | Any aOldAssignment = _map->remove( Any( xControlModel ) ); |
263 | 0 | OSL_ENSURE( |
264 | 0 | aOldAssignment == Any( Reference< XControlShape >( const_cast< FmFormObj& >( _object ).getUnoShape(), UNO_QUERY ) ), |
265 | 0 | "lcl_removeFormObject: map was inconsistent!" ); |
266 | 0 | } |
267 | | } |
268 | | |
269 | | |
270 | | Reference< XMap > FmFormPageImpl::impl_createControlShapeMap_nothrow() |
271 | 0 | { |
272 | 0 | Reference< XMap > xMap; |
273 | |
|
274 | 0 | try |
275 | 0 | { |
276 | 0 | xMap = EnumerableMap::create( comphelper::getProcessComponentContext(), |
277 | 0 | ::cppu::UnoType< XControlModel >::get(), |
278 | 0 | ::cppu::UnoType< XControlShape >::get() |
279 | 0 | ); |
280 | |
|
281 | 0 | SdrObjListIter aPageIter( &m_rPage ); |
282 | 0 | while ( aPageIter.IsMore() ) |
283 | 0 | { |
284 | | // only FmFormObjs are what we're interested in |
285 | 0 | FmFormObj* pCurrent = FmFormObj::GetFormObject( aPageIter.Next() ); |
286 | 0 | if ( !pCurrent ) |
287 | 0 | continue; |
288 | | |
289 | 0 | lcl_insertFormObject_throw( *pCurrent, xMap ); |
290 | 0 | } |
291 | 0 | } |
292 | 0 | catch( const Exception& ) |
293 | 0 | { |
294 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
295 | 0 | } |
296 | 0 | return xMap; |
297 | 0 | } |
298 | | |
299 | | |
300 | | const Reference< css::form::XForms >& FmFormPageImpl::getForms( bool _bForceCreate ) |
301 | 773k | { |
302 | 773k | if ( m_xForms.is() || !_bForceCreate ) |
303 | 773k | return m_xForms; |
304 | | |
305 | 56 | if ( !m_bAttemptedFormCreation ) |
306 | 25 | { |
307 | 25 | m_bAttemptedFormCreation = true; |
308 | | |
309 | 25 | const Reference<XComponentContext>& xContext = comphelper::getProcessComponentContext(); |
310 | 25 | m_xForms = css::form::Forms::create( xContext ); |
311 | | |
312 | 25 | if ( m_aFormsCreationHdl.IsSet() ) |
313 | 0 | { |
314 | 0 | m_aFormsCreationHdl.Call( *this ); |
315 | 0 | } |
316 | | |
317 | 25 | FmFormModel& rFmFormModel(dynamic_cast< FmFormModel& >(m_rPage.getSdrModelFromSdrPage())); |
318 | | |
319 | | // give the newly created collection a place in the universe |
320 | 25 | SfxObjectShell* pObjShell(rFmFormModel.GetObjectShell()); |
321 | 25 | if ( pObjShell ) |
322 | 0 | m_xForms->setParent( pObjShell->GetModel() ); |
323 | | |
324 | | // tell the UNDO environment that we have a new forms collection |
325 | 25 | rFmFormModel.GetUndoEnv().AddForms( Reference<XNameContainer>(m_xForms,UNO_QUERY_THROW) ); |
326 | 25 | } |
327 | 56 | return m_xForms; |
328 | 773k | } |
329 | | |
330 | | |
331 | | FmFormPageImpl::~FmFormPageImpl() |
332 | 718k | { |
333 | 718k | xCurrentForm = nullptr; |
334 | | |
335 | 718k | ::comphelper::disposeComponent( m_xForms ); |
336 | 718k | } |
337 | | |
338 | | |
339 | | bool FmFormPageImpl::validateCurForm() |
340 | 0 | { |
341 | 0 | if ( !xCurrentForm.is() ) |
342 | 0 | return false; |
343 | | |
344 | 0 | if ( !xCurrentForm->getParent().is() ) |
345 | 0 | xCurrentForm.clear(); |
346 | |
|
347 | 0 | return xCurrentForm.is(); |
348 | 0 | } |
349 | | |
350 | | |
351 | | void FmFormPageImpl::setCurForm(const Reference< css::form::XForm >& xForm) |
352 | 0 | { |
353 | 0 | xCurrentForm = xForm; |
354 | 0 | } |
355 | | |
356 | | |
357 | | Reference< XForm > FmFormPageImpl::getDefaultForm() |
358 | 0 | { |
359 | 0 | Reference< XForm > xForm; |
360 | |
|
361 | 0 | Reference< XForms > xForms( getForms() ); |
362 | | |
363 | | // by default, we use our "current form" |
364 | 0 | if ( !validateCurForm() ) |
365 | 0 | { |
366 | | // check whether there is a "standard" form |
367 | 0 | if ( Reference<XNameAccess>(xForms,UNO_QUERY_THROW)->hasElements() ) |
368 | 0 | { |
369 | | // find the standard form |
370 | 0 | OUString sStandardFormname = SvxResId(RID_STR_STDFORMNAME); |
371 | |
|
372 | 0 | try |
373 | 0 | { |
374 | 0 | if ( xForms->hasByName( sStandardFormname ) ) |
375 | 0 | xForm.set( xForms->getByName( sStandardFormname ), UNO_QUERY_THROW ); |
376 | 0 | else |
377 | 0 | { |
378 | 0 | xForm.set( xForms->getByIndex(0), UNO_QUERY_THROW ); |
379 | 0 | } |
380 | 0 | } |
381 | 0 | catch( const Exception& ) |
382 | 0 | { |
383 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
384 | 0 | } |
385 | 0 | } |
386 | 0 | } |
387 | 0 | else |
388 | 0 | { |
389 | 0 | xForm = xCurrentForm; |
390 | 0 | } |
391 | | |
392 | | // did not find an existing suitable form -> create a new one |
393 | 0 | if ( !xForm.is() ) |
394 | 0 | { |
395 | 0 | SdrModel& rModel(m_rPage.getSdrModelFromSdrPage()); |
396 | |
|
397 | 0 | if( rModel.IsUndoEnabled() ) |
398 | 0 | { |
399 | 0 | OUString aStr(SvxResId(RID_STR_FORM)); |
400 | 0 | OUString aUndoStr(SvxResId(RID_STR_UNDO_CONTAINER_INSERT)); |
401 | 0 | rModel.BegUndo(aUndoStr.replaceFirst("'#'", aStr)); |
402 | 0 | } |
403 | |
|
404 | 0 | try |
405 | 0 | { |
406 | 0 | xForm.set( ::comphelper::getProcessServiceFactory()->createInstance( FM_SUN_COMPONENT_FORM ), UNO_QUERY ); |
407 | | |
408 | | // a form should always have the command type table as default |
409 | 0 | Reference< XPropertySet > xFormProps( xForm, UNO_QUERY_THROW ); |
410 | 0 | xFormProps->setPropertyValue( FM_PROP_COMMANDTYPE, Any( sal_Int32( CommandType::TABLE ) ) ); |
411 | | |
412 | | // and the "Standard" name |
413 | 0 | OUString sName = SvxResId(RID_STR_STDFORMNAME); |
414 | 0 | xFormProps->setPropertyValue( FM_PROP_NAME, Any( sName ) ); |
415 | |
|
416 | 0 | if( rModel.IsUndoEnabled() ) |
417 | 0 | { |
418 | 0 | rModel.AddUndo( |
419 | 0 | std::make_unique<FmUndoContainerAction>( |
420 | 0 | static_cast< FmFormModel& >(rModel), |
421 | 0 | FmUndoContainerAction::Inserted, |
422 | 0 | xForms, |
423 | 0 | xForm, |
424 | 0 | xForms->getCount())); |
425 | 0 | } |
426 | 0 | xForms->insertByName( sName, Any( xForm ) ); |
427 | 0 | xCurrentForm = xForm; |
428 | 0 | } |
429 | 0 | catch( const Exception& ) |
430 | 0 | { |
431 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
432 | 0 | xForm.clear(); |
433 | 0 | } |
434 | |
|
435 | 0 | if( rModel.IsUndoEnabled() ) |
436 | 0 | rModel.EndUndo(); |
437 | 0 | } |
438 | |
|
439 | 0 | return xForm; |
440 | 0 | } |
441 | | |
442 | | |
443 | | Reference< css::form::XForm > FmFormPageImpl::findPlaceInFormComponentHierarchy( |
444 | | const Reference< XFormComponent > & rContent, const Reference< XDataSource > & rDatabase, |
445 | | const OUString& rDBTitle, const OUString& rCursorSource, sal_Int32 nCommandType ) |
446 | 0 | { |
447 | | // if the control already is child of a form, don't do anything |
448 | 0 | if (!rContent.is() || rContent->getParent().is()) |
449 | 0 | return nullptr; |
450 | | |
451 | 0 | Reference< XForm > xForm; |
452 | | |
453 | | // If database and CursorSource are set, the form is searched for using |
454 | | // these criteria, otherwise only current and the DefaultForm. |
455 | 0 | if (rDatabase.is() && !rCursorSource.isEmpty()) |
456 | 0 | { |
457 | 0 | validateCurForm(); |
458 | | |
459 | | // first search in the current form |
460 | 0 | xForm = findFormForDataSource( xCurrentForm, rDatabase, rCursorSource, nCommandType ); |
461 | |
|
462 | 0 | Reference< css::container::XIndexAccess > xFormsByIndex = getForms(); |
463 | 0 | DBG_ASSERT(xFormsByIndex.is(), "FmFormPageImpl::findPlaceInFormComponentHierarchy : no index access for my forms collection !"); |
464 | 0 | sal_Int32 nCount = xFormsByIndex->getCount(); |
465 | 0 | for (sal_Int32 i = 0; !xForm.is() && i < nCount; i++) |
466 | 0 | { |
467 | 0 | Reference< css::form::XForm > xToSearch; |
468 | 0 | xFormsByIndex->getByIndex(i) >>= xToSearch; |
469 | 0 | xForm = findFormForDataSource( xToSearch, rDatabase, rCursorSource, nCommandType ); |
470 | 0 | } |
471 | | |
472 | | // If no css::form found, then create a new one |
473 | 0 | if (!xForm.is()) |
474 | 0 | { |
475 | 0 | SdrModel& rModel(m_rPage.getSdrModelFromSdrPage()); |
476 | 0 | const bool bUndo(rModel.IsUndoEnabled()); |
477 | |
|
478 | 0 | if( bUndo ) |
479 | 0 | { |
480 | 0 | OUString aStr(SvxResId(RID_STR_FORM)); |
481 | 0 | OUString aUndoStr(SvxResId(RID_STR_UNDO_CONTAINER_INSERT)); |
482 | 0 | aUndoStr = aUndoStr.replaceFirst("#", aStr); |
483 | 0 | rModel.BegUndo(aUndoStr); |
484 | 0 | } |
485 | |
|
486 | 0 | xForm.set(::comphelper::getProcessServiceFactory()->createInstance(FM_SUN_COMPONENT_FORM), UNO_QUERY); |
487 | | // a form should always have the command type table as default |
488 | 0 | Reference< css::beans::XPropertySet > xFormProps(xForm, UNO_QUERY); |
489 | 0 | try { xFormProps->setPropertyValue(FM_PROP_COMMANDTYPE, Any(sal_Int32(CommandType::TABLE))); } |
490 | 0 | catch(Exception&) { } |
491 | |
|
492 | 0 | if (!rDBTitle.isEmpty()) |
493 | 0 | xFormProps->setPropertyValue(FM_PROP_DATASOURCE,Any(rDBTitle)); |
494 | 0 | else |
495 | 0 | { |
496 | 0 | Reference< css::beans::XPropertySet > xDatabaseProps(rDatabase, UNO_QUERY); |
497 | 0 | Any aDatabaseUrl = xDatabaseProps->getPropertyValue(FM_PROP_URL); |
498 | 0 | xFormProps->setPropertyValue(FM_PROP_URL, aDatabaseUrl); |
499 | 0 | } |
500 | |
|
501 | 0 | xFormProps->setPropertyValue(FM_PROP_COMMAND,Any(rCursorSource)); |
502 | 0 | xFormProps->setPropertyValue(FM_PROP_COMMANDTYPE, Any(nCommandType)); |
503 | |
|
504 | 0 | Reference< css::container::XNameAccess > xNamedSet = getForms(); |
505 | |
|
506 | 0 | const bool bTableOrQuery = ( CommandType::TABLE == nCommandType ) || ( CommandType::QUERY == nCommandType ); |
507 | 0 | OUString sName = FormControlFactory::getUniqueName( xNamedSet, |
508 | 0 | bTableOrQuery ? rCursorSource : SvxResId(RID_STR_STDFORMNAME) ); |
509 | |
|
510 | 0 | xFormProps->setPropertyValue( FM_PROP_NAME, Any( sName ) ); |
511 | |
|
512 | 0 | if( bUndo ) |
513 | 0 | { |
514 | 0 | Reference< css::container::XIndexContainer > xContainer = getForms(); |
515 | 0 | rModel.AddUndo( |
516 | 0 | std::make_unique<FmUndoContainerAction>( |
517 | 0 | static_cast< FmFormModel& >(rModel), |
518 | 0 | FmUndoContainerAction::Inserted, |
519 | 0 | xContainer, |
520 | 0 | xForm, |
521 | 0 | xContainer->getCount())); |
522 | 0 | } |
523 | |
|
524 | 0 | getForms()->insertByName( sName, Any( xForm ) ); |
525 | |
|
526 | 0 | if( bUndo ) |
527 | 0 | rModel.EndUndo(); |
528 | 0 | } |
529 | 0 | xCurrentForm = xForm; |
530 | 0 | } |
531 | |
|
532 | 0 | xForm = getDefaultForm(); |
533 | 0 | return xForm; |
534 | 0 | } |
535 | | |
536 | | |
537 | | Reference< XForm > FmFormPageImpl::findFormForDataSource( |
538 | | const Reference< XForm > & rForm, const Reference< XDataSource > & _rxDatabase, |
539 | | const OUString& _rCursorSource, sal_Int32 nCommandType) |
540 | 0 | { |
541 | 0 | Reference< XForm > xResultForm; |
542 | 0 | Reference< XRowSet > xDBForm(rForm, UNO_QUERY); |
543 | 0 | Reference< XPropertySet > xFormProps(rForm, UNO_QUERY); |
544 | 0 | if (!xDBForm.is() || !xFormProps.is()) |
545 | 0 | return xResultForm; |
546 | | |
547 | 0 | OSL_ENSURE(_rxDatabase.is(), "FmFormPageImpl::findFormForDataSource: invalid data source!"); |
548 | 0 | OUString sLookupName; // the name of the data source we're looking for |
549 | 0 | OUString sFormDataSourceName; // the name of the data source the current connection in the form is based on |
550 | 0 | try |
551 | 0 | { |
552 | 0 | Reference< XPropertySet > xDSProps(_rxDatabase, UNO_QUERY); |
553 | 0 | if (xDSProps.is()) |
554 | 0 | xDSProps->getPropertyValue(FM_PROP_NAME) >>= sLookupName; |
555 | |
|
556 | 0 | xFormProps->getPropertyValue(FM_PROP_DATASOURCE) >>= sFormDataSourceName; |
557 | | // if there's no DataSourceName set at the form, check whether we can deduce one from its |
558 | | // ActiveConnection |
559 | 0 | if (sFormDataSourceName.isEmpty()) |
560 | 0 | { |
561 | 0 | Reference< XConnection > xFormConnection; |
562 | 0 | xFormProps->getPropertyValue( FM_PROP_ACTIVE_CONNECTION ) >>= xFormConnection; |
563 | 0 | if ( !xFormConnection.is() ) |
564 | 0 | isEmbeddedInDatabase( xFormProps, xFormConnection ); |
565 | 0 | if (xFormConnection.is()) |
566 | 0 | { |
567 | 0 | Reference< XChild > xConnAsChild(xFormConnection, UNO_QUERY); |
568 | 0 | if (xConnAsChild.is()) |
569 | 0 | { |
570 | 0 | Reference< XDataSource > xFormDS(xConnAsChild->getParent(), UNO_QUERY); |
571 | 0 | if (xFormDS.is()) |
572 | 0 | { |
573 | 0 | xDSProps.set(xFormDS, css::uno::UNO_QUERY); |
574 | 0 | if (xDSProps.is()) |
575 | 0 | xDSProps->getPropertyValue(FM_PROP_NAME) >>= sFormDataSourceName; |
576 | 0 | } |
577 | 0 | } |
578 | 0 | } |
579 | 0 | } |
580 | 0 | } |
581 | 0 | catch(const Exception&) |
582 | 0 | { |
583 | 0 | TOOLS_WARN_EXCEPTION("svx", "FmFormPageImpl::findFormForDataSource"); |
584 | 0 | } |
585 | | |
586 | 0 | if (sLookupName == sFormDataSourceName) |
587 | 0 | { |
588 | | // now check whether CursorSource and type match |
589 | 0 | OUString aCursorSource = ::comphelper::getString(xFormProps->getPropertyValue(FM_PROP_COMMAND)); |
590 | 0 | sal_Int32 nType = ::comphelper::getINT32(xFormProps->getPropertyValue(FM_PROP_COMMANDTYPE)); |
591 | 0 | if (aCursorSource.isEmpty() || ((nType == nCommandType) && (aCursorSource == _rCursorSource))) // found the form |
592 | 0 | { |
593 | 0 | xResultForm = rForm; |
594 | | // if no data source is set yet, it is done here |
595 | 0 | if (aCursorSource.isEmpty()) |
596 | 0 | { |
597 | 0 | xFormProps->setPropertyValue(FM_PROP_COMMAND, Any(_rCursorSource)); |
598 | 0 | xFormProps->setPropertyValue(FM_PROP_COMMANDTYPE, Any(nCommandType)); |
599 | 0 | } |
600 | 0 | } |
601 | 0 | } |
602 | | |
603 | | // as long as xResultForm is NULL, search the child forms of rForm |
604 | 0 | Reference< XIndexAccess > xComponents(rForm, UNO_QUERY); |
605 | 0 | sal_Int32 nCount = xComponents->getCount(); |
606 | 0 | for (sal_Int32 i = 0; !xResultForm.is() && i < nCount; ++i) |
607 | 0 | { |
608 | 0 | Reference< css::form::XForm > xSearchForm; |
609 | 0 | xComponents->getByIndex(i) >>= xSearchForm; |
610 | | // continue searching in the sub form |
611 | 0 | if (xSearchForm.is()) |
612 | 0 | xResultForm = findFormForDataSource( xSearchForm, _rxDatabase, _rCursorSource, nCommandType ); |
613 | 0 | } |
614 | 0 | return xResultForm; |
615 | 0 | } |
616 | | |
617 | | |
618 | | OUString FmFormPageImpl::setUniqueName(const Reference< XFormComponent > & xFormComponent, const Reference< XForm > & xControls) |
619 | 0 | { |
620 | | #if OSL_DEBUG_LEVEL > 0 |
621 | | try |
622 | | { |
623 | | OSL_ENSURE( !xFormComponent->getParent().is(), "FmFormPageImpl::setUniqueName: to be called before insertion!" ); |
624 | | } |
625 | | catch( const Exception& ) |
626 | | { |
627 | | DBG_UNHANDLED_EXCEPTION("svx"); |
628 | | } |
629 | | #endif |
630 | 0 | OUString sName; |
631 | 0 | Reference< css::beans::XPropertySet > xSet(xFormComponent, UNO_QUERY); |
632 | 0 | if (xSet.is()) |
633 | 0 | { |
634 | 0 | sName = ::comphelper::getString( xSet->getPropertyValue( FM_PROP_NAME ) ); |
635 | 0 | Reference< css::container::XNameAccess > xNameAcc(xControls, UNO_QUERY); |
636 | |
|
637 | 0 | if (sName.isEmpty() || xNameAcc->hasByName(sName)) |
638 | 0 | { |
639 | | // set a default name via the ClassId |
640 | 0 | sal_Int16 nClassId( FormComponentType::CONTROL ); |
641 | 0 | xSet->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId; |
642 | |
|
643 | 0 | OUString sDefaultName = FormControlFactory::getDefaultUniqueName_ByComponentType( |
644 | 0 | Reference< XNameAccess >( xControls, UNO_QUERY ), xSet ); |
645 | | |
646 | | // do not overwrite the name of radio buttons that have it! |
647 | 0 | if (sName.isEmpty() || nClassId != css::form::FormComponentType::RADIOBUTTON) |
648 | 0 | { |
649 | 0 | xSet->setPropertyValue(FM_PROP_NAME, Any(sDefaultName)); |
650 | 0 | } |
651 | |
|
652 | 0 | sName = sDefaultName; |
653 | 0 | } |
654 | 0 | } |
655 | 0 | return sName; |
656 | 0 | } |
657 | | |
658 | | |
659 | | void FmFormPageImpl::formModelAssigned( const FmFormObj& _object ) |
660 | 0 | { |
661 | 0 | Reference< XMap > xControlShapeMap( m_aControlShapeMap.get(), UNO_QUERY ); |
662 | 0 | if ( !xControlShapeMap.is() ) |
663 | | // our map does not exist -> not interested in this event |
664 | 0 | return; |
665 | | |
666 | 0 | try |
667 | 0 | { |
668 | 0 | lcl_removeFormObject_throw( _object, xControlShapeMap ); |
669 | 0 | lcl_insertFormObject_throw( _object, xControlShapeMap ); |
670 | 0 | } |
671 | 0 | catch( const Exception& ) |
672 | 0 | { |
673 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
674 | 0 | } |
675 | 0 | } |
676 | | |
677 | | |
678 | | void FmFormPageImpl::formObjectInserted( const FmFormObj& _object ) |
679 | 0 | { |
680 | 0 | Reference< XMap > xControlShapeMap( m_aControlShapeMap.get(), UNO_QUERY ); |
681 | 0 | if ( !xControlShapeMap.is() ) |
682 | | // our map does not exist -> not interested in this event |
683 | 0 | return; |
684 | | |
685 | 0 | try |
686 | 0 | { |
687 | 0 | lcl_insertFormObject_throw( _object, xControlShapeMap ); |
688 | 0 | } |
689 | 0 | catch( const Exception& ) |
690 | 0 | { |
691 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
692 | 0 | } |
693 | 0 | } |
694 | | |
695 | | |
696 | | void FmFormPageImpl::formObjectRemoved( const FmFormObj& _object ) |
697 | 0 | { |
698 | 0 | Reference< XMap > xControlShapeMap( m_aControlShapeMap.get(), UNO_QUERY ); |
699 | 0 | if ( !xControlShapeMap.is() ) |
700 | | // our map does not exist -> not interested in this event |
701 | 0 | return; |
702 | | |
703 | 0 | try |
704 | 0 | { |
705 | 0 | lcl_removeFormObject_throw( _object, xControlShapeMap ); |
706 | 0 | } |
707 | 0 | catch( const Exception& ) |
708 | 0 | { |
709 | 0 | DBG_UNHANDLED_EXCEPTION("svx"); |
710 | 0 | } |
711 | 0 | } |
712 | | |
713 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |