1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <o3tl/safeint.hxx>
23 #include <sal/macros.h>
24 #include <sal/log.hxx>
26 #include <fmpgeimp.hxx>
27 #include <svx/fmtools.hxx>
29 #include <fmservs.hxx>
30 #include <fmshimp.hxx>
31 #include <fmtextcontrolshell.hxx>
34 #include <fmvwimp.hxx>
35 #include <gridcols.hxx>
36 #include <svx/svditer.hxx>
37 #include <svx/dialmgr.hxx>
38 #include <svx/strings.hrc>
39 #include <svx/svdobjkind.hxx>
40 #include <svx/fmmodel.hxx>
41 #include <svx/fmpage.hxx>
42 #include <svx/fmshell.hxx>
43 #include <svx/fmview.hxx>
44 #include <svx/obj3d.hxx>
45 #include <svx/sdrpagewindow.hxx>
46 #include <svx/svdpagv.hxx>
47 #include <svx/svxdlg.hxx>
48 #include <svx/svxids.hrc>
49 #include <bitmaps.hlst>
50 #include <formnavi.hrc>
52 #include <com/sun/star/awt/XWindow2.hpp>
53 #include <com/sun/star/awt/XCheckBox.hpp>
54 #include <com/sun/star/awt/XListBox.hpp>
55 #include <com/sun/star/awt/XTextComponent.hpp>
56 #include <com/sun/star/beans/theIntrospection.hpp>
57 #include <com/sun/star/beans/PropertyAttribute.hpp>
58 #include <com/sun/star/beans/XPropertyState.hpp>
59 #include <com/sun/star/container/XContainer.hpp>
60 #include <com/sun/star/container/XIndexAccess.hpp>
61 #include <com/sun/star/container/XNamed.hpp>
62 #include <com/sun/star/form/ListSourceType.hpp>
63 #include <com/sun/star/form/TabOrderDialog.hpp>
64 #include <com/sun/star/form/XGrid.hpp>
65 #include <com/sun/star/form/XGridPeer.hpp>
66 #include <com/sun/star/form/XLoadable.hpp>
67 #include <com/sun/star/form/XReset.hpp>
68 #include <com/sun/star/form/binding/XBindableValue.hpp>
69 #include <com/sun/star/form/binding/XListEntrySink.hpp>
70 #include <com/sun/star/frame/FrameSearchFlag.hpp>
71 #include <com/sun/star/lang/XServiceInfo.hpp>
72 #include <com/sun/star/script/XEventAttacherManager.hpp>
73 #include <com/sun/star/sdbc/SQLException.hpp>
74 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
75 #include <com/sun/star/util/XModeSelector.hpp>
76 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
77 #include <com/sun/star/view/XSelectionSupplier.hpp>
79 #include <comphelper/evtmethodhelper.hxx>
80 #include <comphelper/processfactory.hxx>
81 #include <comphelper/property.hxx>
82 #include <comphelper/sequence.hxx>
83 #include <comphelper/solarmutex.hxx>
84 #include <comphelper/string.hxx>
85 #include <comphelper/types.hxx>
86 #include <connectivity/dbtools.hxx>
87 #include <sfx2/dispatch.hxx>
88 #include <sfx2/frame.hxx>
89 #include <sfx2/objsh.hxx>
90 #include <sfx2/viewfrm.hxx>
91 #include <sfx2/viewsh.hxx>
92 #include <toolkit/helper/vclunohelper.hxx>
93 #include <tools/debug.hxx>
94 #include <comphelper/diagnose_ex.hxx>
95 #include <comphelper/configuration.hxx>
96 #include <vcl/settings.hxx>
97 #include <vcl/svapp.hxx>
98 #include <vcl/weld.hxx>
99 #include <vcl/window.hxx>
104 #include <string_view>
107 // is used for Invalidate -> maintain it as well
108 const sal_uInt16 DatabaseSlotMap
[] =
115 SID_FM_RECORD_DELETE
,
116 SID_FM_RECORD_ABSOLUTE
,
120 SID_FM_REMOVE_FILTER_SORT
,
125 SID_FM_FORM_FILTERED
,
127 SID_FM_REFRESH_FORM_CONTROL
,
134 // is used for Invalidate -> maintain it as well
135 // sort ascending !!!!!!
136 const sal_uInt16 DlgSlotMap
[] = // slots of the controller
138 SID_FM_CTL_PROPERTIES
,
142 SID_FM_SHOW_FMEXPLORER
,
143 SID_FM_FIELDS_CONTROL
,
144 SID_FM_SHOW_PROPERTIES
,
145 SID_FM_PROPERTY_CONTROL
,
146 SID_FM_FMEXPLORER_CONTROL
,
147 SID_FM_SHOW_DATANAVIGATOR
,
148 SID_FM_DATANAVIGATOR_CONTROL
,
152 const sal_uInt16 SelObjectSlotMap
[] = // slots depending on the SelObject
154 SID_FM_CONVERTTO_EDIT
,
155 SID_FM_CONVERTTO_BUTTON
,
156 SID_FM_CONVERTTO_FIXEDTEXT
,
157 SID_FM_CONVERTTO_LISTBOX
,
158 SID_FM_CONVERTTO_CHECKBOX
,
159 SID_FM_CONVERTTO_RADIOBUTTON
,
160 SID_FM_CONVERTTO_GROUPBOX
,
161 SID_FM_CONVERTTO_COMBOBOX
,
162 SID_FM_CONVERTTO_IMAGEBUTTON
,
163 SID_FM_CONVERTTO_FILECONTROL
,
164 SID_FM_CONVERTTO_DATE
,
165 SID_FM_CONVERTTO_TIME
,
166 SID_FM_CONVERTTO_NUMERIC
,
167 SID_FM_CONVERTTO_CURRENCY
,
168 SID_FM_CONVERTTO_PATTERN
,
169 SID_FM_CONVERTTO_IMAGECONTROL
,
170 SID_FM_CONVERTTO_FORMATTED
,
171 SID_FM_CONVERTTO_SCROLLBAR
,
172 SID_FM_CONVERTTO_SPINBUTTON
,
173 SID_FM_CONVERTTO_NAVIGATIONBAR
,
175 SID_FM_FMEXPLORER_CONTROL
,
176 SID_FM_DATANAVIGATOR_CONTROL
,
181 // the following arrays must be consistent, i.e., corresponding entries should
182 // be at the same relative position within their respective arrays
183 static std::u16string_view aConvertSlots
[] =
189 u
"ConvertToCheckBox",
193 u
"ConvertToImageBtn",
194 u
"ConvertToFileControl",
198 u
"ConvertToCurrency",
200 u
"ConvertToImageControl",
201 u
"ConvertToFormatted",
202 u
"ConvertToScrollBar",
203 u
"ConvertToSpinButton",
204 u
"ConvertToNavigationBar"
207 constexpr OUString aImgIds
[] =
211 RID_SVXBMP_FIXEDTEXT
,
214 RID_SVXBMP_RADIOBUTTON
,
217 RID_SVXBMP_IMAGEBUTTON
,
218 RID_SVXBMP_FILECONTROL
,
219 RID_SVXBMP_DATEFIELD
,
220 RID_SVXBMP_TIMEFIELD
,
221 RID_SVXBMP_NUMERICFIELD
,
222 RID_SVXBMP_CURRENCYFIELD
,
223 RID_SVXBMP_PATTERNFIELD
,
224 RID_SVXBMP_IMAGECONTROL
,
225 RID_SVXBMP_FORMATTEDFIELD
,
226 RID_SVXBMP_SCROLLBAR
,
227 RID_SVXBMP_SPINBUTTON
,
228 RID_SVXBMP_NAVIGATIONBAR
231 const SdrObjKind nObjectTypes
[] =
233 SdrObjKind::FormEdit
,
234 SdrObjKind::FormButton
,
235 SdrObjKind::FormFixedText
,
236 SdrObjKind::FormListbox
,
237 SdrObjKind::FormCheckbox
,
238 SdrObjKind::FormRadioButton
,
239 SdrObjKind::FormGroupBox
,
240 SdrObjKind::FormCombobox
,
241 SdrObjKind::FormImageButton
,
242 SdrObjKind::FormFileControl
,
243 SdrObjKind::FormDateField
,
244 SdrObjKind::FormTimeField
,
245 SdrObjKind::FormNumericField
,
246 SdrObjKind::FormCurrencyField
,
247 SdrObjKind::FormPatternField
,
248 SdrObjKind::FormImageControl
,
249 SdrObjKind::FormFormattedField
,
250 SdrObjKind::FormScrollbar
,
251 SdrObjKind::FormSpinButton
,
252 SdrObjKind::FormNavigationBar
255 using namespace ::com::sun::star
;
256 using namespace ::com::sun::star::ui
;
257 using namespace ::com::sun::star::uno
;
258 using namespace ::com::sun::star::sdb
;
259 using namespace ::com::sun::star::sdbc
;
260 using namespace ::com::sun::star::sdbcx
;
261 using namespace ::com::sun::star::beans
;
262 using namespace ::com::sun::star::container
;
263 using namespace ::com::sun::star::form
;
264 using namespace ::com::sun::star::form::binding
;
265 using namespace ::com::sun::star::form::runtime
;
266 using namespace ::com::sun::star::awt
;
267 using namespace ::com::sun::star::view
;
268 using namespace ::com::sun::star::util
;
269 using namespace ::com::sun::star::script
;
270 using namespace ::svxform
;
271 using namespace ::svx
;
272 using namespace ::dbtools
;
280 void collectInterfacesFromMarkList( const SdrMarkList
& _rMarkList
, InterfaceBag
& /* [out] */ _rInterfaces
)
282 _rInterfaces
.clear();
284 const size_t nMarkCount
= _rMarkList
.GetMarkCount();
285 for ( size_t i
= 0; i
< nMarkCount
; ++i
)
287 SdrObject
* pCurrent
= _rMarkList
.GetMark( i
)->GetMarkedSdrObj();
288 assert(pCurrent
&& "marked object will exist");
290 std::optional
<SdrObjListIter
> oGroupIterator
;
291 if ( pCurrent
->IsGroupObject() )
293 oGroupIterator
.emplace( pCurrent
->GetSubList() );
294 pCurrent
= oGroupIterator
->IsMore() ? oGroupIterator
->Next() : nullptr;
299 FmFormObj
* pAsFormObject
= FmFormObj::GetFormObject( pCurrent
);
300 // note this will de-reference virtual objects, if necessary/possible
303 Reference
< XInterface
> xControlModel( pAsFormObject
->GetUnoControlModel(), UNO_QUERY
);
304 // the UNO_QUERY is important for normalization
305 if ( xControlModel
.is() )
306 _rInterfaces
.insert( xControlModel
);
310 pCurrent
= oGroupIterator
&& oGroupIterator
->IsMore() ? oGroupIterator
->Next() : nullptr;
316 sal_Int32
GridView2ModelPos(const Reference
< XIndexAccess
>& rColumns
, sal_Int16 nViewPos
)
322 // loop through all columns
324 Reference
< XPropertySet
> xCur
;
325 for (i
=0; i
<rColumns
->getCount(); ++i
)
327 rColumns
->getByIndex(i
) >>= xCur
;
328 if (!::comphelper::getBOOL(xCur
->getPropertyValue(FM_PROP_HIDDEN
)))
330 // for every visible col : if nViewPos is greater zero, decrement it, else we
331 // have found the model position
338 if (i
<rColumns
->getCount())
342 catch(const Exception
&)
344 DBG_UNHANDLED_EXCEPTION("svx");
350 void TransferEventScripts(const Reference
< XControlModel
>& xModel
, const Reference
< XControl
>& xControl
,
351 const Sequence
< ScriptEventDescriptor
>& rTransferIfAvailable
)
353 // first check if we have a XEventAttacherManager for the model
354 Reference
< XChild
> xModelChild(xModel
, UNO_QUERY
);
355 if (!xModelChild
.is())
356 return; // nothing to do
358 Reference
< XEventAttacherManager
> xEventManager(xModelChild
->getParent(), UNO_QUERY
);
359 if (!xEventManager
.is())
360 return; // nothing to do
362 if (!rTransferIfAvailable
.hasElements())
363 return; // nothing to do
365 // check for the index of the model within its parent
366 Reference
< XIndexAccess
> xParentIndex(xModelChild
->getParent(), UNO_QUERY
);
367 if (!xParentIndex
.is())
368 return; // nothing to do
369 sal_Int32 nIndex
= getElementPos(xParentIndex
, xModel
);
370 if (nIndex
<0 || nIndex
>=xParentIndex
->getCount())
371 return; // nothing to do
373 // then we need information about the listeners supported by the control and the model
374 Sequence
< Type
> aModelListeners
;
375 Sequence
< Type
> aControlListeners
;
377 Reference
< XIntrospection
> xIntrospection
= theIntrospection::get(::comphelper::getProcessComponentContext());
382 aModelListeners
= xIntrospection
->inspect(aModel
)->getSupportedListeners();
387 Any
aControl(xControl
);
388 aControlListeners
= xIntrospection
->inspect(aControl
)->getSupportedListeners();
391 sal_Int32 nMaxNewLen
= aModelListeners
.getLength() + aControlListeners
.getLength();
393 return; // the model and the listener don't support any listeners (or we were unable to retrieve these infos)
395 Sequence
< ScriptEventDescriptor
> aTransferable(nMaxNewLen
);
396 ScriptEventDescriptor
* pTransferable
= aTransferable
.getArray();
398 for (const ScriptEventDescriptor
& rCurrent
: rTransferIfAvailable
)
400 // search the model/control idl classes for the event described by pCurrent
401 for (const Sequence
< Type
>* pCurrentArray
: { &aModelListeners
, &aControlListeners
})
403 for (const Type
& rCurrentListener
: *pCurrentArray
)
405 OUString aListener
= rCurrentListener
.getTypeName();
406 if (!aListener
.isEmpty())
407 aListener
= aListener
.copy(aListener
.lastIndexOf('.')+1);
409 if (aListener
== rCurrent
.ListenerType
)
410 // the current ScriptEventDescriptor doesn't match the current listeners class
413 // now check the methods
414 Sequence
< OUString
> aMethodsNames
= ::comphelper::getEventMethodsForType(rCurrentListener
);
416 if (comphelper::findValue(aMethodsNames
, rCurrent
.EventMethod
) != -1)
418 // we can transfer the script event : the model (control) supports it
419 *pTransferable
= rCurrent
;
427 sal_Int32 nRealNewLen
= pTransferable
- aTransferable
.getArray();
428 aTransferable
.realloc(nRealNewLen
);
430 xEventManager
->registerScriptEvents(nIndex
, aTransferable
);
434 const OUString
& getServiceNameByControlType(SdrObjKind nType
)
438 case SdrObjKind::FormEdit
: return FM_COMPONENT_TEXTFIELD
;
439 case SdrObjKind::FormButton
: return FM_COMPONENT_COMMANDBUTTON
;
440 case SdrObjKind::FormFixedText
: return FM_COMPONENT_FIXEDTEXT
;
441 case SdrObjKind::FormListbox
: return FM_COMPONENT_LISTBOX
;
442 case SdrObjKind::FormCheckbox
: return FM_COMPONENT_CHECKBOX
;
443 case SdrObjKind::FormRadioButton
: return FM_COMPONENT_RADIOBUTTON
;
444 case SdrObjKind::FormGroupBox
: return FM_COMPONENT_GROUPBOX
;
445 case SdrObjKind::FormCombobox
: return FM_COMPONENT_COMBOBOX
;
446 case SdrObjKind::FormGrid
: return FM_COMPONENT_GRIDCONTROL
;
447 case SdrObjKind::FormImageButton
: return FM_COMPONENT_IMAGEBUTTON
;
448 case SdrObjKind::FormFileControl
: return FM_COMPONENT_FILECONTROL
;
449 case SdrObjKind::FormDateField
: return FM_COMPONENT_DATEFIELD
;
450 case SdrObjKind::FormTimeField
: return FM_COMPONENT_TIMEFIELD
;
451 case SdrObjKind::FormNumericField
: return FM_COMPONENT_NUMERICFIELD
;
452 case SdrObjKind::FormCurrencyField
: return FM_COMPONENT_CURRENCYFIELD
;
453 case SdrObjKind::FormPatternField
: return FM_COMPONENT_PATTERNFIELD
;
454 case SdrObjKind::FormHidden
: return FM_COMPONENT_HIDDENCONTROL
;
455 case SdrObjKind::FormImageControl
: return FM_COMPONENT_IMAGECONTROL
;
456 case SdrObjKind::FormFormattedField
: return FM_COMPONENT_FORMATTEDFIELD
;
457 case SdrObjKind::FormScrollbar
: return FM_SUN_COMPONENT_SCROLLBAR
;
458 case SdrObjKind::FormSpinButton
: return FM_SUN_COMPONENT_SPINBUTTON
;
459 case SdrObjKind::FormNavigationBar
: return FM_SUN_COMPONENT_NAVIGATIONBAR
;
462 return EMPTY_OUSTRING
;
468 // check if the control has one of the interfaces we can use for searching
469 // *_pCurrentText will be filled with the current text of the control (as used when searching this control)
470 bool IsSearchableControl( const css::uno::Reference
< css::uno::XInterface
>& _rxControl
,
471 OUString
* _pCurrentText
)
473 if ( !_rxControl
.is() )
476 Reference
< XTextComponent
> xAsText( _rxControl
, UNO_QUERY
);
480 *_pCurrentText
= xAsText
->getText();
484 Reference
< XListBox
> xListBox( _rxControl
, UNO_QUERY
);
488 *_pCurrentText
= xListBox
->getSelectedItem();
492 Reference
< XCheckBox
> xCheckBox( _rxControl
, UNO_QUERY
);
493 if ( xCheckBox
.is() )
497 switch ( static_cast<::TriState
>(xCheckBox
->getState()) )
499 case TRISTATE_FALSE
: *_pCurrentText
= "0"; break;
500 case TRISTATE_TRUE
: *_pCurrentText
= "1"; break;
501 default: _pCurrentText
->clear(); break;
511 bool FmXBoundFormFieldIterator::ShouldStepInto(const Reference
< XInterface
>& _rContainer
) const
513 if (_rContainer
== m_xStartingPoint
)
514 // would be quite stupid to step over the root...
517 return Reference
< XControlModel
>(_rContainer
, UNO_QUERY
).is();
521 bool FmXBoundFormFieldIterator::ShouldHandleElement(const Reference
< XInterface
>& _rElement
)
527 if (Reference
< XForm
>(_rElement
, UNO_QUERY
).is() || Reference
< XGrid
>(_rElement
, UNO_QUERY
).is())
531 Reference
< XPropertySet
> xSet(_rElement
, UNO_QUERY
);
532 if (!xSet
.is() || !::comphelper::hasProperty(FM_PROP_BOUNDFIELD
, xSet
))
533 // no "BoundField" property
536 Any
aVal( xSet
->getPropertyValue(FM_PROP_BOUNDFIELD
) );
537 if (aVal
.getValueTypeClass() != TypeClass_INTERFACE
)
538 // void or invalid property value
541 return aVal
.hasValue();
545 static bool isControlList(const SdrMarkList
& rMarkList
)
547 // the list contains only controls and at least one control
548 const size_t nMarkCount
= rMarkList
.GetMarkCount();
549 bool bControlList
= nMarkCount
!= 0;
551 bool bHadAnyLeafs
= false;
553 for (size_t i
= 0; i
< nMarkCount
&& bControlList
; ++i
)
555 SdrObject
*pObj
= rMarkList
.GetMark(i
)->GetMarkedSdrObj();
556 E3dObject
* pAs3DObject
= DynCastE3dObject( pObj
);
557 // E3dObject's do not contain any 2D-objects (by definition)
558 // we need this extra check here : an E3dObject->IsGroupObject says "YES", but an SdrObjListIter working
559 // with an E3dObject doesn't give me any Nodes (E3dObject has a sub list, but no members in that list,
560 // cause there implementation differs from the one of "normal" SdrObject's. Unfortunally SdrObject::IsGroupObject
561 // doesn't check the element count of the sub list, which is simply a bug in IsGroupObject we can't fix at the moment).
562 // So at the end of this function bControlList would have the same value it was initialized with above : sal_True
563 // And this would be wrong :)
564 // 03.02.00 - 72529 - FS
567 if (pObj
->IsGroupObject())
569 SdrObjListIter
aIter(pObj
->GetSubList());
570 while (aIter
.IsMore() && bControlList
)
572 bControlList
= SdrInventor::FmForm
== aIter
.Next()->GetObjInventor();
579 bControlList
= SdrInventor::FmForm
== pObj
->GetObjInventor();
584 return bControlList
&& bHadAnyLeafs
;
588 static Reference
< XForm
> GetForm(const Reference
< XInterface
>& _rxElement
)
590 Reference
< XForm
> xForm( _rxElement
, UNO_QUERY
);
594 Reference
< XChild
> xChild( _rxElement
, UNO_QUERY
);
596 return GetForm( xChild
->getParent() );
598 return Reference
< XForm
>();
601 FmXFormShell_Base_Disambiguation::FmXFormShell_Base_Disambiguation( ::osl::Mutex
& _rMutex
)
602 :FmXFormShell_BD_BASE( _rMutex
)
606 FmXFormShell::FmXFormShell( FmFormShell
& _rShell
, SfxViewFrame
* _pViewFrame
)
607 :FmXFormShell_BASE(m_aMutex
)
608 ,FmXFormShell_CFGBASE(u
"Office.Common/Misc"_ustr
, ConfigItemMode::NONE
)
609 ,m_aMarkTimer("svx::FmXFormShell m_aMarkTimer")
610 ,m_eNavigate( NavigationBarMode_NONE
)
611 ,m_nInvalidationEvent( nullptr )
612 ,m_nActivationEvent( nullptr )
613 ,m_pShell( &_rShell
)
614 ,m_pTextShell( new svx::FmTextControlShell( _pViewFrame
) )
615 ,m_aActiveControllerFeatures( this )
616 ,m_aNavControllerFeatures( this )
617 ,m_eDocumentType( eUnknownDocumentType
)
618 ,m_nLockSlotInvalidation( 0 )
619 ,m_bHadPropertyBrowserInDesignMode( false )
620 ,m_bTrackProperties( true )
621 ,m_bUseWizards( true )
622 ,m_bDatabaseBar( false )
623 ,m_bInActivate( false )
624 ,m_bSetFocus( false )
625 ,m_bFilterMode( false )
626 ,m_bChangingDesignMode( false )
627 ,m_bPreparedClose( false )
628 ,m_bFirstActivation( true )
630 m_aMarkTimer
.SetTimeout(100);
631 m_aMarkTimer
.SetInvokeHandler(LINK(this, FmXFormShell
, OnTimeOut_Lock
));
633 m_xAttachedFrame
= _pViewFrame
->GetFrame().GetFrameInterface();
635 // to prevent deletion of this we acquire our refcounter once
636 osl_atomic_increment(&m_refCount
);
638 // correct the refcounter
639 osl_atomic_decrement(&m_refCount
);
641 // cache the current configuration settings we're interested in
642 implAdjustConfigCache_Lock();
643 // and register for changes on this settings
644 Sequence
< OUString
> aNames
{ u
"FormControlPilotsEnabled"_ustr
};
645 EnableNotification(aNames
);
649 FmXFormShell::~FmXFormShell()
654 Reference
< css::frame::XModel
> FmXFormShell::getContextDocument_Lock() const
656 Reference
< css::frame::XModel
> xModel
;
658 // determine the type of document we live in
661 Reference
< css::frame::XController
> xController
;
662 if ( m_xAttachedFrame
.is() )
663 xController
= m_xAttachedFrame
->getController();
664 if ( xController
.is() )
665 xModel
= xController
->getModel();
667 catch( const Exception
& )
669 DBG_UNHANDLED_EXCEPTION("svx");
675 bool FmXFormShell::isEnhancedForm_Lock() const
677 return getDocumentType_Lock() == eEnhancedForm
;
681 bool FmXFormShell::impl_checkDisposed_Lock() const
683 DBG_TESTSOLARMUTEX();
686 OSL_FAIL( "FmXFormShell::impl_checkDisposed: already disposed!" );
693 ::svxform::DocumentType
FmXFormShell::getDocumentType_Lock() const
695 if ( m_eDocumentType
!= eUnknownDocumentType
)
696 return m_eDocumentType
;
698 // determine the type of document we live in
699 Reference
<css::frame::XModel
> xModel
= getContextDocument_Lock();
701 m_eDocumentType
= DocumentClassification::classifyDocument( xModel
);
704 OSL_FAIL( "FmXFormShell::getDocumentType: can't determine the document type!" );
705 m_eDocumentType
= eTextDocument
;
706 // fallback, just to have a defined state
709 return m_eDocumentType
;
713 bool FmXFormShell::IsReadonlyDoc_Lock() const
715 if (impl_checkDisposed_Lock())
718 FmFormModel
* pModel
= m_pShell
->GetFormModel();
719 if ( pModel
&& pModel
->GetObjectShell() )
720 return pModel
->GetObjectShell()->IsReadOnly() || pModel
->GetObjectShell()->IsReadOnlyUI();
726 void SAL_CALL
FmXFormShell::disposing(const lang::EventObject
& e
)
730 if (m_xActiveController
== e
.Source
)
732 // the controller will release, then release everything
733 stopListening_Lock();
734 m_xActiveForm
= nullptr;
735 m_xActiveController
= nullptr;
736 m_xNavigationController
= nullptr;
738 m_aActiveControllerFeatures
.dispose();
739 m_aNavControllerFeatures
.dispose();
742 m_pShell
->GetViewShell()->GetViewFrame().GetBindings().InvalidateShell(*m_pShell
);
745 if (e
.Source
!= m_xExternalViewController
)
748 Reference
< runtime::XFormController
> xFormController( m_xExternalViewController
, UNO_QUERY
);
749 OSL_ENSURE( xFormController
.is(), "FmXFormShell::disposing: invalid external view controller!" );
750 if (xFormController
.is())
751 xFormController
->removeActivateListener(static_cast<XFormControllerListener
*>(this));
753 if (m_xExternalViewController
.is())
754 m_xExternalViewController
->removeEventListener(static_cast<XEventListener
*>(static_cast<XPropertyChangeListener
*>(this)));
756 m_xExternalViewController
= nullptr;
757 m_xExternalDisplayedForm
= nullptr;
758 m_xExtViewTriggerController
= nullptr;
760 InvalidateSlot_Lock( SID_FM_VIEW_AS_GRID
, false );
764 void SAL_CALL
FmXFormShell::propertyChange(const PropertyChangeEvent
& evt
)
768 if (impl_checkDisposed_Lock())
771 if (evt
.PropertyName
== FM_PROP_ROWCOUNT
)
773 // The update following this forces a re-painting of the corresponding
774 // slots. But if I am not in the MainThread of the application (because,
775 // for example, a cursor is counting data sets at the moment and always
776 // gives me this PropertyChanges), this can clash with normal paints in
777 // the MainThread of the application. (Such paints happen, for example,
778 // if one simply places another application over the office and switches
780 // Therefore the use of the SolarMutex, which safeguards that.
781 comphelper::SolarMutex
& rSolarSafety
= Application::GetSolarMutex();
782 if (rSolarSafety
.tryToAcquire())
784 m_pShell
->GetViewShell()->GetViewFrame().GetBindings().Invalidate(SID_FM_RECORD_TOTAL
, true);
785 m_pShell
->GetViewShell()->GetViewFrame().GetBindings().Update(SID_FM_RECORD_TOTAL
);
786 rSolarSafety
.release();
790 // with the following the slot is invalidated asynchron
791 LockSlotInvalidation_Lock(true);
792 InvalidateSlot_Lock(SID_FM_RECORD_TOTAL
, false);
793 LockSlotInvalidation_Lock(false);
797 // this may be called from a non-main-thread so invalidate the shell asynchronously
798 LockSlotInvalidation_Lock(true);
799 InvalidateSlot_Lock(0, false); // special meaning : invalidate m_pShell
800 LockSlotInvalidation_Lock(false);
804 void FmXFormShell::invalidateFeatures( const ::std::vector
< sal_Int32
>& _rFeatures
)
808 if (impl_checkDisposed_Lock())
811 OSL_ENSURE( !_rFeatures
.empty(), "FmXFormShell::invalidateFeatures: invalid arguments!" );
813 if (!m_pShell
->GetViewShell())
816 // unfortunately, SFX requires sal_uInt16
817 ::std::vector
< sal_uInt16
> aSlotIds( _rFeatures
.begin(), _rFeatures
.end() );
819 // furthermore, SFX wants a terminating 0
820 aSlotIds
.push_back( 0 );
822 // and, last but not least, SFX wants the ids to be sorted
823 ::std::sort( aSlotIds
.begin(), aSlotIds
.end() - 1 );
825 sal_uInt16
*pSlotIds
= aSlotIds
.data();
826 m_pShell
->GetViewShell()->GetViewFrame().GetBindings().Invalidate( pSlotIds
);
830 void SAL_CALL
FmXFormShell::formActivated(const lang::EventObject
& rEvent
)
834 if (impl_checkDisposed_Lock())
837 Reference
< runtime::XFormController
> xController( rEvent
.Source
, UNO_QUERY_THROW
);
838 m_pTextShell
->formActivated( xController
);
839 setActiveController_Lock(xController
);
843 void SAL_CALL
FmXFormShell::formDeactivated(const lang::EventObject
& rEvent
)
847 if (impl_checkDisposed_Lock())
850 Reference
< runtime::XFormController
> xController( rEvent
.Source
, UNO_QUERY_THROW
);
851 m_pTextShell
->formDeactivated( xController
);
855 void FmXFormShell::disposing()
859 FmXFormShell_BASE::disposing();
861 if ( m_pShell
&& !m_pShell
->IsDesignMode() )
862 setActiveController_Lock(nullptr, true);
863 // do NOT save the content of the old form (the second parameter tells this)
864 // if we're here, then we expect that PrepareClose has been called, and thus the user
865 // got a chance to commit or reject any changes. So in case we're here and there
866 // are still uncommitted changes, the user explicitly wanted this.
868 m_pTextShell
->dispose();
870 m_xAttachedFrame
= nullptr;
872 CloseExternalFormViewer_Lock();
874 while ( !m_aLoadingPages
.empty() )
876 Application::RemoveUserEvent( m_aLoadingPages
.front().nEventId
);
877 m_aLoadingPages
.pop();
881 if (m_nInvalidationEvent
)
883 Application::RemoveUserEvent(m_nInvalidationEvent
);
884 m_nInvalidationEvent
= nullptr;
886 if ( m_nActivationEvent
)
888 Application::RemoveUserEvent( m_nActivationEvent
);
889 m_nActivationEvent
= nullptr;
894 DBG_ASSERT(!m_nInvalidationEvent
, "FmXFormShell::~FmXFormShell : still have an invalidation event !");
895 // should have been deleted while being disposed
900 DisableNotification();
902 RemoveElement_Lock(m_xForms
);
905 impl_switchActiveControllerListening_Lock(false);
906 m_xActiveController
= nullptr;
907 m_xActiveForm
= nullptr;
910 m_xNavigationController
= nullptr;
911 m_xCurrentForm
= nullptr;
912 m_xLastGridFound
= nullptr;
913 m_xAttachedFrame
= nullptr;
914 m_xExternalViewController
= nullptr;
915 m_xExtViewTriggerController
= nullptr;
916 m_xExternalDisplayedForm
= nullptr;
918 InterfaceBag().swap(m_aCurrentSelection
);
920 m_aActiveControllerFeatures
.dispose();
921 m_aNavControllerFeatures
.dispose();
925 void FmXFormShell::UpdateSlot_Lock(sal_Int16 _nId
)
927 if (impl_checkDisposed_Lock())
930 if ( m_nLockSlotInvalidation
)
932 OSL_FAIL( "FmXFormShell::UpdateSlot: cannot update if invalidation is currently locked!" );
933 InvalidateSlot_Lock(_nId
, false);
937 OSL_ENSURE( _nId
, "FmXFormShell::UpdateSlot: can't update the complete shell!" );
938 m_pShell
->GetViewShell()->GetViewFrame().GetBindings().Invalidate( _nId
, true, true );
939 m_pShell
->GetViewShell()->GetViewFrame().GetBindings().Update( _nId
);
943 void FmXFormShell::InvalidateSlot_Lock(sal_Int16 nId
, bool bWithId
)
945 if (impl_checkDisposed_Lock())
948 if (m_nLockSlotInvalidation
)
950 sal_uInt8 nFlags
= ( bWithId
? 0x01 : 0 );
951 m_arrInvalidSlots
.emplace_back(nId
, nFlags
);
955 m_pShell
->GetViewShell()->GetViewFrame().GetBindings().Invalidate(nId
, true, bWithId
);
957 m_pShell
->GetViewShell()->GetViewFrame().GetBindings().InvalidateShell(*m_pShell
);
960 void FmXFormShell::LockSlotInvalidation_Lock(bool bLock
)
962 if (impl_checkDisposed_Lock())
965 DBG_ASSERT(bLock
|| m_nLockSlotInvalidation
>0, "FmXFormShell::LockSlotInvalidation : invalid call !");
968 ++m_nLockSlotInvalidation
;
969 else if (!--m_nLockSlotInvalidation
)
971 // (asynchronously) invalidate everything accumulated during the locked phase
972 if (!m_nInvalidationEvent
)
973 m_nInvalidationEvent
= Application::PostUserEvent(LINK(this, FmXFormShell
, OnInvalidateSlots_Lock
));
977 IMPL_LINK_NOARG(FmXFormShell
, OnInvalidateSlots_Lock
, void*,void)
979 if (impl_checkDisposed_Lock())
982 m_nInvalidationEvent
= nullptr;
984 for (const auto& rInvalidSlot
: m_arrInvalidSlots
)
987 m_pShell
->GetViewShell()->GetViewFrame().GetBindings().Invalidate(rInvalidSlot
.id
, true, (rInvalidSlot
.flags
& 0x01));
989 m_pShell
->GetViewShell()->GetViewFrame().GetBindings().InvalidateShell(*m_pShell
);
991 m_arrInvalidSlots
.clear();
994 void FmXFormShell::ForceUpdateSelection_Lock()
996 if (impl_checkDisposed_Lock())
999 if (IsSelectionUpdatePending_Lock())
1001 m_aMarkTimer
.Stop();
1003 // optionally turn off the invalidation of slots which is implicitly done by SetSelection
1004 LockSlotInvalidation_Lock(true);
1006 SetSelection_Lock(m_pShell
->GetFormView()->GetMarkedObjectList());
1008 LockSlotInvalidation_Lock(false);
1012 void FmXFormShell::GetConversionMenu_Lock(weld::Menu
& rNewMenu
)
1014 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aConvertSlots
); ++i
)
1016 // the corresponding image at it
1017 rNewMenu
.append(OUString(aConvertSlots
[i
]), SvxResId(RID_SVXSW_CONVERTMENU
[i
]), aImgIds
[i
]);
1021 OUString
FmXFormShell::SlotToIdent(sal_uInt16 nSlot
)
1023 static_assert(SAL_N_ELEMENTS(SelObjectSlotMap
) >= SAL_N_ELEMENTS(aConvertSlots
));
1025 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aConvertSlots
); ++i
)
1027 if (nSlot
== SelObjectSlotMap
[i
])
1028 return OUString(aConvertSlots
[i
]);
1034 bool FmXFormShell::isControlConversionSlot(std::u16string_view rIdent
)
1036 for (const auto& rConvertSlot
: aConvertSlots
)
1037 if (rIdent
== rConvertSlot
)
1042 void FmXFormShell::executeControlConversionSlot_Lock(std::u16string_view rIdent
)
1044 OSL_PRECOND( canConvertCurrentSelectionToControl_Lock(rIdent
), "FmXFormShell::executeControlConversionSlot: illegal call!" );
1045 InterfaceBag::const_iterator aSelectedElement
= m_aCurrentSelection
.begin();
1046 if ( aSelectedElement
== m_aCurrentSelection
.end() )
1049 executeControlConversionSlot_Lock(Reference
<XFormComponent
>(*aSelectedElement
, UNO_QUERY
), rIdent
);
1052 bool FmXFormShell::executeControlConversionSlot_Lock(const Reference
<XFormComponent
>& _rxObject
, std::u16string_view rIdent
)
1054 if (impl_checkDisposed_Lock())
1057 OSL_ENSURE( _rxObject
.is(), "FmXFormShell::executeControlConversionSlot: invalid object!" );
1058 if ( !_rxObject
.is() )
1061 SdrPage
* pPage
= m_pShell
->GetCurPage();
1062 FmFormPage
* pFormPage
= dynamic_cast< FmFormPage
* >( pPage
);
1063 OSL_ENSURE( pFormPage
, "FmXFormShell::executeControlConversionSlot: no current (form) page!" );
1067 OSL_ENSURE( isSolelySelected_Lock(_rxObject
),
1068 "FmXFormShell::executeControlConversionSlot: hmm ... shouldn't this parameter be redundant?" );
1070 for (size_t lookupSlot
= 0; lookupSlot
< SAL_N_ELEMENTS(aConvertSlots
); ++lookupSlot
)
1072 if (rIdent
== aConvertSlots
[lookupSlot
])
1074 Reference
< XInterface
> xNormalizedObject( _rxObject
, UNO_QUERY
);
1076 FmFormObj
* pFormObject
= nullptr;
1077 SdrObjListIter
aPageIter( pFormPage
);
1078 while ( aPageIter
.IsMore() )
1080 SdrObject
* pCurrent
= aPageIter
.Next();
1081 pFormObject
= FmFormObj::GetFormObject( pCurrent
);
1085 Reference
< XInterface
> xCurrentNormalized( pFormObject
->GetUnoControlModel(), UNO_QUERY
);
1086 if ( xCurrentNormalized
.get() == xNormalizedObject
.get() )
1089 pFormObject
= nullptr;
1095 OUString
sNewName( getServiceNameByControlType( nObjectTypes
[ lookupSlot
] ) );
1096 const Reference
<XComponentContext
>& xContext
= comphelper::getProcessComponentContext();
1097 Reference
< XControlModel
> xNewModel( xContext
->getServiceManager()->createInstanceWithContext(sNewName
, xContext
), UNO_QUERY
);
1098 if (!xNewModel
.is())
1101 Reference
< XControlModel
> xOldModel( pFormObject
->GetUnoControlModel() );
1103 // transfer properties
1104 Reference
< XPropertySet
> xOldSet(xOldModel
, UNO_QUERY
);
1105 Reference
< XPropertySet
> xNewSet(xNewModel
, UNO_QUERY
);
1108 lang::Locale aNewLanguage
= Application::GetSettings().GetUILanguageTag().getLocale();
1109 TransferFormComponentProperties(xOldSet
, xNewSet
, aNewLanguage
);
1111 Sequence
< css::script::ScriptEventDescriptor
> aOldScripts
;
1112 Reference
< XChild
> xChild(xOldModel
, UNO_QUERY
);
1115 Reference
< XIndexAccess
> xParent(xChild
->getParent(), UNO_QUERY
);
1117 // remember old script events
1118 Reference
< css::script::XEventAttacherManager
> xEvManager(xChild
->getParent(), UNO_QUERY
);
1119 if (xParent
.is() && xEvManager
.is())
1121 sal_Int32 nIndex
= getElementPos(xParent
, xOldModel
);
1122 if (nIndex
>=0 && nIndex
<xParent
->getCount())
1123 aOldScripts
= xEvManager
->getScriptEvents(nIndex
);
1126 // replace the model within the parent container
1127 Reference
< XIndexContainer
> xIndexParent(xChild
->getParent(), UNO_QUERY
);
1128 if (xIndexParent
.is())
1130 // the form container works with FormComponents
1131 Reference
< XFormComponent
> xComponent(xNewModel
, UNO_QUERY
);
1132 DBG_ASSERT(xComponent
.is(), "FmXFormShell::executeControlConversionSlot: the new model is no form component !");
1133 Any
aNewModel(xComponent
);
1137 sal_Int32 nIndex
= getElementPos(xParent
, xOldModel
);
1138 if (nIndex
>=0 && nIndex
<xParent
->getCount())
1139 xIndexParent
->replaceByIndex(nIndex
, aNewModel
);
1142 OSL_FAIL("FmXFormShell::executeControlConversionSlot: could not replace the model !");
1143 Reference
< css::lang::XComponent
> xNewComponent(xNewModel
, UNO_QUERY
);
1144 if (xNewComponent
.is())
1145 xNewComponent
->dispose();
1151 OSL_FAIL("FmXFormShell::executeControlConversionSlot: could not replace the model !");
1152 Reference
< css::lang::XComponent
> xNewComponent(xNewModel
, UNO_QUERY
);
1153 if (xNewComponent
.is())
1154 xNewComponent
->dispose();
1161 // special handling for the LabelControl-property : can only be set when the model is placed
1162 // within the forms hierarchy
1163 if (::comphelper::hasProperty(FM_PROP_CONTROLLABEL
, xOldSet
) && ::comphelper::hasProperty(FM_PROP_CONTROLLABEL
, xNewSet
))
1167 xNewSet
->setPropertyValue(FM_PROP_CONTROLLABEL
, xOldSet
->getPropertyValue(FM_PROP_CONTROLLABEL
));
1176 pFormObject
->SetChanged();
1177 pFormObject
->SetUnoControlModel(xNewModel
);
1179 // transfer script events
1180 // (do this _after_ SetUnoControlModel as we need the new (implicitly created) control)
1181 if (aOldScripts
.hasElements())
1183 // find the control for the model
1184 Reference
<XControlContainer
> xControlContainer(getControlContainerForView_Lock());
1186 const Sequence
< Reference
< XControl
> > aControls( xControlContainer
->getControls() );
1188 Reference
< XControl
> xControl
;
1189 auto pControl
= std::find_if(aControls
.begin(), aControls
.end(),
1190 [&xNewModel
](const Reference
< XControl
>& rControl
) { return rControl
->getModel() == xNewModel
; });
1191 if (pControl
!= aControls
.end())
1192 xControl
= *pControl
;
1193 TransferEventScripts(xNewModel
, xControl
, aOldScripts
);
1196 // transfer value bindings, if possible
1198 Reference
< XBindableValue
> xOldBindable( xOldModel
, UNO_QUERY
);
1199 Reference
< XBindableValue
> xNewBindable( xNewModel
, UNO_QUERY
);
1200 if ( xOldBindable
.is() )
1204 if ( xNewBindable
.is() )
1205 xNewBindable
->setValueBinding( xOldBindable
->getValueBinding() );
1206 xOldBindable
->setValueBinding( nullptr );
1208 catch(const Exception
&)
1210 DBG_UNHANDLED_EXCEPTION("svx");
1214 // same for list entry sources
1216 Reference
< XListEntrySink
> xOldSink( xOldModel
, UNO_QUERY
);
1217 Reference
< XListEntrySink
> xNewSink( xNewModel
, UNO_QUERY
);
1218 if ( xOldSink
.is() )
1222 if ( xNewSink
.is() )
1223 xNewSink
->setListEntrySource( xOldSink
->getListEntrySource() );
1224 xOldSink
->setListEntrySource( nullptr );
1226 catch(const Exception
&)
1228 DBG_UNHANDLED_EXCEPTION("svx");
1233 // create an undo action
1234 FmFormModel
* pModel
= m_pShell
->GetFormModel();
1235 DBG_ASSERT(pModel
!= nullptr, "FmXFormShell::executeControlConversionSlot: my shell has no model !");
1236 if (pModel
&& pModel
->IsUndoEnabled() )
1238 pModel
->AddUndo(std::make_unique
<FmUndoModelReplaceAction
>(*pModel
, pFormObject
, xOldModel
));
1242 FmUndoModelReplaceAction::DisposeElement( xOldModel
);
1251 bool FmXFormShell::canConvertCurrentSelectionToControl_Lock(std::u16string_view rIdent
)
1253 if ( m_aCurrentSelection
.empty() )
1256 InterfaceBag::const_iterator aCheck
= m_aCurrentSelection
.begin();
1257 Reference
< lang::XServiceInfo
> xElementInfo( *aCheck
, UNO_QUERY
);
1258 if ( !xElementInfo
.is() )
1259 // no service info -> cannot determine this
1262 if ( ++aCheck
!= m_aCurrentSelection
.end() )
1263 // more than one element
1266 if ( Reference
< XForm
>::query( xElementInfo
).is() )
1270 SdrObjKind nObjectType
= getControlTypeByObject( xElementInfo
);
1272 if ( ( SdrObjKind::FormHidden
== nObjectType
)
1273 || ( SdrObjKind::FormControl
== nObjectType
)
1274 || ( SdrObjKind::FormGrid
== nObjectType
)
1276 return false; // those types cannot be converted
1278 DBG_ASSERT(SAL_N_ELEMENTS(aConvertSlots
) == SAL_N_ELEMENTS(nObjectTypes
),
1279 "FmXFormShell::canConvertCurrentSelectionToControl: aConvertSlots & nObjectTypes must have the same size !");
1281 for (size_t i
= 0; i
< SAL_N_ELEMENTS(aConvertSlots
); ++i
)
1282 if (rIdent
== aConvertSlots
[i
])
1283 return nObjectTypes
[i
] != nObjectType
;
1285 return true; // all other slots: assume "yes"
1288 void FmXFormShell::checkControlConversionSlotsForCurrentSelection_Lock(weld::Menu
& rMenu
)
1290 for (int i
= 0, nCount
= rMenu
.n_children(); i
< nCount
; ++i
)
1292 // the context is already of a type that corresponds to the entry -> disable
1293 OUString
sIdent(aConvertSlots
[i
]);
1294 rMenu
.set_sensitive(sIdent
, canConvertCurrentSelectionToControl_Lock(sIdent
));
1298 void FmXFormShell::LoopGrids_Lock(LoopGridsSync nSync
, LoopGridsFlags nFlags
)
1300 if (impl_checkDisposed_Lock())
1303 Reference
< XIndexContainer
> xControlModels(m_xActiveForm
, UNO_QUERY
);
1304 if (!xControlModels
.is())
1307 for (sal_Int32 i
=0; i
<xControlModels
->getCount(); ++i
)
1309 Reference
< XPropertySet
> xModelSet
;
1310 xControlModels
->getByIndex(i
) >>= xModelSet
;
1311 if (!xModelSet
.is())
1314 if (!::comphelper::hasProperty(FM_PROP_CLASSID
, xModelSet
))
1316 sal_Int16 nClassId
= ::comphelper::getINT16(xModelSet
->getPropertyValue(FM_PROP_CLASSID
));
1317 if (FormComponentType::GRIDCONTROL
!= nClassId
)
1320 if (!::comphelper::hasProperty(FM_PROP_CURSORCOLOR
, xModelSet
) || !::comphelper::hasProperty(FM_PROP_ALWAYSSHOWCURSOR
, xModelSet
) || !::comphelper::hasProperty(FM_PROP_DISPLAYSYNCHRON
, xModelSet
))
1325 case LoopGridsSync::DISABLE_SYNC
:
1327 xModelSet
->setPropertyValue(FM_PROP_DISPLAYSYNCHRON
, Any(false));
1330 case LoopGridsSync::FORCE_SYNC
:
1332 Any
aOldVal( xModelSet
->getPropertyValue(FM_PROP_DISPLAYSYNCHRON
) );
1333 xModelSet
->setPropertyValue(FM_PROP_DISPLAYSYNCHRON
, Any(true));
1334 xModelSet
->setPropertyValue(FM_PROP_DISPLAYSYNCHRON
, aOldVal
);
1337 case LoopGridsSync::ENABLE_SYNC
:
1339 xModelSet
->setPropertyValue(FM_PROP_DISPLAYSYNCHRON
, Any(true));
1344 if (nFlags
& LoopGridsFlags::DISABLE_ROCTRLR
)
1346 xModelSet
->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR
, Any(false));
1347 Reference
< XPropertyState
> xModelPropState(xModelSet
, UNO_QUERY
);
1348 if (xModelPropState
.is())
1349 xModelPropState
->setPropertyToDefault(FM_PROP_CURSORCOLOR
);
1351 xModelSet
->setPropertyValue(FM_PROP_CURSORCOLOR
, Any()); // this should be the default
1357 Reference
< XControlContainer
> FmXFormShell::getControlContainerForView_Lock() const
1359 if (impl_checkDisposed_Lock())
1362 SdrPageView
* pPageView
= nullptr;
1363 if ( m_pShell
&& m_pShell
->GetFormView() )
1364 pPageView
= m_pShell
->GetFormView()->GetSdrPageView();
1366 Reference
< XControlContainer
> xControlContainer
;
1368 xControlContainer
= pPageView
->GetPageWindow(0)->GetControlContainer();
1370 return xControlContainer
;
1374 void FmXFormShell::ExecuteTabOrderDialog_Lock(const Reference
<XTabControllerModel
>& _rxForForm
)
1376 if (impl_checkDisposed_Lock())
1379 OSL_PRECOND( _rxForForm
.is(), "FmXFormShell::ExecuteTabOrderDialog: invalid tabbing model!" );
1380 if ( !_rxForForm
.is() )
1385 Reference
< XWindow
> xParentWindow
;
1386 if (m_pShell
->GetViewShell())
1387 xParentWindow
= VCLUnoHelper::GetInterface ( &m_pShell
->GetViewShell()->GetViewFrame().GetWindow() );
1389 Reference
< dialogs::XExecutableDialog
> xDialog
= form::TabOrderDialog::createWithModel(
1390 comphelper::getProcessComponentContext(),
1391 _rxForForm
, getControlContainerForView_Lock(), xParentWindow
1394 (void)xDialog
->execute();
1396 catch( const Exception
& )
1398 TOOLS_WARN_EXCEPTION( "svx", "FmXFormShell::ExecuteTabOrderDialog" );
1403 void FmXFormShell::ExecuteSearch_Lock()
1405 if (impl_checkDisposed_Lock())
1408 // a collection of all (logical) forms
1409 FmFormArray().swap(m_aSearchForms
);
1410 ::std::vector
< OUString
> aContextNames
;
1411 impl_collectFormSearchContexts_nothrow_Lock(
1412 m_pShell
->GetCurPage()->GetForms(), u
"",
1413 m_aSearchForms
, aContextNames
);
1415 if ( m_aSearchForms
.size() != aContextNames
.size() )
1417 SAL_WARN ( "svx.form", "FmXFormShell::ExecuteSearch: nonsense!" );
1421 // filter out the forms which do not contain valid controls at all
1423 FmFormArray aValidForms
;
1424 ::std::vector
< OUString
> aValidContexts
;
1425 FmFormArray::const_iterator form
= m_aSearchForms
.begin();
1426 ::std::vector
< OUString
>::const_iterator contextName
= aContextNames
.begin();
1427 for ( ; form
!= m_aSearchForms
.end(); ++form
, ++contextName
)
1429 FmSearchContext aTestContext
;
1430 aTestContext
.nContext
= static_cast< sal_Int16
>( form
- m_aSearchForms
.begin() );
1431 sal_uInt32 nValidControls
= OnSearchContextRequest_Lock(aTestContext
);
1432 if ( nValidControls
> 0 )
1434 aValidForms
.push_back( *form
);
1435 aValidContexts
.push_back( *contextName
);
1439 m_aSearchForms
.swap( aValidForms
);
1440 aContextNames
.swap( aValidContexts
);
1443 if (m_aSearchForms
.empty() )
1445 // there are no controls that meet all the conditions for a search
1446 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(nullptr,
1447 VclMessageType::Warning
, VclButtonsType::Ok
,
1448 SvxResId(RID_STR_NODATACONTROLS
)));
1453 // now I need another 'initial context'
1454 sal_Int16 nInitialContext
= 0;
1455 Reference
<XForm
> xActiveForm(getActiveForm_Lock());
1456 for ( size_t i
=0; i
<m_aSearchForms
.size(); ++i
)
1458 if (m_aSearchForms
.at(i
) == xActiveForm
)
1460 nInitialContext
= static_cast<sal_Int16
>(i
);
1465 // If the dialog should initially offer the text of the active control,
1466 // this must have an XTextComponent interface. An addition, this makes
1467 // sense only if the current field is also bound to a table (or whatever) field.
1468 OUString strActiveField
;
1469 OUString strInitialText
;
1470 // ... this I get from my FormController
1471 DBG_ASSERT(m_xActiveController
.is(), "FmXFormShell::ExecuteSearch : no active controller !");
1472 Reference
< XControl
> xActiveControl( m_xActiveController
->getCurrentControl());
1473 if (xActiveControl
.is())
1475 // the control can tell me its model ...
1476 Reference
< XControlModel
> xActiveModel( xActiveControl
->getModel());
1477 DBG_ASSERT(xActiveModel
.is(), "FmXFormShell::ExecuteSearch : active control has no model !");
1479 // I ask the model for the ControlSource property ...
1480 Reference
< XPropertySet
> xProperties(xActiveControl
->getModel(), UNO_QUERY
);
1481 if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCE
, xProperties
) && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD
, xProperties
))
1483 Reference
< XPropertySet
> xField
;
1484 xProperties
->getPropertyValue(FM_PROP_BOUNDFIELD
) >>= xField
;
1485 if (xField
.is()) // (only when the thing is really bound)
1487 // and the control itself for a TextComponent interface (so that I can pick up the text there)
1488 Reference
< XTextComponent
> xText(xActiveControl
, UNO_QUERY
);
1491 strActiveField
= getLabelName(xProperties
);
1492 strInitialText
= xText
->getText();
1498 // the control itself has no ControlSource, but maybe it is a GridControl
1499 Reference
< XGrid
> xGrid(xActiveControl
, UNO_QUERY
);
1502 // for strActiveField I need the ControlSource of the column,
1503 // for that the columns container, for that the GridPeer
1504 Reference
< XGridPeer
> xGridPeer(xActiveControl
->getPeer(), UNO_QUERY
);
1505 Reference
< XIndexAccess
> xColumns
;
1507 xColumns
= xGridPeer
->getColumns();
1509 sal_Int16 nViewCol
= xGrid
->getCurrentColumnPosition();
1510 sal_Int32 nModelCol
= GridView2ModelPos(xColumns
, nViewCol
);
1511 Reference
< XPropertySet
> xCurrentCol
;
1513 xColumns
->getByIndex(nModelCol
) >>= xCurrentCol
;
1514 if (xCurrentCol
.is())
1515 strActiveField
= ::comphelper::getString(xCurrentCol
->getPropertyValue(FM_PROP_LABEL
));
1517 // the text of the current column
1518 Reference
< XIndexAccess
> xColControls(xGridPeer
, UNO_QUERY
);
1519 Reference
< XInterface
> xCurControl
;
1520 xColControls
->getByIndex(nViewCol
) >>= xCurControl
;
1521 OUString sInitialText
;
1522 if (IsSearchableControl(xCurControl
, &sInitialText
))
1523 strInitialText
= sInitialText
;
1528 // taking care of possible GridControls that I know
1529 LoopGrids_Lock(LoopGridsSync::DISABLE_SYNC
);
1531 // Now I am ready for the dialogue.
1532 // When the potential deadlocks caused by the use of the solar mutex in
1533 // MTs VCLX... classes are eventually cleared, an SM_USETHREAD should be
1534 // placed here, because the search in a separate thread is nevertheless
1535 // somewhat more fluid. Should be, however, somehow made dependent of the
1536 // underlying cursor. DAO for example is not thread-safe.
1537 SvxAbstractDialogFactory
* pFact
= SvxAbstractDialogFactory::Create();
1538 ScopedVclPtr
<AbstractFmSearchDialog
> pDialog(
1539 pFact
->CreateFmSearchDialog(
1540 m_pShell
->GetViewShell()->GetViewFrame().GetFrameWeld(),
1541 strInitialText
, aContextNames
, nInitialContext
,
1542 LINK(this, FmXFormShell
, OnSearchContextRequest_Lock
) ));
1543 pDialog
->SetActiveField( strActiveField
);
1544 pDialog
->SetFoundHandler(LINK(this, FmXFormShell
, OnFoundData_Lock
));
1545 pDialog
->SetCanceledNotFoundHdl(LINK(this, FmXFormShell
, OnCanceledNotFound_Lock
));
1547 pDialog
.disposeAndClear();
1549 // restore GridControls again
1550 LoopGrids_Lock(LoopGridsSync::ENABLE_SYNC
, LoopGridsFlags::DISABLE_ROCTRLR
);
1552 m_pShell
->GetFormView()->UnMarkAll(m_pShell
->GetFormView()->GetSdrPageView());
1553 // because I marked controls in OnFoundData (if I was there)
1557 bool FmXFormShell::GetY2KState_Lock(sal_uInt16
& n
)
1559 if (impl_checkDisposed_Lock())
1562 if (m_pShell
->IsDesignMode())
1563 // in the design mode (without active controls) the main document is to take care of it
1566 Reference
<XForm
> xForm(getActiveForm_Lock());
1568 // no current form (in particular no current control) -> the main document is to take care
1571 Reference
< XRowSet
> xDB(xForm
, UNO_QUERY
);
1572 DBG_ASSERT(xDB
.is(), "FmXFormShell::GetY2KState : current form has no dbform-interface !");
1574 Reference
< XNumberFormatsSupplier
> xSupplier( getNumberFormats(getConnection(xDB
)));
1577 Reference
< XPropertySet
> xSet(xSupplier
->getNumberFormatSettings());
1582 Any
aVal( xSet
->getPropertyValue(u
"TwoDigitDateStart"_ustr
) );
1596 void FmXFormShell::SetY2KState_Lock(sal_uInt16 n
)
1598 if (impl_checkDisposed_Lock())
1601 Reference
<XForm
> xActiveForm(getActiveForm_Lock());
1602 Reference
< XRowSet
> xActiveRowSet( xActiveForm
, UNO_QUERY
);
1603 if ( xActiveRowSet
.is() )
1605 Reference
< XNumberFormatsSupplier
> xSupplier( getNumberFormats( getConnection( xActiveRowSet
) ) );
1608 Reference
< XPropertySet
> xSet(xSupplier
->getNumberFormatSettings());
1613 xSet
->setPropertyValue(u
"TwoDigitDateStart"_ustr
, Any(sal_uInt16(n
)));
1617 TOOLS_WARN_EXCEPTION("svx.form", "");
1625 // no active form found -> iterate through all current forms
1626 Reference
< XIndexAccess
> xCurrentForms( m_xForms
);
1627 if (!xCurrentForms
.is())
1628 { // in the alive mode, my forms are not set, but the ones on the page are
1629 if (m_pShell
->GetCurPage())
1630 xCurrentForms
= m_pShell
->GetCurPage()->GetForms( false );
1632 if (!xCurrentForms
.is())
1635 ::comphelper::IndexAccessIterator
aIter(xCurrentForms
);
1636 Reference
< XInterface
> xCurrentElement( aIter
.Next());
1637 while (xCurrentElement
.is())
1639 // is the current element a DatabaseForm?
1640 Reference
< XRowSet
> xElementAsRowSet( xCurrentElement
, UNO_QUERY
);
1641 if ( xElementAsRowSet
.is() )
1643 Reference
< XNumberFormatsSupplier
> xSupplier( getNumberFormats( getConnection( xElementAsRowSet
) ) );
1644 if (!xSupplier
.is())
1647 Reference
< XPropertySet
> xSet(xSupplier
->getNumberFormatSettings());
1652 xSet
->setPropertyValue(u
"TwoDigitDateStart"_ustr
, Any(sal_uInt16(n
)));
1656 TOOLS_WARN_EXCEPTION("svx.form", "");
1661 xCurrentElement
= aIter
.Next();
1666 void FmXFormShell::CloseExternalFormViewer_Lock()
1668 if (impl_checkDisposed_Lock())
1671 if (!m_xExternalViewController
.is())
1674 Reference
< css::frame::XFrame
> xExternalViewFrame( m_xExternalViewController
->getFrame());
1675 Reference
< css::frame::XDispatchProvider
> xCommLink(xExternalViewFrame
, UNO_QUERY
);
1676 if (!xCommLink
.is())
1679 xExternalViewFrame
->setComponent(nullptr,nullptr);
1680 ::comphelper::disposeComponent(xExternalViewFrame
);
1681 m_xExternalViewController
= nullptr;
1682 m_xExtViewTriggerController
= nullptr;
1683 m_xExternalDisplayedForm
= nullptr;
1687 Reference
<XResultSet
> FmXFormShell::getInternalForm_Lock(const Reference
<XResultSet
>& _xForm
) const
1689 if (impl_checkDisposed_Lock())
1692 Reference
< runtime::XFormController
> xExternalCtrlr(m_xExternalViewController
, UNO_QUERY
);
1693 if (xExternalCtrlr
.is() && (_xForm
== xExternalCtrlr
->getModel()))
1695 DBG_ASSERT(m_xExternalDisplayedForm
.is(), "FmXFormShell::getInternalForm : invalid external form !");
1696 return m_xExternalDisplayedForm
;
1702 Reference
<XForm
> FmXFormShell::getInternalForm_Lock(const Reference
<XForm
>& _xForm
) const
1704 if (impl_checkDisposed_Lock())
1707 Reference
< runtime::XFormController
> xExternalCtrlr(m_xExternalViewController
, UNO_QUERY
);
1708 if (xExternalCtrlr
.is() && (_xForm
== xExternalCtrlr
->getModel()))
1710 DBG_ASSERT(m_xExternalDisplayedForm
.is(), "FmXFormShell::getInternalForm : invalid external form !");
1711 return Reference
< XForm
>(m_xExternalDisplayedForm
, UNO_QUERY
);
1719 bool lcl_isNavigationRelevant( sal_Int32 _nWhich
)
1721 return ( _nWhich
== SID_FM_RECORD_FIRST
)
1722 || ( _nWhich
== SID_FM_RECORD_PREV
)
1723 || ( _nWhich
== SID_FM_RECORD_NEXT
)
1724 || ( _nWhich
== SID_FM_RECORD_LAST
)
1725 || ( _nWhich
== SID_FM_RECORD_NEW
);
1730 bool FmXFormShell::IsFormSlotEnabled( sal_Int32 _nSlot
, FeatureState
* _pCompleteState
) const
1732 const svx::ControllerFeatures
& rController
=
1733 lcl_isNavigationRelevant( _nSlot
)
1734 ? getNavControllerFeatures_Lock()
1735 : getActiveControllerFeatures_Lock();
1737 if ( !_pCompleteState
)
1738 return rController
->isEnabled( _nSlot
);
1740 rController
->getState( _nSlot
, *_pCompleteState
);
1741 return _pCompleteState
->Enabled
;
1745 void FmXFormShell::ExecuteFormSlot_Lock( sal_Int32 _nSlot
)
1747 const svx::ControllerFeatures
& rController
=
1748 lcl_isNavigationRelevant( _nSlot
)
1749 ? getNavControllerFeatures_Lock()
1750 : getActiveControllerFeatures_Lock();
1752 rController
->execute( _nSlot
);
1754 if ( _nSlot
!= SID_FM_RECORD_UNDO
)
1757 // if we're doing an UNDO, *and* if the affected form is the form which we also display
1758 // as external view, then we need to reset the controls of the external form, too
1759 if (getInternalForm_Lock(getActiveForm_Lock()) != m_xExternalDisplayedForm
)
1762 Reference
< XIndexAccess
> xContainer( m_xExternalDisplayedForm
, UNO_QUERY
);
1763 if ( !xContainer
.is() )
1766 Reference
< XReset
> xReset
;
1767 for ( sal_Int32 i
= 0; i
< xContainer
->getCount(); ++i
)
1769 if ( ( xContainer
->getByIndex( i
) >>= xReset
) && xReset
.is() )
1771 // no resets on sub forms
1772 Reference
< XForm
> xAsForm( xReset
, UNO_QUERY
);
1773 if ( !xAsForm
.is() )
1779 void FmXFormShell::impl_switchActiveControllerListening_Lock(const bool _bListen
)
1781 if ( !m_xActiveController
.is() )
1785 m_xActiveController
->addEventListener( static_cast<XFormControllerListener
*>(this) );
1787 m_xActiveController
->removeEventListener( static_cast<XFormControllerListener
*>(this) );
1790 void FmXFormShell::setActiveController_Lock(const Reference
<runtime::XFormController
>& xController
, bool _bNoSaveOldContent
)
1792 if (impl_checkDisposed_Lock())
1795 if (m_bChangingDesignMode
)
1797 DBG_ASSERT(!m_pShell
->IsDesignMode(), "only to be used in alive mode");
1799 // if the routine has been called a second time,
1800 // the focus should no longer be transferred
1803 m_bSetFocus
= xController
!= m_xActiveController
;
1807 if (xController
== m_xActiveController
)
1810 // switch all nav dispatchers belonging to the form of the current nav controller to 'non active'
1811 Reference
< XResultSet
> xNavigationForm
;
1812 if (m_xNavigationController
.is())
1813 xNavigationForm
.set(m_xNavigationController
->getModel(), UNO_QUERY
);
1815 m_bInActivate
= true;
1817 // check if the 2 controllers serve different forms
1818 Reference
< XResultSet
> xOldForm
;
1819 if (m_xActiveController
.is())
1820 xOldForm
.set(m_xActiveController
->getModel(), UNO_QUERY
);
1821 Reference
< XResultSet
> xNewForm
;
1822 if (xController
.is())
1823 xNewForm
= Reference
< XResultSet
>(xController
->getModel(), UNO_QUERY
);
1824 xOldForm
= getInternalForm_Lock(xOldForm
);
1825 xNewForm
= getInternalForm_Lock(xNewForm
);
1827 bool bDifferentForm
= ( xOldForm
.get() != xNewForm
.get() );
1828 bool bNeedSave
= bDifferentForm
&& !_bNoSaveOldContent
;
1829 // we save the content of the old form if we move to a new form, and saving old content is allowed
1831 if ( m_xActiveController
.is() && bNeedSave
)
1833 // save content on change of the controller; a commit has already been executed
1834 if ( m_aActiveControllerFeatures
->commitCurrentControl() )
1837 if ( m_aActiveControllerFeatures
->isModifiedRow() )
1839 bool bIsNew
= m_aActiveControllerFeatures
->isInsertionRow();
1840 bool bResult
= m_aActiveControllerFeatures
->commitCurrentRecord();
1841 if ( !bResult
&& m_bSetFocus
)
1843 // if we couldn't save the current record, set the focus back to the
1845 Reference
< XWindow
> xWindow( m_xActiveController
->getCurrentControl(), UNO_QUERY
);
1847 xWindow
->setFocus();
1848 m_bInActivate
= false;
1851 else if ( bResult
&& bIsNew
)
1853 Reference
< XResultSet
> xCursor( m_aActiveControllerFeatures
->getCursor() );
1856 DO_SAFE( xCursor
->last(); );
1863 stopListening_Lock();
1865 impl_switchActiveControllerListening_Lock(false);
1867 m_aActiveControllerFeatures
.dispose();
1868 m_xActiveController
= xController
;
1869 if ( m_xActiveController
.is() )
1870 m_aActiveControllerFeatures
.assign( m_xActiveController
);
1872 impl_switchActiveControllerListening_Lock(true);
1874 if ( m_xActiveController
.is() )
1875 m_xActiveForm
= getInternalForm_Lock(Reference
<XForm
>(m_xActiveController
->getModel(), UNO_QUERY
));
1877 m_xActiveForm
= nullptr;
1879 startListening_Lock();
1881 // activate all dispatchers belonging to form of the new navigation controller
1882 xNavigationForm
= nullptr;
1883 if (m_xNavigationController
.is())
1884 xNavigationForm
.set(m_xNavigationController
->getModel(), UNO_QUERY
);
1886 m_bInActivate
= false;
1888 m_pShell
->UIFeatureChanged();
1889 m_pShell
->GetViewShell()->GetViewFrame().GetBindings().InvalidateShell(*m_pShell
);
1891 InvalidateSlot_Lock(SID_FM_FILTER_NAVIGATOR_CONTROL
, true);
1894 void FmXFormShell::getCurrentSelection_Lock(InterfaceBag
& /* [out] */ _rSelection
) const
1896 _rSelection
= m_aCurrentSelection
;
1899 bool FmXFormShell::setCurrentSelectionFromMark_Lock(const SdrMarkList
& _rMarkList
)
1901 m_aLastKnownMarkedControls
.clear();
1903 if ( ( _rMarkList
.GetMarkCount() > 0 ) && isControlList( _rMarkList
) )
1904 collectInterfacesFromMarkList( _rMarkList
, m_aLastKnownMarkedControls
);
1906 return setCurrentSelection_Lock(o3tl::sorted_vector(m_aLastKnownMarkedControls
));
1910 bool FmXFormShell::selectLastMarkedControls_Lock()
1912 return setCurrentSelection_Lock(o3tl::sorted_vector(m_aLastKnownMarkedControls
));
1916 bool FmXFormShell::setCurrentSelection_Lock( InterfaceBag
&& _rSelection
)
1918 if (impl_checkDisposed_Lock())
1921 DBG_ASSERT( m_pShell
->IsDesignMode(), "FmXFormShell::setCurrentSelection: only to be used in design mode!" );
1923 if ( _rSelection
.empty() && m_aCurrentSelection
.empty() )
1927 if ( _rSelection
.size() == m_aCurrentSelection
.size() )
1929 InterfaceBag::const_iterator aNew
= _rSelection
.begin();
1930 InterfaceBag::const_iterator aOld
= m_aCurrentSelection
.begin();
1931 for ( ; aNew
!= _rSelection
.end(); ++aNew
, ++aOld
)
1933 OSL_ENSURE( Reference
< XInterface
>( *aNew
, UNO_QUERY
).get() == aNew
->get(), "FmXFormShell::setCurrentSelection: new interface not normalized!" );
1934 OSL_ENSURE( Reference
< XInterface
>( *aOld
, UNO_QUERY
).get() == aOld
->get(), "FmXFormShell::setCurrentSelection: old interface not normalized!" );
1936 if ( aNew
->get() != aOld
->get() )
1940 if ( aNew
== _rSelection
.end() )
1945 // the following is some strange code to ensure that when you have two grid controls in a document,
1946 // only one of them can have a selected column.
1947 // TODO: this should happen elsewhere, but not here - shouldn't it?
1948 if ( !m_aCurrentSelection
.empty() )
1950 Reference
< XChild
> xCur
; if ( m_aCurrentSelection
.size() == 1 ) xCur
.set(*m_aCurrentSelection
.begin(), css::uno::UNO_QUERY
);
1951 Reference
< XChild
> xNew
; if ( _rSelection
.size() == 1 ) xNew
.set(*_rSelection
.begin(), css::uno::UNO_QUERY
);
1953 // is there nothing to be selected, or the parents differ, and the parent of the current object
1954 // is a selection supplier, then deselect
1955 if ( xCur
.is() && ( !xNew
.is() || ( xCur
->getParent() != xNew
->getParent() ) ) )
1957 Reference
< XSelectionSupplier
> xSel( xCur
->getParent(), UNO_QUERY
);
1959 xSel
->select( Any() );
1963 m_aCurrentSelection
= std::move(_rSelection
);
1965 // determine the form which all the selected objects belong to, if any
1966 Reference
< XForm
> xNewCurrentForm
;
1967 for (const auto& rpSelection
: m_aCurrentSelection
)
1969 Reference
< XForm
> xThisRoundsForm( GetForm( rpSelection
) );
1970 OSL_ENSURE( xThisRoundsForm
.is(), "FmXFormShell::setCurrentSelection: *everything* should belong to a form!" );
1972 if ( !xNewCurrentForm
.is() )
1973 { // the first form we encountered
1974 xNewCurrentForm
= std::move(xThisRoundsForm
);
1976 else if ( xNewCurrentForm
!= xThisRoundsForm
)
1977 { // different forms -> no "current form" at all
1978 xNewCurrentForm
.clear();
1983 if ( !m_aCurrentSelection
.empty() )
1984 impl_updateCurrentForm_Lock(xNewCurrentForm
);
1986 // ensure some slots are updated
1987 for (sal_Int16 i
: SelObjectSlotMap
)
1988 InvalidateSlot_Lock(i
, false);
1994 bool FmXFormShell::isSolelySelected_Lock(const Reference
<XInterface
>& _rxObject
)
1996 return ( m_aCurrentSelection
.size() == 1 ) && ( *m_aCurrentSelection
.begin() == _rxObject
);
2000 void FmXFormShell::forgetCurrentForm_Lock()
2002 if ( !m_xCurrentForm
.is() )
2006 impl_updateCurrentForm_Lock(nullptr);
2008 // ... and try finding a new current form
2009 // #i88186# / 2008-04-12 / frank.schoenheit@sun.com
2010 impl_defaultCurrentForm_nothrow_Lock();
2014 void FmXFormShell::impl_updateCurrentForm_Lock(const Reference
<XForm
>& _rxNewCurForm
)
2016 if (impl_checkDisposed_Lock())
2019 m_xCurrentForm
= _rxNewCurForm
;
2021 // propagate to the FormPage(Impl)
2022 FmFormPage
* pPage
= m_pShell
->GetCurPage();
2024 pPage
->GetImpl().setCurForm( m_xCurrentForm
);
2026 // ensure the UI which depends on the current form is up-to-date
2027 for (sal_Int16 i
: DlgSlotMap
)
2028 InvalidateSlot_Lock(i
, false);
2032 void FmXFormShell::startListening_Lock()
2034 if (impl_checkDisposed_Lock())
2037 Reference
< XRowSet
> xDatabaseForm(m_xActiveForm
, UNO_QUERY
);
2038 if (xDatabaseForm
.is() && getConnection(xDatabaseForm
).is())
2040 Reference
< XPropertySet
> xActiveFormSet(m_xActiveForm
, UNO_QUERY
);
2041 if (xActiveFormSet
.is())
2043 // if there is a data source, then build the listener
2044 // TODO: this is strange - shouldn't this depend on a isLoaded instead of
2045 // a "has command value"? Finally, the command value only means that it was
2046 // intended to be loaded, not that it actually *is* loaded
2047 OUString aSource
= ::comphelper::getString(xActiveFormSet
->getPropertyValue(FM_PROP_COMMAND
));
2048 if (!aSource
.isEmpty())
2050 m_bDatabaseBar
= true;
2052 xActiveFormSet
->getPropertyValue(FM_PROP_NAVIGATION
) >>= m_eNavigate
;
2054 switch (m_eNavigate
)
2056 case NavigationBarMode_PARENT
:
2058 // search for the controller via which navigation is possible
2059 Reference
< XChild
> xChild
= m_xActiveController
;
2060 Reference
< runtime::XFormController
> xParent
;
2063 xChild
.set(xChild
->getParent(), UNO_QUERY
);
2064 xParent
.set(xChild
, UNO_QUERY
);
2065 Reference
< XPropertySet
> xParentSet
;
2067 xParentSet
.set(xParent
->getModel(), UNO_QUERY
);
2068 if (xParentSet
.is())
2070 xParentSet
->getPropertyValue(FM_PROP_NAVIGATION
) >>= m_eNavigate
;
2071 if (m_eNavigate
== NavigationBarMode_CURRENT
)
2075 m_xNavigationController
= std::move(xParent
);
2079 case NavigationBarMode_CURRENT
:
2080 m_xNavigationController
= m_xActiveController
;
2084 m_xNavigationController
= nullptr;
2085 m_bDatabaseBar
= false;
2088 m_aNavControllerFeatures
.dispose();
2089 if ( m_xNavigationController
.is() && ( m_xNavigationController
!= m_xActiveController
) )
2090 m_aNavControllerFeatures
.assign( m_xNavigationController
);
2092 // because of RecordCount, listen at the controller which controls the navigation
2093 Reference
< XPropertySet
> xNavigationSet
;
2094 if (m_xNavigationController
.is())
2096 xNavigationSet
.set(m_xNavigationController
->getModel(), UNO_QUERY
);
2097 if (xNavigationSet
.is())
2098 xNavigationSet
->addPropertyChangeListener(FM_PROP_ROWCOUNT
,this);
2105 m_eNavigate
= NavigationBarMode_NONE
;
2106 m_bDatabaseBar
= false;
2107 m_xNavigationController
= nullptr;
2111 void FmXFormShell::stopListening_Lock()
2113 if (impl_checkDisposed_Lock())
2116 Reference
< XRowSet
> xDatabaseForm(m_xActiveForm
, UNO_QUERY
);
2117 if ( xDatabaseForm
.is() )
2119 if (m_xNavigationController
.is())
2121 Reference
< XPropertySet
> xSet(m_xNavigationController
->getModel(), UNO_QUERY
);
2123 xSet
->removePropertyChangeListener(FM_PROP_ROWCOUNT
, this);
2128 m_bDatabaseBar
= false;
2129 m_eNavigate
= NavigationBarMode_NONE
;
2130 m_xNavigationController
= nullptr;
2133 void FmXFormShell::ShowSelectionProperties_Lock(bool bShow
)
2135 if (impl_checkDisposed_Lock())
2138 // if the window is already visible, only update the state
2139 bool bHasChild
= m_pShell
->GetViewShell()->GetViewFrame().HasChildWindow( SID_FM_SHOW_PROPERTIES
);
2140 if ( bHasChild
&& bShow
)
2141 UpdateSlot_Lock(SID_FM_PROPERTY_CONTROL
);
2143 // else toggle state
2145 m_pShell
->GetViewShell()->GetViewFrame().ToggleChildWindow(SID_FM_SHOW_PROPERTIES
);
2147 InvalidateSlot_Lock(SID_FM_PROPERTIES
, false);
2148 InvalidateSlot_Lock(SID_FM_CTL_PROPERTIES
, false);
2151 IMPL_LINK(FmXFormShell
, OnFoundData_Lock
, FmFoundRecordInformation
&, rfriWhere
, void)
2153 if (impl_checkDisposed_Lock())
2156 DBG_ASSERT((rfriWhere
.nContext
>= 0) && (o3tl::make_unsigned(rfriWhere
.nContext
) < m_aSearchForms
.size()),
2157 "FmXFormShell::OnFoundData : invalid context!");
2158 Reference
< XForm
> xForm( m_aSearchForms
.at(rfriWhere
.nContext
));
2159 DBG_ASSERT(xForm
.is(), "FmXFormShell::OnFoundData : invalid form!");
2161 Reference
< XRowLocate
> xCursor(xForm
, UNO_QUERY
);
2163 return; // what should I do there?
2168 xCursor
->moveToBookmark(rfriWhere
.aPosition
);
2170 catch(const SQLException
&)
2172 OSL_FAIL("Can position on bookmark!");
2175 LoopGrids_Lock(LoopGridsSync::FORCE_SYNC
);
2177 // and to the field (for that, I collected the XVclComponent interfaces before the start of the search)
2178 SAL_WARN_IF(o3tl::make_unsigned(rfriWhere
.nFieldPos
) >=
2179 m_arrSearchedControls
.size(),
2180 "svx.form", "FmXFormShell::OnFoundData : invalid index!");
2181 SdrObject
* pObject
= m_arrSearchedControls
.at(rfriWhere
.nFieldPos
);
2183 m_pShell
->GetFormView()->UnMarkAll(m_pShell
->GetFormView()->GetSdrPageView());
2184 m_pShell
->GetFormView()->MarkObj(pObject
, m_pShell
->GetFormView()->GetSdrPageView());
2186 FmFormObj
* pFormObject
= FmFormObj::GetFormObject( pObject
);
2187 Reference
< XControlModel
> xControlModel( pFormObject
? pFormObject
->GetUnoControlModel() : Reference
< XControlModel
>() );
2188 DBG_ASSERT( xControlModel
.is(), "FmXFormShell::OnFoundData: invalid control!" );
2189 if ( !xControlModel
.is() )
2192 // disable the permanent cursor for the last grid we found a record
2193 if (m_xLastGridFound
.is() && (m_xLastGridFound
!= xControlModel
))
2195 Reference
< XPropertySet
> xOldSet(m_xLastGridFound
, UNO_QUERY
);
2196 xOldSet
->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR
, Any( false ) );
2197 Reference
< XPropertyState
> xOldSetState(xOldSet
, UNO_QUERY
);
2198 if (xOldSetState
.is())
2199 xOldSetState
->setPropertyToDefault(FM_PROP_CURSORCOLOR
);
2201 xOldSet
->setPropertyValue(FM_PROP_CURSORCOLOR
, Any());
2204 // if the field is in a GridControl, I have to additionally go into the corresponding column there
2205 sal_Int32 nGridColumn
= m_arrRelativeGridColumn
[rfriWhere
.nFieldPos
];
2206 if (nGridColumn
!= -1)
2207 { // unfortunately, I have to first get the control again
2208 Reference
<XControl
> xControl(pFormObject
? impl_getControl_Lock(xControlModel
, *pFormObject
) : Reference
<XControl
>());
2209 Reference
< XGrid
> xGrid(xControl
, UNO_QUERY
);
2210 DBG_ASSERT(xGrid
.is(), "FmXFormShell::OnFoundData : invalid control!");
2211 // if one of the asserts fires, I probably did something wrong on building of m_arrSearchedControls
2213 // enable a permanent cursor for the grid so we can see the found text
2214 Reference
< XPropertySet
> xModelSet(xControlModel
, UNO_QUERY
);
2215 DBG_ASSERT(xModelSet
.is(), "FmXFormShell::OnFoundData : invalid control model (no property set) !");
2216 xModelSet
->setPropertyValue( FM_PROP_ALWAYSSHOWCURSOR
, Any( true ) );
2217 xModelSet
->setPropertyValue( FM_PROP_CURSORCOLOR
, Any( COL_LIGHTRED
) );
2218 m_xLastGridFound
= std::move(xControlModel
);
2221 xGrid
->setCurrentColumnPosition(static_cast<sal_Int16
>(nGridColumn
));
2224 // As the cursor has been repositioned, I have (in positioned) invalidated
2225 // my form bar slots. But that does not take effect here unfortunately, as
2226 // generally the (modal) search dialog is of course at the top ... So, force ...
2227 sal_uInt16 nPos
= 0;
2228 while (DatabaseSlotMap
[nPos
])
2229 m_pShell
->GetViewShell()->GetViewFrame().GetBindings().Update(DatabaseSlotMap
[nPos
++]);
2230 // unfortunately the update goes against the invalidate with only individual slots
2233 IMPL_LINK(FmXFormShell
, OnCanceledNotFound_Lock
, FmFoundRecordInformation
&, rfriWhere
, void)
2235 if (impl_checkDisposed_Lock())
2238 DBG_ASSERT((rfriWhere
.nContext
>= 0) && (o3tl::make_unsigned(rfriWhere
.nContext
) < m_aSearchForms
.size()),
2239 "FmXFormShell::OnCanceledNotFound : invalid context!");
2240 Reference
< XForm
> xForm( m_aSearchForms
.at(rfriWhere
.nContext
));
2241 DBG_ASSERT(xForm
.is(), "FmXFormShell::OnCanceledNotFound : invalid form!");
2243 Reference
< XRowLocate
> xCursor(xForm
, UNO_QUERY
);
2245 return; // what should I do there?
2250 xCursor
->moveToBookmark(rfriWhere
.aPosition
);
2252 catch(const SQLException
&)
2254 OSL_FAIL("Can position on bookmark!");
2258 m_pShell
->GetFormView()->UnMarkAll(m_pShell
->GetFormView()->GetSdrPageView());
2262 IMPL_LINK(FmXFormShell
, OnSearchContextRequest_Lock
, FmSearchContext
&, rfmscContextInfo
, sal_uInt32
)
2264 if (impl_checkDisposed_Lock())
2267 DBG_ASSERT(rfmscContextInfo
.nContext
< static_cast<sal_Int16
>(m_aSearchForms
.size()), "FmXFormShell::OnSearchContextRequest : invalid parameter !");
2268 Reference
< XForm
> xForm( m_aSearchForms
.at(rfmscContextInfo
.nContext
));
2269 DBG_ASSERT(xForm
.is(), "FmXFormShell::OnSearchContextRequest : unexpected : invalid context !");
2271 Reference
< XResultSet
> xIter(xForm
, UNO_QUERY
);
2272 DBG_ASSERT(xIter
.is(), "FmXFormShell::OnSearchContextRequest : unexpected : context has no iterator !");
2275 // assemble the list of fields to involve (that is, the ControlSources of all fields that have such a property)
2276 OUString strFieldList
, sFieldDisplayNames
;
2277 m_arrSearchedControls
.clear();
2278 m_arrRelativeGridColumn
.clear();
2280 // small problem: To mark found fields, I need SdrObjects. To determine which controls
2281 // to include in the search, I need Controls (that is, XControl interfaces). So I have
2282 // to iterate over one of them and get the other in some way. Unfortunately, there is
2283 // no direct connection between the two worlds (except from a GetUnoControl to a
2284 // SdrUnoObject, but this requires an OutputDevice I can not do anything with.
2285 // However I can get to the Model from the Control and also from the SdrObject, and in
2286 // this way the assignment SdrObject<->Control is possible with a double loop.
2287 // The alternative to this (ugly but certainly not entirely fixable) solution would be
2288 // to renounce the caching of the SdrObjects, which would lead to significant extra
2289 // work in OnFoundData (since there I'd have to get the SdrObject first thing every
2290 // time). But since OnFoundData is usually called more often than ExecuteSearch, I'll
2293 Reference
< XNameAccess
> xValidFormFields
;
2294 Reference
< XColumnsSupplier
> xSupplyCols(xIter
, UNO_QUERY
);
2295 DBG_ASSERT(xSupplyCols
.is(), "FmXFormShell::OnSearchContextRequest : invalid cursor : no columns supplier !");
2296 if (xSupplyCols
.is())
2297 xValidFormFields
= xSupplyCols
->getColumns();
2298 DBG_ASSERT(xValidFormFields
.is(), "FmXFormShell::OnSearchContextRequest : form has no fields !");
2300 // current Page/Controller
2301 FmFormPage
* pCurrentPage
= m_pShell
->GetCurPage();
2302 assert(pCurrentPage
&& "FmXFormShell::OnSearchContextRequest : no page !");
2303 // Search all SdrControls of this page...
2304 OUString sControlSource
, aName
;
2306 SdrObjListIter
aPageIter( pCurrentPage
);
2307 while ( aPageIter
.IsMore() )
2309 SdrObject
* pCurrent
= aPageIter
.Next();
2310 FmFormObj
* pFormObject
= FmFormObj::GetFormObject( pCurrent
);
2311 // note that in case pCurrent is a virtual object, pFormObject points to the referenced object
2316 // the current object's model, in different tastes
2317 Reference
< XControlModel
> xControlModel( pFormObject
->GetUnoControlModel() );
2318 Reference
< XFormComponent
> xCurrentFormComponent( xControlModel
, UNO_QUERY
);
2319 DBG_ASSERT( xCurrentFormComponent
.is(), "FmXFormShell::OnSearchContextRequest: invalid objects!" );
2320 if ( !xCurrentFormComponent
.is() )
2323 // does the component belong to the form which we're interested in?
2324 if ( xCurrentFormComponent
->getParent() != xForm
)
2327 // ... ask for the ControlSource property
2328 SearchableControlIterator
iter( xCurrentFormComponent
);
2329 Reference
< XControl
> xControl
;
2330 // the control that has model xControlModel
2331 // (the following while can be passed through several times, without the Control
2332 // being modified, so I don't have to search every time from scratch)
2334 Reference
< XInterface
> xSearchable( iter
.Next() );
2335 while ( xSearchable
.is() )
2337 sControlSource
= iter
.getCurrentValue();
2338 if ( sControlSource
.isEmpty() )
2340 // the current element has no ControlSource, so it is a GridControl (that
2341 // is the only thing that still permits the SearchableControlIteratore)
2342 xControl
= impl_getControl_Lock(xControlModel
, *pFormObject
);
2343 DBG_ASSERT(xControl
.is(), "FmXFormShell::OnSearchContextRequest : didn't ::std::find a control with requested model !");
2345 Reference
< XGridPeer
> xGridPeer
;
2346 if ( xControl
.is() )
2347 xGridPeer
.set( xControl
->getPeer(), UNO_QUERY
);
2350 if (!xGridPeer
.is())
2353 Reference
< XIndexAccess
> xPeerContainer(xGridPeer
, UNO_QUERY
);
2354 if (!xPeerContainer
.is())
2357 Reference
< XIndexAccess
> xModelColumns
= xGridPeer
->getColumns();
2358 DBG_ASSERT(xModelColumns
.is(), "FmXFormShell::OnSearchContextRequest : there is a grid control without columns !");
2359 // the case 'no columns' should be indicated with an empty container, I think ...
2360 DBG_ASSERT(xModelColumns
->getCount() >= xPeerContainer
->getCount(), "FmXFormShell::OnSearchContextRequest : impossible : have more view than model columns !");
2362 Reference
< XInterface
> xCurrentColumn
;
2363 for (sal_Int32 nViewPos
=0; nViewPos
<xPeerContainer
->getCount(); ++nViewPos
)
2365 xPeerContainer
->getByIndex(nViewPos
) >>= xCurrentColumn
;
2366 if (!xCurrentColumn
.is())
2369 // can we use this column control for searching ?
2370 if (!IsSearchableControl(xCurrentColumn
))
2373 sal_Int32 nModelPos
= GridView2ModelPos(xModelColumns
, nViewPos
);
2374 Reference
< XPropertySet
> xCurrentColModel
;
2375 xModelColumns
->getByIndex(nModelPos
) >>= xCurrentColModel
;
2376 aName
= ::comphelper::getString(xCurrentColModel
->getPropertyValue(FM_PROP_CONTROLSOURCE
));
2377 // the cursor has a field matching the control source ?
2378 if (xValidFormFields
->hasByName(aName
))
2380 strFieldList
+= aName
+ ";";
2382 sFieldDisplayNames
+=
2383 ::comphelper::getString(xCurrentColModel
->getPropertyValue(FM_PROP_LABEL
)) +
2386 rfmscContextInfo
.arrFields
.push_back(xCurrentColumn
);
2388 // and the SdrOject to the Field
2389 m_arrSearchedControls
.push_back(pCurrent
);
2390 // the number of the column
2391 m_arrRelativeGridColumn
.push_back(nViewPos
);
2398 if (!sControlSource
.isEmpty() && xValidFormFields
->hasByName(sControlSource
))
2400 // now I need the Control to SdrObject
2403 xControl
= impl_getControl_Lock(xControlModel
, *pFormObject
);
2404 DBG_ASSERT(xControl
.is(), "FmXFormShell::OnSearchContextRequest : didn't ::std::find a control with requested model !");
2407 if (IsSearchableControl(xControl
))
2409 // all tests passed -> take along in the list
2410 strFieldList
+= sControlSource
+ ";";
2412 // the label which should appear for the control :
2413 sFieldDisplayNames
+=
2414 getLabelName(Reference
< XPropertySet
>(xControlModel
, UNO_QUERY
)) +
2417 // mark the SdrObject (accelerates the treatment in OnFoundData)
2418 m_arrSearchedControls
.push_back(pCurrent
);
2420 // the number of the column (here a dummy, since it is only interesting for GridControls)
2421 m_arrRelativeGridColumn
.push_back(-1);
2423 // and for the formatted search...
2424 rfmscContextInfo
.arrFields
.emplace_back( xControl
, UNO_QUERY
);
2429 xSearchable
= iter
.Next();
2433 strFieldList
= comphelper::string::stripEnd(strFieldList
, ';');
2434 sFieldDisplayNames
= comphelper::string::stripEnd(sFieldDisplayNames
, ';');
2436 if (rfmscContextInfo
.arrFields
.empty())
2438 rfmscContextInfo
.arrFields
.clear();
2439 rfmscContextInfo
.xCursor
= nullptr;
2440 rfmscContextInfo
.strUsedFields
.clear();
2444 rfmscContextInfo
.xCursor
= std::move(xIter
);
2445 rfmscContextInfo
.strUsedFields
= strFieldList
;
2446 rfmscContextInfo
.sFieldDisplayNames
= sFieldDisplayNames
;
2448 // 66463 - 31.05.99 - FS
2449 // when the cursor is a non-STANDARD RecordMode, set it back
2450 Reference
< XPropertySet
> xCursorSet(rfmscContextInfo
.xCursor
, UNO_QUERY
);
2451 Reference
< XResultSetUpdate
> xUpdateCursor(rfmscContextInfo
.xCursor
, UNO_QUERY
);
2452 if (xUpdateCursor
.is() && xCursorSet
.is())
2454 if (::comphelper::getBOOL(xCursorSet
->getPropertyValue(FM_PROP_ISNEW
)))
2455 xUpdateCursor
->moveToCurrentRow();
2456 else if (::comphelper::getBOOL(xCursorSet
->getPropertyValue(FM_PROP_ISMODIFIED
)))
2457 xUpdateCursor
->cancelRowUpdates();
2460 return rfmscContextInfo
.arrFields
.size();
2463 // XContainerListener
2465 void SAL_CALL
FmXFormShell::elementInserted(const ContainerEvent
& evt
)
2469 if (impl_checkDisposed_Lock())
2472 // new object to listen to
2473 Reference
< XInterface
> xTemp
;
2474 evt
.Element
>>= xTemp
;
2475 AddElement_Lock(xTemp
);
2477 m_pShell
->DetermineForms(true);
2481 void SAL_CALL
FmXFormShell::elementReplaced(const ContainerEvent
& evt
)
2485 if (impl_checkDisposed_Lock() )
2488 Reference
< XInterface
> xTemp
;
2489 evt
.ReplacedElement
>>= xTemp
;
2490 RemoveElement_Lock(xTemp
);
2491 evt
.Element
>>= xTemp
;
2492 AddElement_Lock(xTemp
);
2496 void SAL_CALL
FmXFormShell::elementRemoved(const ContainerEvent
& evt
)
2500 if (impl_checkDisposed_Lock())
2503 Reference
< XInterface
> xTemp
;
2504 evt
.Element
>>= xTemp
;
2505 RemoveElement_Lock(xTemp
);
2507 m_pShell
->DetermineForms(true);
2511 void FmXFormShell::UpdateForms_Lock(bool _bInvalidate
)
2513 if (impl_checkDisposed_Lock())
2516 Reference
< XIndexAccess
> xForms
;
2518 FmFormPage
* pPage
= m_pShell
->GetCurPage();
2519 if ( pPage
&& m_pShell
->m_bDesignMode
)
2520 xForms
= pPage
->GetForms( false );
2522 if ( m_xForms
!= xForms
)
2524 RemoveElement_Lock( m_xForms
);
2525 m_xForms
= std::move(xForms
);
2526 AddElement_Lock(m_xForms
);
2530 m_pShell
->DetermineForms( _bInvalidate
);
2534 void FmXFormShell::AddElement_Lock(const Reference
<XInterface
>& _xElement
)
2536 if (impl_checkDisposed_Lock())
2538 impl_AddElement_nothrow(_xElement
);
2541 void FmXFormShell::impl_AddElement_nothrow(const Reference
< XInterface
>& Element
)
2543 // listen at the container
2544 const Reference
< XIndexContainer
> xContainer(Element
, UNO_QUERY
);
2545 if (xContainer
.is())
2547 const sal_uInt32 nCount
= xContainer
->getCount();
2548 Reference
< XInterface
> xElement
;
2549 for (sal_uInt32 i
= 0; i
< nCount
; ++i
)
2551 xElement
.set(xContainer
->getByIndex(i
),UNO_QUERY
);
2552 impl_AddElement_nothrow(xElement
);
2555 const Reference
< XContainer
> xCont(Element
, UNO_QUERY
);
2557 xCont
->addContainerListener(this);
2560 const Reference
< css::view::XSelectionSupplier
> xSelSupplier(Element
, UNO_QUERY
);
2561 if (xSelSupplier
.is())
2562 xSelSupplier
->addSelectionChangeListener(this);
2566 void FmXFormShell::RemoveElement_Lock(const Reference
<XInterface
>& Element
)
2568 if (impl_checkDisposed_Lock())
2570 impl_RemoveElement_nothrow_Lock(Element
);
2573 void FmXFormShell::impl_RemoveElement_nothrow_Lock(const Reference
<XInterface
>& Element
)
2575 const Reference
< css::view::XSelectionSupplier
> xSelSupplier(Element
, UNO_QUERY
);
2576 if (xSelSupplier
.is())
2577 xSelSupplier
->removeSelectionChangeListener(this);
2579 // remove connection to children
2580 const Reference
< XIndexContainer
> xContainer(Element
, UNO_QUERY
);
2581 if (xContainer
.is())
2583 const Reference
< XContainer
> xCont(Element
, UNO_QUERY
);
2585 xCont
->removeContainerListener(this);
2587 const sal_uInt32 nCount
= xContainer
->getCount();
2588 Reference
< XInterface
> xElement
;
2589 for (sal_uInt32 i
= 0; i
< nCount
; i
++)
2591 xElement
.set(xContainer
->getByIndex(i
),UNO_QUERY
);
2592 impl_RemoveElement_nothrow_Lock(xElement
);
2596 auto wasSelectedPos
= m_aCurrentSelection
.find( Element
);
2597 if ( wasSelectedPos
!= m_aCurrentSelection
.end() )
2598 m_aCurrentSelection
.erase( wasSelectedPos
);
2602 void SAL_CALL
FmXFormShell::selectionChanged(const lang::EventObject
& rEvent
)
2606 if (impl_checkDisposed_Lock())
2609 Reference
< XSelectionSupplier
> xSupplier( rEvent
.Source
, UNO_QUERY
);
2610 Reference
< XInterface
> xSelObj( xSupplier
->getSelection(), UNO_QUERY
);
2611 // a selection was removed, this can only be done by the shell
2612 if ( !xSelObj
.is() )
2615 EnableTrackProperties_Lock(false);
2617 bool bMarkChanged
= m_pShell
->GetFormView()->checkUnMarkAll(rEvent
.Source
);
2619 InterfaceBag aNewSelection
;
2620 aNewSelection
.insert( Reference
<XInterface
>( xSelObj
, UNO_QUERY
) );
2622 if (setCurrentSelection_Lock(std::move(aNewSelection
)) && IsPropBrwOpen_Lock())
2623 ShowSelectionProperties_Lock(true);
2625 EnableTrackProperties_Lock(true);
2628 m_pShell
->NotifyMarkListChanged( m_pShell
->GetFormView() );
2632 IMPL_LINK_NOARG(FmXFormShell
, OnTimeOut_Lock
, Timer
*, void)
2634 if (impl_checkDisposed_Lock())
2637 if (m_pShell
->IsDesignMode() && m_pShell
->GetFormView())
2638 SetSelection_Lock(m_pShell
->GetFormView()->GetMarkedObjectList());
2642 void FmXFormShell::SetSelectionDelayed_Lock()
2644 if (impl_checkDisposed_Lock())
2647 if (m_pShell
->IsDesignMode() && IsTrackPropertiesEnabled_Lock() && !m_aMarkTimer
.IsActive())
2648 m_aMarkTimer
.Start();
2652 void FmXFormShell::SetSelection_Lock(const SdrMarkList
& rMarkList
)
2654 if (impl_checkDisposed_Lock())
2657 DetermineSelection_Lock(rMarkList
);
2658 m_pShell
->NotifyMarkListChanged(m_pShell
->GetFormView());
2661 void FmXFormShell::DetermineSelection_Lock(const SdrMarkList
& rMarkList
)
2663 if (setCurrentSelectionFromMark_Lock(rMarkList
) && IsPropBrwOpen_Lock())
2664 ShowSelectionProperties_Lock(true);
2667 bool FmXFormShell::IsPropBrwOpen_Lock() const
2669 if (impl_checkDisposed_Lock())
2672 return m_pShell
->GetViewShell() &&
2673 m_pShell
->GetViewShell()->GetViewFrame().HasChildWindow(SID_FM_SHOW_PROPERTIES
);
2676 class FmXFormShell::SuspendPropertyTracking
2679 FmXFormShell
& m_rShell
;
2683 explicit SuspendPropertyTracking( FmXFormShell
& _rShell
)
2684 :m_rShell( _rShell
)
2685 ,m_bEnabled( false )
2687 if (m_rShell
.IsTrackPropertiesEnabled_Lock())
2689 m_rShell
.EnableTrackProperties_Lock(false);
2694 ~SuspendPropertyTracking( )
2696 if ( m_bEnabled
) // note that ( false != m_bEnabled ) implies ( NULL != m_pShell )
2697 m_rShell
.EnableTrackProperties_Lock(true);
2701 void FmXFormShell::SetDesignMode_Lock(bool bDesign
)
2703 if (impl_checkDisposed_Lock())
2706 DBG_ASSERT(m_pShell
->GetFormView(), "FmXFormShell::SetDesignMode : invalid call (have no shell or no view) !");
2707 m_bChangingDesignMode
= true;
2709 // 67506 - 15.07.99 - FS
2710 // if we're switching off the design mode we have to force the property browser to be closed
2711 // so it can commit it's changes _before_ we load the forms
2714 m_bHadPropertyBrowserInDesignMode
= m_pShell
->GetViewShell()->GetViewFrame().HasChildWindow(SID_FM_SHOW_PROPERTIES
);
2715 if (m_bHadPropertyBrowserInDesignMode
)
2716 m_pShell
->GetViewShell()->GetViewFrame().ToggleChildWindow(SID_FM_SHOW_PROPERTIES
);
2719 FmFormView
* pFormView
= m_pShell
->GetFormView();
2722 // we are currently filtering, so stop filtering
2724 stopFiltering_Lock(false);
2726 // unsubscribe from the objects of my MarkList
2727 pFormView
->GetImpl()->stopMarkListWatching();
2731 m_aMarkTimer
.Stop();
2733 SuspendPropertyTracking
aSuspend( *this );
2734 pFormView
->GetImpl()->saveMarkList();
2737 if (bDesign
&& m_xExternalViewController
.is())
2738 CloseExternalFormViewer_Lock();
2740 pFormView
->ChangeDesignMode(bDesign
);
2743 FmDesignModeChangedHint
aChangedHint( bDesign
);
2744 m_pShell
->Broadcast(aChangedHint
);
2746 m_pShell
->m_bDesignMode
= bDesign
;
2747 UpdateForms_Lock(false);
2749 m_pTextShell
->designModeChanged();
2755 // during changing the mark list, don't track the selected objects in the property browser
2756 SuspendPropertyTracking
aSuspend( *this );
2757 // restore the marks
2758 pFormView
->GetImpl()->restoreMarkList( aList
);
2761 // synchronize with the restored mark list
2762 if ( aList
.GetMarkCount() )
2763 SetSelection_Lock(aList
);
2767 // subscribe to the model of the view (so that I'm informed when someone deletes
2768 // during the alive mode controls that I had saved in the saveMarklist (60343)
2769 pFormView
->GetImpl()->startMarkListWatching();
2772 m_pShell
->UIFeatureChanged();
2774 // 67506 - 15.07.99 - FS
2775 if (bDesign
&& m_bHadPropertyBrowserInDesignMode
)
2777 // The UIFeatureChanged performs an update (a check of the available features) asynchronously.
2778 // So we can't call ShowSelectionProperties directly as the according feature isn't enabled yet.
2779 // That's why we use an asynchron execution on the dispatcher.
2780 // (And that's why this has to be done AFTER the UIFeatureChanged.)
2781 m_pShell
->GetViewShell()->GetViewFrame().GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER
, SfxCallMode::ASYNCHRON
);
2783 m_bChangingDesignMode
= false;
2786 Reference
< XControl
> FmXFormShell::impl_getControl_Lock(const Reference
<XControlModel
>& i_rxModel
, const FmFormObj
& i_rKnownFormObj
)
2788 if (impl_checkDisposed_Lock())
2791 Reference
< XControl
> xControl
;
2794 Reference
< XControlContainer
> xControlContainer(getControlContainerForView_Lock(), UNO_SET_THROW
);
2796 const Sequence
< Reference
< XControl
> > seqControls( xControlContainer
->getControls() );
2797 // ... that I can then search
2798 for (Reference
< XControl
> const & control
: seqControls
)
2800 xControl
.set( control
, UNO_SET_THROW
);
2801 Reference
< XControlModel
> xCurrentModel( xControl
->getModel() );
2802 if ( xCurrentModel
== i_rxModel
)
2807 if ( !xControl
.is() )
2809 // fallback (some controls might not have been created, yet, since they were never visible so far)
2810 Reference
< XControl
> xContainerControl( xControlContainer
, UNO_QUERY_THROW
);
2811 const vcl::Window
* pContainerWindow
= VCLUnoHelper::GetWindow( xContainerControl
->getPeer() );
2812 ENSURE_OR_THROW( pContainerWindow
, "unexpected control container implementation" );
2814 const SdrView
* pSdrView
= m_pShell
? m_pShell
->GetFormView() : nullptr;
2815 ENSURE_OR_THROW( pSdrView
, "no current view" );
2817 xControl
.set( i_rKnownFormObj
.GetUnoControl( *pSdrView
, *pContainerWindow
->GetOutDev() ), UNO_SET_THROW
);
2820 catch( const Exception
& )
2822 DBG_UNHANDLED_EXCEPTION("svx");
2825 OSL_ENSURE( xControl
.is(), "FmXFormShell::impl_getControl: no control found!" );
2829 // note: _out_rForms is a member so needs lock
2830 void FmXFormShell::impl_collectFormSearchContexts_nothrow_Lock( const Reference
<XInterface
>& _rxStartingPoint
,
2831 std::u16string_view _rCurrentLevelPrefix
, FmFormArray
& _out_rForms
, ::std::vector
< OUString
>& _out_rNames
)
2835 Reference
< XIndexAccess
> xContainer( _rxStartingPoint
, UNO_QUERY
);
2836 if ( !xContainer
.is() )
2839 sal_Int32
nCount( xContainer
->getCount() );
2843 OUString sCurrentFormName
;
2844 OUStringBuffer aNextLevelPrefix
;
2845 for ( sal_Int32 i
=0; i
<nCount
; ++i
)
2847 // is the current child a form?
2848 Reference
< XForm
> xCurrentAsForm( xContainer
->getByIndex(i
), UNO_QUERY
);
2849 if ( !xCurrentAsForm
.is() )
2852 Reference
< XNamed
> xNamed( xCurrentAsForm
, UNO_QUERY_THROW
);
2853 sCurrentFormName
= xNamed
->getName();
2855 // the name of the current form
2856 OUString
sCompleteCurrentName( sCurrentFormName
);
2857 if ( !_rCurrentLevelPrefix
.empty() )
2859 sCompleteCurrentName
+= OUString::Concat(" (") + _rCurrentLevelPrefix
+ ")";
2862 // the prefix for the next level
2863 aNextLevelPrefix
= _rCurrentLevelPrefix
;
2864 if ( !_rCurrentLevelPrefix
.empty() )
2865 aNextLevelPrefix
.append( '/' );
2866 aNextLevelPrefix
.append( sCurrentFormName
);
2868 // remember both the form and its "display name"
2869 _out_rForms
.push_back( xCurrentAsForm
);
2870 _out_rNames
.push_back( sCompleteCurrentName
);
2873 impl_collectFormSearchContexts_nothrow_Lock(
2874 xCurrentAsForm
, aNextLevelPrefix
,
2875 _out_rForms
, _out_rNames
);
2876 aNextLevelPrefix
.setLength(0);
2879 catch( const Exception
& )
2881 DBG_UNHANDLED_EXCEPTION("svx");
2885 void FmXFormShell::startFiltering_Lock()
2887 if (impl_checkDisposed_Lock())
2890 // setting all forms in filter mode
2891 FmXFormView
* pXView
= m_pShell
->GetFormView()->GetImpl();
2893 // if the active controller is our external one we have to use the trigger controller
2894 Reference
< XControlContainer
> xContainer
;
2895 if (getActiveController_Lock() == m_xExternalViewController
)
2897 DBG_ASSERT(m_xExtViewTriggerController
.is(), "FmXFormShell::startFiltering : inconsistent : active external controller, but no one triggered this !");
2898 xContainer
= m_xExtViewTriggerController
->getContainer();
2901 xContainer
= getActiveController_Lock()->getContainer();
2903 rtl::Reference
< FormViewPageWindowAdapter
> pAdapter
= pXView
->findWindow( xContainer
);
2904 if ( pAdapter
.is() )
2906 const ::std::vector
< Reference
< runtime::XFormController
> >& rControllerList
= pAdapter
->GetList();
2907 for (const auto& rpController
: rControllerList
)
2909 Reference
< XModeSelector
> xModeSelector(rpController
, UNO_QUERY
);
2910 if (xModeSelector
.is())
2911 xModeSelector
->setMode( u
"FilterMode"_ustr
);
2915 m_bFilterMode
= true;
2917 m_pShell
->UIFeatureChanged();
2918 SfxViewFrame
& rViewFrame
= m_pShell
->GetViewShell()->GetViewFrame();
2919 rViewFrame
.GetBindings().InvalidateShell( *m_pShell
);
2921 if ( rViewFrame
.KnowsChildWindow( SID_FM_FILTER_NAVIGATOR
)
2922 && !rViewFrame
.HasChildWindow( SID_FM_FILTER_NAVIGATOR
)
2925 rViewFrame
.ToggleChildWindow( SID_FM_FILTER_NAVIGATOR
);
2929 static void saveFilter(const Reference
< runtime::XFormController
>& _rxController
)
2931 Reference
< XPropertySet
> xFormAsSet(_rxController
->getModel(), UNO_QUERY
);
2932 Reference
< XPropertySet
> xControllerAsSet(_rxController
, UNO_QUERY
);
2934 // call the subcontroller
2935 Reference
< runtime::XFormController
> xController
;
2936 for (sal_Int32 i
= 0, nCount
= _rxController
->getCount(); i
< nCount
; ++i
)
2938 _rxController
->getByIndex(i
) >>= xController
;
2939 saveFilter(xController
);
2945 xFormAsSet
->setPropertyValue(FM_PROP_FILTER
, xControllerAsSet
->getPropertyValue(FM_PROP_FILTER
));
2946 xFormAsSet
->setPropertyValue(FM_PROP_APPLYFILTER
, Any( true ) );
2948 catch (const Exception
& )
2950 DBG_UNHANDLED_EXCEPTION("svx");
2956 void FmXFormShell::stopFiltering_Lock(bool bSave
)
2958 if (impl_checkDisposed_Lock())
2961 m_bFilterMode
= false;
2963 FmXFormView
* pXView
= m_pShell
->GetFormView()->GetImpl();
2965 // if the active controller is our external one we have to use the trigger controller
2966 Reference
< XControlContainer
> xContainer
;
2967 if (getActiveController_Lock() == m_xExternalViewController
)
2969 DBG_ASSERT(m_xExtViewTriggerController
.is(), "FmXFormShell::stopFiltering : inconsistent : active external controller, but no one triggered this !");
2970 xContainer
= m_xExtViewTriggerController
->getContainer();
2973 xContainer
= getActiveController_Lock()->getContainer();
2975 rtl::Reference
< FormViewPageWindowAdapter
> pAdapter
= pXView
->findWindow(xContainer
);
2976 if ( pAdapter
.is() )
2978 const ::std::vector
< Reference
< runtime::XFormController
> >& rControllerList
= pAdapter
->GetList();
2979 ::std::vector
< OUString
> aOriginalFilters
;
2980 ::std::vector
< bool > aOriginalApplyFlags
;
2984 for (const auto& rpController
: rControllerList
)
2986 // remember the current filter settings in case we're going to reload the forms below (which may fail)
2989 Reference
< XPropertySet
> xFormAsSet(rpController
->getModel(), UNO_QUERY
);
2990 aOriginalFilters
.push_back(::comphelper::getString(xFormAsSet
->getPropertyValue(FM_PROP_FILTER
)));
2991 aOriginalApplyFlags
.push_back(::comphelper::getBOOL(xFormAsSet
->getPropertyValue(FM_PROP_APPLYFILTER
)));
2995 OSL_FAIL("FmXFormShell::stopFiltering : could not get the original filter !");
2996 // put dummies into the arrays so the they have the right size
2998 if (aOriginalFilters
.size() == aOriginalApplyFlags
.size())
2999 // the first getPropertyValue failed -> use two dummies
3000 aOriginalFilters
.emplace_back( );
3001 aOriginalApplyFlags
.push_back( false );
3003 saveFilter(rpController
);
3006 for (const auto& rController
: rControllerList
)
3009 Reference
< XModeSelector
> xModeSelector(rController
, UNO_QUERY
);
3010 if (xModeSelector
.is())
3011 xModeSelector
->setMode( u
"DataMode"_ustr
);
3013 if (bSave
) // execute the filter
3015 const ::std::vector
< Reference
< runtime::XFormController
> > & rControllers
= pAdapter
->GetList();
3016 for (::std::vector
< Reference
< runtime::XFormController
> > ::const_iterator j
= rControllers
.begin();
3017 j
!= rControllers
.end(); ++j
)
3019 Reference
< XLoadable
> xReload((*j
)->getModel(), UNO_QUERY
);
3022 Reference
< XPropertySet
> xFormSet(xReload
, UNO_QUERY
);
3030 TOOLS_WARN_EXCEPTION("svx.form", "");
3033 if (!isRowSetAlive(xFormSet
))
3034 { // something went wrong -> restore the original state
3035 OUString sOriginalFilter
= aOriginalFilters
[ j
- rControllers
.begin() ];
3036 bool bOriginalApplyFlag
= aOriginalApplyFlags
[ j
- rControllers
.begin() ];
3039 xFormSet
->setPropertyValue(FM_PROP_FILTER
, Any(sOriginalFilter
));
3040 xFormSet
->setPropertyValue(FM_PROP_APPLYFILTER
, Any(bOriginalApplyFlag
));
3043 catch(const Exception
&)
3045 DBG_UNHANDLED_EXCEPTION("svx");
3052 m_pShell
->UIFeatureChanged();
3053 m_pShell
->GetViewShell()->GetViewFrame().GetBindings().InvalidateShell(*m_pShell
);
3057 void FmXFormShell::CreateExternalView_Lock()
3059 if (impl_checkDisposed_Lock())
3062 DBG_ASSERT(m_xAttachedFrame
.is(), "FmXFormShell::CreateExternalView : no frame !");
3064 // the frame the external view is displayed in
3065 bool bAlreadyExistent
= m_xExternalViewController
.is();
3066 Reference
< css::frame::XFrame
> xExternalViewFrame
;
3068 Reference
<runtime::XFormController
> xCurrentNavController(getNavController_Lock());
3069 // the creation of the "partwindow" may cause a deactivate of the document which will result in our nav controller to be set to NULL
3071 // _first_ check if we have any valid fields we can use for the grid view
3072 // FS - 21.10.99 - 69219
3074 FmXBoundFormFieldIterator
aModelIterator(xCurrentNavController
->getModel());
3075 bool bHaveUsableControls
= false;
3078 Reference
< XPropertySet
> xCurrentModelSet(aModelIterator
.Next(), UNO_QUERY
);
3079 if (!xCurrentModelSet
.is())
3081 // the FmXBoundFormFieldIterator only supplies controls with a valid control source
3082 // so we just have to check the field type
3083 sal_Int16 nClassId
= ::comphelper::getINT16(xCurrentModelSet
->getPropertyValue(FM_PROP_CLASSID
));
3086 case FormComponentType::IMAGECONTROL
:
3087 case FormComponentType::CONTROL
:
3090 bHaveUsableControls
= true;
3094 if (!bHaveUsableControls
)
3096 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(nullptr,
3097 VclMessageType::Warning
, VclButtonsType::Ok
,
3098 SvxResId(RID_STR_NOCONTROLS_FOR_EXTERNALDISPLAY
)));
3104 // load the component for external form views
3105 if (!bAlreadyExistent
)
3107 OUString
sFrameName(u
"_beamer"_ustr
);
3108 URL aWantToDispatch
;
3109 aWantToDispatch
.Complete
= FMURL_COMPONENT_FORMGRIDVIEW
;
3111 Reference
< css::frame::XDispatchProvider
> xProv(m_xAttachedFrame
, UNO_QUERY
);
3112 Reference
< css::frame::XDispatch
> xDisp
;
3114 xDisp
= xProv
->queryDispatch(aWantToDispatch
, sFrameName
,
3115 css::frame::FrameSearchFlag::CHILDREN
| css::frame::FrameSearchFlag::CREATE
);
3118 xDisp
->dispatch(aWantToDispatch
, Sequence
< PropertyValue
>());
3121 // with this the component should be loaded, now search the frame where it resides in
3122 xExternalViewFrame
= m_xAttachedFrame
->findFrame(sFrameName
, css::frame::FrameSearchFlag::CHILDREN
);
3123 if (xExternalViewFrame
.is())
3125 m_xExternalViewController
= xExternalViewFrame
->getController();
3126 if (m_xExternalViewController
.is())
3127 m_xExternalViewController
->addEventListener(static_cast<XEventListener
*>(static_cast<XPropertyChangeListener
*>(this)));
3132 xExternalViewFrame
= m_xExternalViewController
->getFrame();
3133 Reference
< css::frame::XDispatchProvider
> xCommLink(xExternalViewFrame
, UNO_QUERY
);
3135 // if we display the active form we interpret the slot as "remove it"
3136 Reference
< XForm
> xCurrentModel(xCurrentNavController
->getModel(), UNO_QUERY
);
3137 if ((xCurrentModel
== m_xExternalDisplayedForm
) || (getInternalForm_Lock(xCurrentModel
) == m_xExternalDisplayedForm
))
3139 if (m_xExternalViewController
== getActiveController_Lock())
3141 Reference
< runtime::XFormController
> xAsFormController( m_xExternalViewController
, UNO_QUERY
);
3142 ControllerFeatures
aHelper( xAsFormController
);
3143 (void)aHelper
->commitCurrentControl();
3146 Reference
< runtime::XFormController
> xNewController(m_xExtViewTriggerController
);
3147 CloseExternalFormViewer_Lock();
3148 setActiveController_Lock(xNewController
);
3153 aClearURL
.Complete
= FMURL_GRIDVIEW_CLEARVIEW
;
3155 Reference
< css::frame::XDispatch
> xClear( xCommLink
->queryDispatch(aClearURL
, OUString(), 0));
3157 xClear
->dispatch(aClearURL
, Sequence
< PropertyValue
>());
3160 // TODO: We need an interceptor at the xSupplier, which forwards all queryDispatch requests to the FormController
3161 // instance for which this "external view" was triggered
3163 // get the dispatch interface of the frame so we can communicate (interceptable) with the controller
3164 Reference
< css::frame::XDispatchProvider
> xCommLink(xExternalViewFrame
, UNO_QUERY
);
3166 if (m_xExternalViewController
.is())
3168 DBG_ASSERT(xCommLink
.is(), "FmXFormShell::CreateExternalView : the component doesn't have the necessary interfaces !");
3169 // collect the dispatchers we will need
3171 aAddColumnURL
.Complete
= FMURL_GRIDVIEW_ADDCOLUMN
;
3172 Reference
< css::frame::XDispatch
> xAddColumnDispatch( xCommLink
->queryDispatch(aAddColumnURL
, OUString(), 0));
3174 aAttachURL
.Complete
= FMURL_GRIDVIEW_ATTACHTOFORM
;
3175 Reference
< css::frame::XDispatch
> xAttachDispatch( xCommLink
->queryDispatch(aAttachURL
, OUString(), 0));
3177 if (xAddColumnDispatch
.is() && xAttachDispatch
.is())
3179 DBG_ASSERT(xCurrentNavController
.is(), "FmXFormShell::CreateExternalView : invalid call : have no nav controller !");
3180 // first : dispatch the descriptions for the columns to add
3181 sal_Int16 nAddedColumns
= 0;
3183 // for radio buttons we need some special structures
3184 typedef std::map
< OUString
, Sequence
< OUString
> > MapUString2UstringSeq
;
3185 typedef std::map
< OUString
, OUString
> FmMapUString2UString
;
3186 typedef std::map
< OUString
, sal_Int16
> FmMapUString2Int16
;
3188 MapUString2UstringSeq aRadioValueLists
;
3189 MapUString2UstringSeq aRadioListSources
;
3190 FmMapUString2UString aRadioControlSources
;
3191 FmMapUString2Int16 aRadioPositions
;
3193 FmXBoundFormFieldIterator
aModelIterator(xCurrentNavController
->getModel());
3194 OUString sColumnType
,aGroupName
,sControlSource
;
3195 Sequence
< Property
> aProps
;
3198 Reference
< XPropertySet
> xCurrentModelSet(aModelIterator
.Next(), UNO_QUERY
);
3199 if (!xCurrentModelSet
.is())
3201 OSL_ENSURE(xCurrentModelSet
.is(),"xCurrentModelSet is null!");
3202 // create a description of the column to be created
3203 // first : determine it's type
3205 sal_Int16 nClassId
= ::comphelper::getINT16(xCurrentModelSet
->getPropertyValue(FM_PROP_CLASSID
));
3208 case FormComponentType::RADIOBUTTON
:
3210 // get the label of the button (this is the access key for our structures)
3211 aGroupName
= getLabelName(xCurrentModelSet
);
3213 // add the reference value of the radio button to the list source sequence
3214 Sequence
< OUString
>& aThisGroupLabels
= aRadioListSources
[aGroupName
];
3215 sal_Int32 nNewSizeL
= aThisGroupLabels
.getLength() + 1;
3216 aThisGroupLabels
.realloc(nNewSizeL
);
3217 aThisGroupLabels
.getArray()[nNewSizeL
- 1] = ::comphelper::getString(xCurrentModelSet
->getPropertyValue(FM_PROP_REFVALUE
));
3219 // add the label to the value list sequence
3220 Sequence
< OUString
>& aThisGroupControlSources
= aRadioValueLists
[aGroupName
];
3221 sal_Int32 nNewSizeC
= aThisGroupControlSources
.getLength() + 1;
3222 aThisGroupControlSources
.realloc(nNewSizeC
);
3223 aThisGroupControlSources
.getArray()[nNewSizeC
- 1] = ::comphelper::getString(xCurrentModelSet
->getPropertyValue(FM_PROP_LABEL
));
3225 // remember the controls source of the radio group
3226 sControlSource
= ::comphelper::getString(xCurrentModelSet
->getPropertyValue(FM_PROP_CONTROLSOURCE
));
3227 if (aRadioControlSources
.find(aGroupName
) == aRadioControlSources
.end())
3228 aRadioControlSources
[aGroupName
] = sControlSource
;
3231 DBG_ASSERT(aRadioControlSources
[aGroupName
] == sControlSource
,
3232 "FmXFormShell::CreateExternalView : inconsistent radio buttons detected !");
3233 // (radio buttons with the same name should have the same control source)
3235 // remember the position within the columns
3236 if (aRadioPositions
.find(aGroupName
) == aRadioPositions
.end())
3237 aRadioPositions
[aGroupName
] = nAddedColumns
;
3239 // any further handling is done below
3243 case FormComponentType::IMAGECONTROL
:
3244 case FormComponentType::CONTROL
:
3245 // no grid columns for these types (though they have a control source)
3247 case FormComponentType::CHECKBOX
:
3248 sColumnType
= FM_COL_CHECKBOX
; break;
3249 case FormComponentType::LISTBOX
:
3250 sColumnType
= FM_COL_LISTBOX
; break;
3251 case FormComponentType::COMBOBOX
:
3252 sColumnType
= FM_COL_COMBOBOX
; break;
3253 case FormComponentType::DATEFIELD
:
3254 sColumnType
= FM_COL_DATEFIELD
; break;
3255 case FormComponentType::TIMEFIELD
:
3256 sColumnType
= FM_COL_TIMEFIELD
; break;
3257 case FormComponentType::NUMERICFIELD
:
3258 sColumnType
= FM_COL_NUMERICFIELD
; break;
3259 case FormComponentType::CURRENCYFIELD
:
3260 sColumnType
= FM_COL_CURRENCYFIELD
; break;
3261 case FormComponentType::PATTERNFIELD
:
3262 sColumnType
= FM_COL_PATTERNFIELD
; break;
3264 case FormComponentType::TEXTFIELD
:
3266 sColumnType
= FM_COL_TEXTFIELD
;
3267 // we know at least two different controls which are TextFields : the basic edit field and the formatted
3268 // field. we distinguish them by their service name
3269 Reference
< lang::XServiceInfo
> xInfo(xCurrentModelSet
, UNO_QUERY
);
3272 SdrObjKind nObjectType
= getControlTypeByObject(xInfo
);
3273 if (SdrObjKind::FormFormattedField
== nObjectType
)
3274 sColumnType
= FM_COL_FORMATTEDFIELD
;
3279 sColumnType
= FM_COL_TEXTFIELD
; break;
3282 const sal_Int16 nDispatchArgs
= 3;
3283 Sequence
< PropertyValue
> aDispatchArgs(nDispatchArgs
);
3284 PropertyValue
* pDispatchArgs
= aDispatchArgs
.getArray();
3286 // properties describing "meta data" about the column
3288 pDispatchArgs
->Name
= FMARG_ADDCOL_COLUMNTYPE
;
3289 pDispatchArgs
->Value
<<= sColumnType
;
3292 // the pos : append the col
3293 pDispatchArgs
->Name
= FMARG_ADDCOL_COLUMNPOS
;
3294 pDispatchArgs
->Value
<<= nAddedColumns
;
3297 // the properties to forward to the new column
3298 Sequence
< PropertyValue
> aColumnProps(1);
3299 PropertyValue
* pColumnProps
= aColumnProps
.getArray();
3302 pColumnProps
->Name
= FM_PROP_LABEL
;
3303 pColumnProps
->Value
<<= getLabelName(xCurrentModelSet
);
3306 // for all other props : transfer them
3307 Reference
< XPropertySetInfo
> xControlModelInfo( xCurrentModelSet
->getPropertySetInfo());
3308 DBG_ASSERT(xControlModelInfo
.is(), "FmXFormShell::CreateExternalView : the control model has no property info ! This will crash !");
3309 aProps
= xControlModelInfo
->getProperties();
3311 // realloc the control description sequence
3312 sal_Int32 nExistentDescs
= pColumnProps
- aColumnProps
.getArray();
3313 aColumnProps
.realloc(nExistentDescs
+ aProps
.getLength());
3314 pColumnProps
= aColumnProps
.getArray() + nExistentDescs
;
3316 for (const Property
& rProp
: aProps
)
3318 if (rProp
.Name
== FM_PROP_LABEL
)
3321 if (rProp
.Name
== FM_PROP_DEFAULTCONTROL
)
3322 // allow the column's own "default control"
3324 if (rProp
.Attributes
& PropertyAttribute::READONLY
)
3325 // assume that properties which are readonly for the control are ro for the column to be created, too
3328 pColumnProps
->Name
= rProp
.Name
;
3329 pColumnProps
->Value
= xCurrentModelSet
->getPropertyValue(rProp
.Name
);
3332 aColumnProps
.realloc(pColumnProps
- aColumnProps
.getArray());
3334 // columns props are a dispatch argument
3335 pDispatchArgs
->Name
= "ColumnProperties"; // TODO : fmurl.*
3336 pDispatchArgs
->Value
<<= aColumnProps
;
3338 DBG_ASSERT(nDispatchArgs
== (pDispatchArgs
- aDispatchArgs
.getConstArray()),
3339 "FmXFormShell::CreateExternalView : forgot to adjust nDispatchArgs ?");
3341 // dispatch the "add column"
3342 xAddColumnDispatch
->dispatch(aAddColumnURL
, aDispatchArgs
);
3346 // now for the radio button handling
3347 sal_Int16
nOffset(0);
3348 // properties describing the "direct" column properties
3349 const sal_Int16 nListBoxDescription
= 6;
3350 Sequence
< PropertyValue
> aListBoxDescription(nListBoxDescription
);
3351 for (const auto& rCtrlSource
: aRadioControlSources
)
3353 PropertyValue
* pListBoxDescription
= aListBoxDescription
.getArray();
3355 pListBoxDescription
->Name
= FM_PROP_LABEL
;
3356 pListBoxDescription
->Value
<<= rCtrlSource
.first
;
3357 ++pListBoxDescription
;
3360 pListBoxDescription
->Name
= FM_PROP_CONTROLSOURCE
;
3361 pListBoxDescription
->Value
<<= rCtrlSource
.second
;
3362 ++pListBoxDescription
;
3365 pListBoxDescription
->Name
= FM_PROP_BOUNDCOLUMN
;
3366 pListBoxDescription
->Value
<<= sal_Int16(1);
3367 ++pListBoxDescription
;
3370 pListBoxDescription
->Name
= FM_PROP_LISTSOURCETYPE
;
3371 pListBoxDescription
->Value
<<= ListSourceType_VALUELIST
;
3372 ++pListBoxDescription
;
3375 MapUString2UstringSeq::const_iterator aCurrentListSource
= aRadioListSources
.find(rCtrlSource
.first
);
3376 assert(aCurrentListSource
!= aRadioListSources
.end() &&
3377 "FmXFormShell::CreateExternalView : inconsistent radio descriptions !");
3378 pListBoxDescription
->Name
= FM_PROP_LISTSOURCE
;
3379 pListBoxDescription
->Value
<<= (*aCurrentListSource
).second
;
3380 ++pListBoxDescription
;
3383 MapUString2UstringSeq::const_iterator aCurrentValueList
= aRadioValueLists
.find(rCtrlSource
.first
);
3384 assert(aCurrentValueList
!= aRadioValueLists
.end() && "FmXFormShell::CreateExternalView : inconsistent radio descriptions !");
3385 pListBoxDescription
->Name
= FM_PROP_STRINGITEMLIST
;
3386 pListBoxDescription
->Value
<<= (*aCurrentValueList
).second
;
3387 ++pListBoxDescription
;
3389 DBG_ASSERT(nListBoxDescription
== (pListBoxDescription
- aListBoxDescription
.getConstArray()),
3390 "FmXFormShell::CreateExternalView : forgot to adjust nListBoxDescription ?");
3392 // properties describing the column "meta data"
3393 const sal_Int16 nDispatchArgs
= 3;
3394 Sequence
< PropertyValue
> aDispatchArgs(nDispatchArgs
);
3395 PropertyValue
* pDispatchArgs
= aDispatchArgs
.getArray();
3397 // column type : listbox
3398 pDispatchArgs
->Name
= FMARG_ADDCOL_COLUMNTYPE
;
3399 pDispatchArgs
->Value
<<= u
"" FM_COL_LISTBOX
""_ustr
;
3400 // pDispatchArgs->Value <<= (OUString)FM_COL_LISTBOX;
3404 pDispatchArgs
->Name
= FMARG_ADDCOL_COLUMNPOS
;
3405 FmMapUString2Int16::const_iterator aOffset
= aRadioPositions
.find(rCtrlSource
.first
);
3406 assert(aOffset
!= aRadioPositions
.end() && "FmXFormShell::CreateExternalView : inconsistent radio descriptions !");
3407 sal_Int16 nPosition
= (*aOffset
).second
;
3408 nPosition
= nPosition
+ nOffset
;
3409 // we already inserted nOffset additional columns...
3410 pDispatchArgs
->Value
<<= nPosition
;
3414 pDispatchArgs
->Name
= "ColumnProperties"; // TODO : fmurl.*
3415 pDispatchArgs
->Value
<<= aListBoxDescription
;
3417 DBG_ASSERT(nDispatchArgs
== (pDispatchArgs
- aDispatchArgs
.getConstArray()),
3418 "FmXFormShell::CreateExternalView : forgot to adjust nDispatchArgs ?");
3420 // dispatch the "add column"
3421 xAddColumnDispatch
->dispatch(aAddColumnURL
, aDispatchArgs
);
3427 DBG_ASSERT(nAddedColumns
> 0, "FmXFormShell::CreateExternalView : no controls (inconsistent) !");
3428 // we should have checked if we have any usable controls (see above).
3430 // "load" the "form" of the external view
3432 aArg
.Name
= FMARG_ATTACHTO_MASTERFORM
;
3433 Reference
< XResultSet
> xForm(xCurrentNavController
->getModel(), UNO_QUERY
);
3434 aArg
.Value
<<= xForm
;
3436 m_xExternalDisplayedForm
= std::move(xForm
);
3437 // do this before dispatching the "attach" command, as the attach may result in a call to our queryDispatch (for the FormSlots)
3438 // which needs the m_xExternalDisplayedForm
3440 xAttachDispatch
->dispatch(aAttachURL
, Sequence
< PropertyValue
>(&aArg
, 1));
3442 m_xExtViewTriggerController
= std::move(xCurrentNavController
);
3444 // we want to know modifications done in the external view
3445 // if the external controller is a XFormController we can use all our default handlings for it
3446 Reference
< runtime::XFormController
> xFormController( m_xExternalViewController
, UNO_QUERY
);
3447 OSL_ENSURE( xFormController
.is(), "FmXFormShell::CreateExternalView:: invalid external view controller!" );
3448 if (xFormController
.is())
3449 xFormController
->addActivateListener(static_cast<XFormControllerListener
*>(this));
3455 OSL_FAIL("FmXFormShell::CreateExternalView : could not create the external form view !");
3458 InvalidateSlot_Lock(SID_FM_VIEW_AS_GRID
, false);
3462 void FmXFormShell::implAdjustConfigCache_Lock()
3464 const bool bFuzzing(comphelper::IsFuzzing());
3468 // get (cache) the wizard usage flag
3469 Sequence
< OUString
> aNames
{ u
"FormControlPilotsEnabled"_ustr
};
3470 Sequence
< Any
> aFlags
= GetProperties(aNames
);
3471 if (1 == aFlags
.getLength())
3472 m_bUseWizards
= ::cppu::any2bool(aFlags
[0]);
3476 void FmXFormShell::Notify( const css::uno::Sequence
< OUString
>& _rPropertyNames
)
3478 DBG_TESTSOLARMUTEX();
3479 if (impl_checkDisposed_Lock())
3482 for (const OUString
& rName
: _rPropertyNames
)
3483 if (rName
== "FormControlPilotsEnabled")
3485 implAdjustConfigCache_Lock();
3486 InvalidateSlot_Lock(SID_FM_USE_WIZARDS
, true);
3490 void FmXFormShell::ImplCommit()
3495 void FmXFormShell::SetWizardUsing_Lock(bool _bUseThem
)
3497 m_bUseWizards
= _bUseThem
;
3499 Sequence
< OUString
> aNames
{ u
"FormControlPilotsEnabled"_ustr
};
3500 Sequence
< Any
> aValues
{ Any(m_bUseWizards
) };
3501 PutProperties(aNames
, aValues
);
3505 void FmXFormShell::viewDeactivated_Lock(FmFormView
& _rCurrentView
, bool _bDeactivateController
)
3508 if ( _rCurrentView
.GetImpl() && !_rCurrentView
.IsDesignMode() )
3510 _rCurrentView
.GetImpl()->Deactivate( _bDeactivateController
);
3513 // if we have an async load operation pending for the 0-th page for this view,
3514 // we need to cancel this
3515 if (FmFormPage
* pPage
= _rCurrentView
.GetCurPage())
3517 // move all events from our queue to a new one, omit the events for the deactivated
3519 ::std::queue
< FmLoadAction
> aNewEvents
;
3520 while ( !m_aLoadingPages
.empty() )
3522 FmLoadAction aAction
= m_aLoadingPages
.front();
3523 m_aLoadingPages
.pop();
3524 if ( pPage
!= aAction
.pPage
)
3526 aNewEvents
.push( aAction
);
3530 Application::RemoveUserEvent( aAction
.nEventId
);
3533 m_aLoadingPages
= std::move(aNewEvents
);
3535 // remove callbacks at the page
3536 pPage
->GetImpl().SetFormsCreationHdl( Link
<FmFormPageImpl
&,void>() );
3538 UpdateForms_Lock(true);
3542 IMPL_LINK_NOARG( FmXFormShell
, OnFirstTimeActivation_Lock
, void*, void )
3544 if (impl_checkDisposed_Lock())
3547 m_nActivationEvent
= nullptr;
3548 SfxObjectShell
* pDocument
= m_pShell
->GetObjectShell();
3550 if ( pDocument
&& !pDocument
->HasName() )
3552 if (isEnhancedForm_Lock())
3554 // show the data navigator
3555 if ( !m_pShell
->GetViewShell()->GetViewFrame().HasChildWindow( SID_FM_SHOW_DATANAVIGATOR
) )
3556 m_pShell
->GetViewShell()->GetViewFrame().ToggleChildWindow( SID_FM_SHOW_DATANAVIGATOR
);
3562 IMPL_LINK_NOARG( FmXFormShell
, OnFormsCreated_Lock
, FmFormPageImpl
&, void )
3564 UpdateForms_Lock(true);
3568 void FmXFormShell::viewActivated_Lock(FmFormView
& _rCurrentView
, bool _bSyncAction
)
3570 FmFormPage
* pPage
= _rCurrentView
.GetCurPage();
3572 // activate our view if we are activated ourself
3573 // FS - 30.06.99 - 67308
3574 if ( _rCurrentView
.GetImpl() && !_rCurrentView
.IsDesignMode() )
3576 // load forms for the page the current view belongs to
3579 if ( !pPage
->GetImpl().hasEverBeenActivated() )
3580 loadForms_Lock(pPage
, LoadFormsFlags::Load
3581 | (_bSyncAction
? LoadFormsFlags::Sync
3582 : LoadFormsFlags::Async
));
3583 pPage
->GetImpl().setHasBeenActivated( );
3586 // first-time initializations for the views
3587 if ( !_rCurrentView
.GetImpl()->hasEverBeenActivated( ) )
3589 auto* pFormModel
= dynamic_cast<FmFormModel
*>(&_rCurrentView
.GetModel());
3590 _rCurrentView
.GetImpl()->onFirstViewActivation(pFormModel
);
3591 _rCurrentView
.GetImpl()->setHasBeenActivated();
3594 // activate the current view
3595 _rCurrentView
.GetImpl()->Activate( _bSyncAction
);
3598 // set callbacks at the page
3601 pPage
->GetImpl().SetFormsCreationHdl(LINK(this, FmXFormShell
, OnFormsCreated_Lock
));
3604 UpdateForms_Lock(true);
3606 if ( m_bFirstActivation
)
3608 m_nActivationEvent
= Application::PostUserEvent(LINK(this, FmXFormShell
, OnFirstTimeActivation_Lock
));
3609 m_bFirstActivation
= false;
3612 // find a default "current form", if there is none, yet
3613 // #i88186# / 2008-04-12 / frank.schoenheit@sun.com
3614 impl_defaultCurrentForm_nothrow_Lock();
3618 void FmXFormShell::impl_defaultCurrentForm_nothrow_Lock()
3620 if (impl_checkDisposed_Lock())
3623 if ( m_xCurrentForm
.is() )
3624 // no action required
3627 FmFormView
* pFormView
= m_pShell
->GetFormView();
3628 FmFormPage
* pPage
= pFormView
? pFormView
->GetCurPage() : nullptr;
3634 Reference
< XIndexAccess
> xForms
= pPage
->GetForms( false );
3635 if ( !xForms
.is() || !xForms
->hasElements() )
3638 Reference
< XForm
> xNewCurrentForm( xForms
->getByIndex(0), UNO_QUERY_THROW
);
3639 impl_updateCurrentForm_Lock(xNewCurrentForm
);
3641 catch( const Exception
& )
3643 DBG_UNHANDLED_EXCEPTION("svx");
3648 void FmXFormShell::smartControlReset( const Reference
< XIndexAccess
>& _rxModels
)
3650 if (!_rxModels
.is())
3652 OSL_FAIL("FmXFormShell::smartControlReset: invalid container!");
3656 sal_Int32 nCount
= _rxModels
->getCount();
3657 Reference
< XPropertySet
> xCurrent
;
3658 Reference
< XPropertySetInfo
> xCurrentInfo
;
3659 Reference
< XPropertySet
> xBoundField
;
3661 for (sal_Int32 i
=0; i
<nCount
; ++i
)
3663 _rxModels
->getByIndex(i
) >>= xCurrent
;
3665 xCurrentInfo
= xCurrent
->getPropertySetInfo();
3667 xCurrentInfo
.clear();
3668 if (!xCurrentInfo
.is())
3671 if (xCurrentInfo
->hasPropertyByName(FM_PROP_CLASSID
))
3672 { // it's a control model
3674 // check if this control is bound to a living database field
3675 if (xCurrentInfo
->hasPropertyByName(FM_PROP_BOUNDFIELD
))
3676 xCurrent
->getPropertyValue(FM_PROP_BOUNDFIELD
) >>= xBoundField
;
3678 xBoundField
.clear();
3680 // reset only if it's *not* bound
3681 bool bReset
= !xBoundField
.is();
3683 // and additionally, check if it has an external value binding
3684 Reference
< XBindableValue
> xBindable( xCurrent
, UNO_QUERY
);
3685 if ( xBindable
.is() && xBindable
->getValueBinding().is() )
3690 Reference
< XReset
> xControlReset( xCurrent
, UNO_QUERY
);
3691 if ( xControlReset
.is() )
3692 xControlReset
->reset();
3697 Reference
< XIndexAccess
> xContainer(xCurrent
, UNO_QUERY
);
3698 if (xContainer
.is())
3699 smartControlReset(xContainer
);
3705 IMPL_LINK_NOARG( FmXFormShell
, OnLoadForms_Lock
, void*, void )
3707 FmLoadAction aAction
= m_aLoadingPages
.front();
3708 m_aLoadingPages
.pop();
3710 loadForms_Lock(aAction
.pPage
, aAction
.nFlags
& ~LoadFormsFlags::Async
);
3716 bool lcl_isLoadable( const Reference
< XInterface
>& _rxLoadable
)
3718 // determines whether a form should be loaded or not
3719 // if there is no datasource or connection there is no reason to load a form
3720 Reference
< XPropertySet
> xSet( _rxLoadable
, UNO_QUERY
);
3725 Reference
< XConnection
> xConn
;
3726 if ( isEmbeddedInDatabase( _rxLoadable
, xConn
) )
3729 // is there already an active connection
3730 xSet
->getPropertyValue(FM_PROP_ACTIVE_CONNECTION
) >>= xConn
;
3734 OUString sPropertyValue
;
3735 OSL_VERIFY( xSet
->getPropertyValue( FM_PROP_DATASOURCE
) >>= sPropertyValue
);
3736 if ( !sPropertyValue
.isEmpty() )
3739 OSL_VERIFY( xSet
->getPropertyValue( FM_PROP_URL
) >>= sPropertyValue
);
3740 if ( !sPropertyValue
.isEmpty() )
3743 catch(const Exception
&)
3745 DBG_UNHANDLED_EXCEPTION("svx");
3752 void FmXFormShell::loadForms_Lock(FmFormPage
* _pPage
, const LoadFormsFlags _nBehaviour
/* LoadFormsFlags::Load | LoadFormsFlags::Sync */)
3754 DBG_ASSERT( ( _nBehaviour
& ( LoadFormsFlags::Async
| LoadFormsFlags::Unload
) ) != ( LoadFormsFlags::Async
| LoadFormsFlags::Unload
),
3755 "FmXFormShell::loadForms: async loading not supported - this will heavily fail!" );
3757 if ( _nBehaviour
& LoadFormsFlags::Async
)
3759 m_aLoadingPages
.push( FmLoadAction(
3762 Application::PostUserEvent(LINK(this, FmXFormShell
, OnLoadForms_Lock
), _pPage
)
3767 DBG_ASSERT( _pPage
, "FmXFormShell::loadForms: invalid page!" );
3771 // lock the undo env so the forms can change non-transient properties while loading
3772 // (without this my doc's modified flag would be set)
3773 FmFormModel
& rFmFormModel(dynamic_cast< FmFormModel
& >(_pPage
->getSdrModelFromSdrPage()));
3774 rFmFormModel
.GetUndoEnv().Lock();
3777 Reference
< XIndexAccess
> xForms
= _pPage
->GetForms( false );
3781 Reference
< XLoadable
> xForm
;
3782 for ( sal_Int32 j
= 0, nCount
= xForms
->getCount(); j
< nCount
; ++j
)
3784 xForms
->getByIndex( j
) >>= xForm
;
3785 bool bFormWasLoaded
= false;
3786 // a database form must be loaded for
3789 if ( !( _nBehaviour
& LoadFormsFlags::Unload
) )
3791 if ( lcl_isLoadable( xForm
) && !xForm
->isLoaded() )
3796 if ( xForm
->isLoaded() )
3798 bFormWasLoaded
= true;
3803 catch( const Exception
& )
3805 DBG_UNHANDLED_EXCEPTION("svx");
3808 // reset the form if it was loaded
3809 if ( bFormWasLoaded
)
3811 Reference
< XIndexAccess
> xContainer( xForm
, UNO_QUERY
);
3812 DBG_ASSERT( xContainer
.is(), "FmXFormShell::loadForms: the form is no container!" );
3813 if ( xContainer
.is() )
3814 smartControlReset( xContainer
);
3819 // unlock the environment
3820 rFmFormModel
.GetUndoEnv().UnLock();
3824 void FmXFormShell::ExecuteTextAttribute_Lock(SfxRequest
& _rReq
)
3826 DBG_TESTSOLARMUTEX();
3827 m_pTextShell
->ExecuteTextAttribute( _rReq
);
3831 void FmXFormShell::GetTextAttributeState_Lock(SfxItemSet
& _rSet
)
3833 DBG_TESTSOLARMUTEX();
3834 m_pTextShell
->GetTextAttributeState( _rSet
);
3838 bool FmXFormShell::IsActiveControl_Lock(bool _bCountRichTextOnly
) const
3840 DBG_TESTSOLARMUTEX();
3841 return m_pTextShell
->IsActiveControl( _bCountRichTextOnly
);
3845 void FmXFormShell::ForgetActiveControl_Lock()
3847 DBG_TESTSOLARMUTEX();
3848 m_pTextShell
->ForgetActiveControl();
3852 void FmXFormShell::SetControlActivationHandler_Lock(const Link
<LinkParamNone
*,void>& _rHdl
)
3854 DBG_TESTSOLARMUTEX();
3855 m_pTextShell
->SetControlActivationHandler( _rHdl
);
3858 void FmXFormShell::handleShowPropertiesRequest_Lock()
3860 if (onlyControlsAreMarked_Lock())
3861 ShowSelectionProperties_Lock( true );
3865 void FmXFormShell::handleMouseButtonDown_Lock(const SdrViewEvent
& _rViewEvent
)
3867 // catch simple double clicks
3868 if (_rViewEvent
.mnMouseClicks
== 2 && _rViewEvent
.mnMouseCode
== MOUSE_LEFT
)
3870 if ( _rViewEvent
.meHit
== SdrHitKind::MarkedObject
)
3872 if (onlyControlsAreMarked_Lock())
3873 ShowSelectionProperties_Lock( true );
3879 bool FmXFormShell::HasControlFocus_Lock() const
3881 bool bHasControlFocus
= false;
3885 Reference
<runtime::XFormController
> xController(getActiveController_Lock());
3886 Reference
< XControl
> xCurrentControl
;
3887 if ( xController
.is() )
3888 xCurrentControl
.set( xController
->getCurrentControl() );
3889 if ( xCurrentControl
.is() )
3891 Reference
< XWindow2
> xPeerWindow( xCurrentControl
->getPeer(), UNO_QUERY_THROW
);
3892 bHasControlFocus
= xPeerWindow
->hasFocus();
3895 catch( const Exception
& )
3897 DBG_UNHANDLED_EXCEPTION("svx");
3900 return bHasControlFocus
;
3904 SearchableControlIterator::SearchableControlIterator(Reference
< XInterface
> const & xStartingPoint
)
3905 :IndexAccessIterator(xStartingPoint
)
3910 bool SearchableControlIterator::ShouldHandleElement(const Reference
< XInterface
>& xElement
)
3912 // if the thing has a ControlSource and a BoundField property
3913 Reference
< XPropertySet
> xProperties(xElement
, UNO_QUERY
);
3914 if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCE
, xProperties
) && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD
, xProperties
))
3916 // and the BoundField is valid
3917 Reference
< XPropertySet
> xField
;
3918 xProperties
->getPropertyValue(FM_PROP_BOUNDFIELD
) >>= xField
;
3922 m_sCurrentValue
= ::comphelper::getString(xProperties
->getPropertyValue(FM_PROP_CONTROLSOURCE
));
3927 // if it is a grid control
3928 if (::comphelper::hasProperty(FM_PROP_CLASSID
, xProperties
))
3930 Any
aClassId( xProperties
->getPropertyValue(FM_PROP_CLASSID
) );
3931 if (::comphelper::getINT16(aClassId
) == FormComponentType::GRIDCONTROL
)
3933 m_sCurrentValue
.clear();
3942 bool SearchableControlIterator::ShouldStepInto(const Reference
< XInterface
>& /*xContainer*/) const
3947 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */