update dev300-m58
[ooovba.git] / svx / source / form / fmshimp.cxx
blob06a4f8179175096810252a52f7b8bd588aba75cf
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: fmshimp.cxx,v $
10 * $Revision: 1.94 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
33 #include "gridcols.hxx"
34 #include <svx/obj3d.hxx>
35 #include "fmvwimp.hxx"
36 #include "fmshimp.hxx"
37 #include "fmtextcontrolshell.hxx"
38 #include <svx/svdpagv.hxx>
39 #include <svx/fmpage.hxx>
40 #include <svx/dialmgr.hxx>
41 #ifndef _SVX_FMRESIDS_HRC
42 #include "fmresids.hrc"
43 #endif
44 #include "fmitems.hxx"
45 #include "fmobj.hxx"
46 #include "formtoolbars.hxx"
47 #include <svx/fmglob.hxx>
48 #include "svditer.hxx"
49 #include "fmservs.hxx"
50 #include "fmpgeimp.hxx"
51 #include "fmtools.hxx"
52 #ifndef _SVX_FMPROP_HRC
53 #include "fmprop.hrc"
54 #endif
55 #include <svx/fmshell.hxx>
56 #ifndef _SVX_SVXIDS_HRC
57 #include <svx/svxids.hrc>
58 #endif
59 #include <svx/fmmodel.hxx>
60 #include "fmundo.hxx"
61 #include "fmurl.hxx"
62 #include "formcontrolling.hxx"
63 #include <svx/svxdlg.hxx>
64 #include <svx/dialogs.hrc>
65 #include <com/sun/star/frame/FrameSearchFlag.hpp>
66 #include <com/sun/star/form/XLoadable.hpp>
67 #include <com/sun/star/container/XNamed.hpp>
68 #include <com/sun/star/container/XContainer.hpp>
69 #include <com/sun/star/container/XEnumeration.hpp>
70 #include <com/sun/star/container/XIndexAccess.hpp>
71 #include <com/sun/star/container/XEnumerationAccess.hpp>
72 #include <com/sun/star/frame/FrameSearchFlag.hpp>
73 #include <com/sun/star/awt/XTextComponent.hpp>
74 #include <com/sun/star/awt/XListBox.hpp>
75 #include <com/sun/star/awt/XCheckBox.hpp>
76 #include <com/sun/star/form/XBoundComponent.hpp>
77 #include <com/sun/star/form/ListSourceType.hpp>
78 #include <com/sun/star/view/XSelectionSupplier.hpp>
79 #include <com/sun/star/script/XEventAttacherManager.hpp>
80 #include <com/sun/star/form/XBoundControl.hpp>
81 #include <com/sun/star/form/XReset.hpp>
82 #include <com/sun/star/form/XGrid.hpp>
83 #include <com/sun/star/form/XGridPeer.hpp>
84 #include <com/sun/star/util/XNumberFormatter.hpp>
85 #include <com/sun/star/util/XModeSelector.hpp>
86 #include <com/sun/star/util/XModifyBroadcaster.hpp>
87 #include <com/sun/star/util/XCancellable.hpp>
88 #include <com/sun/star/beans/PropertyAttribute.hpp>
89 #include <com/sun/star/beans/XPropertyState.hpp>
90 #include <com/sun/star/form/binding/XBindableValue.hpp>
91 #include <com/sun/star/beans/NamedValue.hpp>
92 #include <com/sun/star/form/binding/XListEntrySink.hpp>
93 #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
94 #include <osl/mutex.hxx>
95 #include <sfx2/viewsh.hxx>
96 #include <sfx2/viewfrm.hxx>
97 #include <sfx2/frame.hxx>
98 #include <vcl/waitobj.hxx>
99 #include <tools/shl.hxx>
100 #include <tools/diagnose_ex.h>
101 #include <vcl/msgbox.hxx>
102 #include <sfx2/dispatch.hxx>
103 #include <sfx2/objsh.hxx>
104 #include <sfx2/docfile.hxx>
105 #include <tools/color.hxx>
106 #include <tools/urlobj.hxx>
107 #include <comphelper/property.hxx>
108 #include <connectivity/dbtools.hxx>
109 #include <comphelper/stl_types.hxx>
110 #include <comphelper/processfactory.hxx>
111 #include <cppuhelper/servicefactory.hxx>
112 #include <comphelper/extract.hxx>
113 #include <toolkit/helper/vclunohelper.hxx>
114 #include <svx/sdrpagewindow.hxx>
115 #include <rtl/logfile.hxx>
117 #include <algorithm>
118 #include <functional>
120 // wird fuer Invalidate verwendet -> mitpflegen
121 sal_uInt16 DatabaseSlotMap[] =
123 SID_FM_RECORD_FIRST,
124 SID_FM_RECORD_NEXT,
125 SID_FM_RECORD_PREV,
126 SID_FM_RECORD_LAST,
127 SID_FM_RECORD_NEW,
128 SID_FM_RECORD_DELETE,
129 SID_FM_RECORD_ABSOLUTE,
130 SID_FM_RECORD_TOTAL,
131 SID_FM_RECORD_SAVE,
132 SID_FM_RECORD_UNDO,
133 SID_FM_REMOVE_FILTER_SORT,
134 SID_FM_SORTUP,
135 SID_FM_SORTDOWN,
136 SID_FM_ORDERCRIT,
137 SID_FM_AUTOFILTER,
138 SID_FM_FORM_FILTERED,
139 SID_FM_REFRESH,
140 SID_FM_REFRESH_FORM_CONTROL,
141 SID_FM_SEARCH,
142 SID_FM_FILTER_START,
143 SID_FM_VIEW_AS_GRID,
147 // wird fuer Invalidate verwendet -> mitpflegen
148 // aufsteigend sortieren !!!!!!
149 sal_Int16 DlgSlotMap[] = // slots des Controllers
151 SID_FM_CTL_PROPERTIES,
152 SID_FM_PROPERTIES,
153 SID_FM_TAB_DIALOG,
154 SID_FM_ADD_FIELD,
155 SID_FM_SHOW_FMEXPLORER,
156 SID_FM_FIELDS_CONTROL,
157 SID_FM_SHOW_PROPERTIES,
158 SID_FM_PROPERTY_CONTROL,
159 SID_FM_FMEXPLORER_CONTROL,
160 SID_FM_SHOW_DATANAVIGATOR,
161 SID_FM_DATANAVIGATOR_CONTROL,
165 sal_Int16 SelObjectSlotMap[] = // vom SelObject abhaengige Slots
167 SID_FM_CONVERTTO_EDIT,
168 SID_FM_CONVERTTO_BUTTON,
169 SID_FM_CONVERTTO_FIXEDTEXT,
170 SID_FM_CONVERTTO_LISTBOX,
171 SID_FM_CONVERTTO_CHECKBOX,
172 SID_FM_CONVERTTO_RADIOBUTTON,
173 SID_FM_CONVERTTO_GROUPBOX,
174 SID_FM_CONVERTTO_COMBOBOX,
175 SID_FM_CONVERTTO_IMAGEBUTTON,
176 SID_FM_CONVERTTO_FILECONTROL,
177 SID_FM_CONVERTTO_DATE,
178 SID_FM_CONVERTTO_TIME,
179 SID_FM_CONVERTTO_NUMERIC,
180 SID_FM_CONVERTTO_CURRENCY,
181 SID_FM_CONVERTTO_PATTERN,
182 SID_FM_CONVERTTO_IMAGECONTROL,
183 SID_FM_CONVERTTO_FORMATTED,
184 SID_FM_CONVERTTO_SCROLLBAR,
185 SID_FM_CONVERTTO_SPINBUTTON,
186 SID_FM_CONVERTTO_NAVIGATIONBAR,
188 SID_FM_FMEXPLORER_CONTROL,
189 SID_FM_DATANAVIGATOR_CONTROL,
194 // die folgenden Arrays muessen kosistent sein, also einander entsprechende Eintraege an der selben relativen Position
195 // innerhalb ihres jeweiligen Arrays stehen
196 sal_Int16 nConvertSlots[] =
198 SID_FM_CONVERTTO_EDIT,
199 SID_FM_CONVERTTO_BUTTON,
200 SID_FM_CONVERTTO_FIXEDTEXT,
201 SID_FM_CONVERTTO_LISTBOX,
202 SID_FM_CONVERTTO_CHECKBOX,
203 SID_FM_CONVERTTO_RADIOBUTTON,
204 SID_FM_CONVERTTO_GROUPBOX,
205 SID_FM_CONVERTTO_COMBOBOX,
206 SID_FM_CONVERTTO_IMAGEBUTTON,
207 SID_FM_CONVERTTO_FILECONTROL,
208 SID_FM_CONVERTTO_DATE,
209 SID_FM_CONVERTTO_TIME,
210 SID_FM_CONVERTTO_NUMERIC,
211 SID_FM_CONVERTTO_CURRENCY,
212 SID_FM_CONVERTTO_PATTERN,
213 SID_FM_CONVERTTO_IMAGECONTROL,
214 SID_FM_CONVERTTO_FORMATTED,
215 SID_FM_CONVERTTO_SCROLLBAR,
216 SID_FM_CONVERTTO_SPINBUTTON,
217 SID_FM_CONVERTTO_NAVIGATIONBAR
220 sal_Int16 nCreateSlots[] =
222 SID_FM_EDIT,
223 SID_FM_PUSHBUTTON,
224 SID_FM_FIXEDTEXT,
225 SID_FM_LISTBOX,
226 SID_FM_CHECKBOX,
227 SID_FM_RADIOBUTTON,
228 SID_FM_GROUPBOX,
229 SID_FM_COMBOBOX,
230 SID_FM_IMAGEBUTTON,
231 SID_FM_FILECONTROL,
232 SID_FM_DATEFIELD,
233 SID_FM_TIMEFIELD,
234 SID_FM_NUMERICFIELD,
235 SID_FM_CURRENCYFIELD,
236 SID_FM_PATTERNFIELD,
237 SID_FM_IMAGECONTROL,
238 SID_FM_FORMATTEDFIELD,
239 SID_FM_SCROLLBAR,
240 SID_FM_SPINBUTTON,
241 SID_FM_NAVIGATIONBAR
244 sal_Int16 nObjectTypes[] =
246 OBJ_FM_EDIT,
247 OBJ_FM_BUTTON,
248 OBJ_FM_FIXEDTEXT,
249 OBJ_FM_LISTBOX,
250 OBJ_FM_CHECKBOX,
251 OBJ_FM_RADIOBUTTON,
252 OBJ_FM_GROUPBOX,
253 OBJ_FM_COMBOBOX,
254 OBJ_FM_IMAGEBUTTON,
255 OBJ_FM_FILECONTROL,
256 OBJ_FM_DATEFIELD,
257 OBJ_FM_TIMEFIELD,
258 OBJ_FM_NUMERICFIELD,
259 OBJ_FM_CURRENCYFIELD,
260 OBJ_FM_PATTERNFIELD,
261 OBJ_FM_IMAGECONTROL,
262 OBJ_FM_FORMATTEDFIELD,
263 OBJ_FM_SCROLLBAR,
264 OBJ_FM_SPINBUTTON,
265 OBJ_FM_NAVIGATIONBAR
268 using namespace ::com::sun::star;
269 using namespace ::com::sun::star::ui;
270 using namespace ::com::sun::star::uno;
271 using namespace ::com::sun::star::sdb;
272 using namespace ::com::sun::star::sdbc;
273 using namespace ::com::sun::star::sdbcx;
274 using namespace ::com::sun::star::beans;
275 using namespace ::com::sun::star::container;
276 using namespace ::com::sun::star::form;
277 using namespace ::com::sun::star::form::binding;
278 using namespace ::com::sun::star::form::runtime;
279 using namespace ::com::sun::star::awt;
280 using namespace ::com::sun::star::view;
281 using namespace ::com::sun::star::lang;
282 using namespace ::com::sun::star::util;
283 using namespace ::com::sun::star::frame;
284 using namespace ::svxform;
285 using namespace ::svx;
287 //==============================================================================
288 //= helper
289 //==============================================================================
290 namespace
292 //....................................................................
293 void collectInterfacesFromMarkList( const SdrMarkList& _rMarkList, InterfaceBag& /* [out] */ _rInterfaces )
295 _rInterfaces.clear();
297 sal_uInt32 nMarkCount = _rMarkList.GetMarkCount();
298 for ( sal_uInt32 i = 0; i < nMarkCount; ++i)
300 SdrObject* pCurrent = _rMarkList.GetMark( i )->GetMarkedSdrObj();
302 SdrObjListIter* pGroupIterator = NULL;
303 if ( pCurrent->IsGroupObject() )
305 pGroupIterator = new SdrObjListIter( *pCurrent->GetSubList() );
306 pCurrent = pGroupIterator->IsMore() ? pGroupIterator->Next() : NULL;
309 while ( pCurrent )
311 FmFormObj* pAsFormObject = FmFormObj::GetFormObject( pCurrent );
312 // note this will de-reference virtual objects, if necessary/possible
313 if ( pAsFormObject )
315 Reference< XInterface > xControlModel( pAsFormObject->GetUnoControlModel(), UNO_QUERY );
316 // the UNO_QUERY is important for normalization
317 if ( xControlModel.is() )
318 _rInterfaces.insert( xControlModel );
321 // next element
322 pCurrent = pGroupIterator && pGroupIterator->IsMore() ? pGroupIterator->Next() : NULL;
325 if ( pGroupIterator )
326 delete pGroupIterator;
332 //------------------------------------------------------------------------------
333 // check if the control has one of the interfaces we can use for searching
334 // *_pCurrentText will be filled with the current text of the control (as used when searching this control)
335 sal_Bool IsSearchableControl( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface>& _rxControl,
336 ::rtl::OUString* _pCurrentText )
338 if ( !_rxControl.is() )
339 return sal_False;
341 Reference< XTextComponent > xAsText( _rxControl, UNO_QUERY );
342 if ( xAsText.is() )
344 if ( _pCurrentText )
345 *_pCurrentText = xAsText->getText();
346 return sal_True;
349 Reference< XListBox > xListBox( _rxControl, UNO_QUERY );
350 if ( xListBox.is() )
352 if ( _pCurrentText )
353 *_pCurrentText = xListBox->getSelectedItem();
354 return sal_True;
357 Reference< XCheckBox > xCheckBox( _rxControl, UNO_QUERY );
358 if ( xCheckBox.is() )
360 if ( _pCurrentText )
362 switch ( (TriState)xCheckBox->getState() )
364 case STATE_NOCHECK: *_pCurrentText = ::rtl::OUString::createFromAscii( "0" ); break;
365 case STATE_CHECK: *_pCurrentText = ::rtl::OUString::createFromAscii( "1" ); break;
366 default: *_pCurrentText = ::rtl::OUString(); break;
369 return sal_True;
372 return sal_False;
375 //------------------------------------------------------------------------------
376 sal_Bool FmXBoundFormFieldIterator::ShouldStepInto(const Reference< XInterface>& _rContainer) const
378 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXBoundFormFieldIterator::ShouldStepInto" );
379 if (_rContainer == m_xStartingPoint)
380 // would be quite stupid to step over the root ....
381 return sal_True;
383 return Reference< XControlModel>(_rContainer, UNO_QUERY).is();
386 //------------------------------------------------------------------------------
387 sal_Bool FmXBoundFormFieldIterator::ShouldHandleElement(const Reference< XInterface>& _rElement)
389 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXBoundFormFieldIterator::ShouldHandleElement" );
390 if (!_rElement.is())
391 // NULL element
392 return sal_False;
394 if (Reference< XForm>(_rElement, UNO_QUERY).is() || Reference< XGrid>(_rElement, UNO_QUERY).is())
395 // a forms or a grid
396 return sal_False;
398 Reference< XPropertySet> xSet(_rElement, UNO_QUERY);
399 if (!xSet.is() || !::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xSet))
400 // no "BoundField" property
401 return sal_False;
403 Any aVal( xSet->getPropertyValue(FM_PROP_BOUNDFIELD) );
404 if (aVal.getValueTypeClass() != TypeClass_INTERFACE)
405 // void or invalid property value
406 return sal_False;
408 return aVal.hasValue();
411 //==============================================================================
413 DECL_CURSOR_ACTION_THREAD(FmMoveToLastThread)
414 IMPL_CURSOR_ACTION_THREAD(FmMoveToLastThread, SVX_RES(RID_STR_MOVING_CURSOR), last());
416 //------------------------------------------------------------------------------
417 sal_Bool isControlList(const SdrMarkList& rMarkList)
419 // enthaelt die liste nur Controls und mindestens ein control
420 sal_uInt32 nMarkCount = rMarkList.GetMarkCount();
421 sal_Bool bControlList = nMarkCount != 0;
423 sal_Bool bHadAnyLeafs = sal_False;
425 for (sal_uInt32 i = 0; i < nMarkCount && bControlList; i++)
427 SdrObject *pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
428 E3dObject* pAs3DObject = PTR_CAST(E3dObject, pObj);
429 // E3dObject's do not contain any 2D-objects (by definition)
430 // we need this extra check here : an E3dObject->IsGroupObject says "YES", but an SdrObjListIter working
431 // with an E3dObject doesn't give me any Nodes (E3dObject has a sub list, but no members in that list,
432 // cause there implementation differs from the one of "normal" SdrObject's. Unfortunally SdrObject::IsGroupObject
433 // doesn't check the element count of the sub list, which is simply a bug in IsGroupObject we can't fix at the moment).
434 // So at the end of this function bControlList would have the same value it was initialized with above : sal_True
435 // And this would be wrong :)
436 // 03.02.00 - 72529 - FS
437 if (!pAs3DObject)
439 if (pObj->IsGroupObject())
441 SdrObjListIter aIter(*pObj->GetSubList());
442 while (aIter.IsMore() && bControlList)
444 bControlList = FmFormInventor == aIter.Next()->GetObjInventor();
445 bHadAnyLeafs = sal_True;
448 else
450 bHadAnyLeafs = sal_True;
451 bControlList = FmFormInventor == pObj->GetObjInventor();
456 return bControlList && bHadAnyLeafs;
459 //------------------------------------------------------------------------
460 Reference< XForm > GetForm(const Reference< XInterface>& _rxElement)
462 Reference< XForm > xForm( _rxElement, UNO_QUERY );
463 if ( xForm.is() )
464 return xForm;
466 Reference< XChild > xChild( _rxElement, UNO_QUERY );
467 if ( xChild.is() )
468 return GetForm( xChild->getParent() );
470 return Reference< XForm >();
473 //========================================================================
474 // class FmXFormShell_Base_Disambiguation
475 //========================================================================
476 FmXFormShell_Base_Disambiguation::FmXFormShell_Base_Disambiguation( ::osl::Mutex& _rMutex )
477 :FmXFormShell_BD_BASE( _rMutex )
481 void SAL_CALL FmXFormShell_Base_Disambiguation::disposing()
483 WeakComponentImplHelperBase::disposing();
484 // Note:
485 // This is a HACK.
486 // Normally it should be sufficient to call the "disposing" of our direct
487 // base class, but SUN PRO 5 does not like this and claims there is a conflict
488 // with the XEventListener::disposing(EventObject) of our various listener
489 // base classes.
492 //========================================================================
493 // class FmXFormShell
494 //========================================================================
495 DBG_NAME(FmXFormShell);
496 //------------------------------------------------------------------------
497 FmXFormShell::FmXFormShell( FmFormShell& _rShell, SfxViewFrame* _pViewFrame )
498 :FmXFormShell_BASE(m_aMutex)
499 ,FmXFormShell_CFGBASE(::rtl::OUString::createFromAscii("Office.Common/Misc"), CONFIG_MODE_DELAYED_UPDATE)
500 ,m_eNavigate( NavigationBarMode_NONE )
501 ,m_nInvalidationEvent( 0 )
502 ,m_nActivationEvent( 0 )
503 ,m_pShell( &_rShell )
504 ,m_pTextShell( new ::svx::FmTextControlShell( _pViewFrame ) )
505 ,m_aActiveControllerFeatures( ::comphelper::getProcessServiceFactory(), this )
506 ,m_aNavControllerFeatures( ::comphelper::getProcessServiceFactory(), this )
507 ,m_pExternalViewInterceptor( NULL )
508 ,m_eDocumentType( eUnknownDocumentType )
509 ,m_nLockSlotInvalidation( 0 )
510 ,m_bHadPropertyBrowserInDesignMode( sal_False )
511 ,m_bTrackProperties( sal_True )
512 ,m_bUseWizards( sal_True )
513 ,m_bDatabaseBar( sal_False )
514 ,m_bInActivate( sal_False )
515 ,m_bSetFocus( sal_False )
516 ,m_bFilterMode( sal_False )
517 ,m_bChangingDesignMode( sal_False )
518 ,m_bPreparedClose( sal_False )
519 ,m_bFirstActivation( sal_True )
521 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::FmXFormShell" );
522 DBG_CTOR(FmXFormShell,NULL);
523 m_aMarkTimer.SetTimeout(100);
524 m_aMarkTimer.SetTimeoutHdl(LINK(this,FmXFormShell,OnTimeOut));
526 SfxFrame* pFrame = _pViewFrame ? _pViewFrame->GetFrame() : NULL;
527 if ( pFrame )
528 m_xAttachedFrame = pFrame->GetFrameInterface();
530 // to prevent deletion of this we acquire our refcounter once
531 ::comphelper::increment(FmXFormShell_BASE::m_refCount);
533 // correct the refcounter
534 ::comphelper::decrement(FmXFormShell_BASE::m_refCount);
536 // cache the current configuration settings we're interested in
537 implAdjustConfigCache();
538 // and register for changes on this settings
539 Sequence< ::rtl::OUString > aNames(1);
540 aNames[0] = ::rtl::OUString::createFromAscii("FormControlPilotsEnabled");
541 EnableNotification(aNames);
544 //------------------------------------------------------------------------
545 FmXFormShell::~FmXFormShell()
547 delete m_pTextShell;
548 DBG_DTOR(FmXFormShell,NULL);
551 //------------------------------------------------------------------
552 Reference< XModel > FmXFormShell::getContextDocument() const
554 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getContextDocument" );
555 Reference< XModel > xModel;
557 // determine the type of document we live in
560 Reference< XController > xController;
561 if ( m_xAttachedFrame.is() )
562 xController = m_xAttachedFrame->getController();
563 if ( xController.is() )
564 xModel = xController->getModel();
566 catch( const Exception& )
568 DBG_UNHANDLED_EXCEPTION();
570 return xModel;
573 //------------------------------------------------------------------
574 bool FmXFormShell::isEnhancedForm() const
576 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::isEnhancedForm" );
577 return getDocumentType() == eEnhancedForm;
580 //------------------------------------------------------------------
581 bool FmXFormShell::impl_checkDisposed() const
583 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::impl_checkDisposed" );
584 if ( !m_pShell )
586 OSL_ENSURE( false, "FmXFormShell::impl_checkDisposed: already disposed!" );
587 return true;
589 return false;
592 //------------------------------------------------------------------
593 ::svxform::DocumentType FmXFormShell::getDocumentType() const
595 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getDocumentType" );
596 if ( m_eDocumentType != eUnknownDocumentType )
597 return m_eDocumentType;
599 // determine the type of document we live in
600 Reference< XModel > xModel = getContextDocument();
601 if ( xModel.is() )
602 m_eDocumentType = DocumentClassification::classifyDocument( xModel );
603 else
605 OSL_ENSURE( sal_False, "FmXFormShell::getDocumentType: can't determine the document type!" );
606 m_eDocumentType = eTextDocument;
607 // fallback, just to have a defined state
610 return m_eDocumentType;
613 //------------------------------------------------------------------
614 bool FmXFormShell::IsReadonlyDoc() const
616 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::IsReadonlyDoc" );
617 if ( impl_checkDisposed() )
618 return true;
620 FmFormModel* pModel = m_pShell->GetFormModel();
621 if ( pModel && pModel->GetObjectShell() )
622 return pModel->GetObjectShell()->IsReadOnly() || pModel->GetObjectShell()->IsReadOnlyUI();
623 return true;
626 //------------------------------------------------------------------
627 Any SAL_CALL FmXFormShell::queryInterface( const Type& type) throw ( RuntimeException )
629 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::queryInterface" );
630 return FmXFormShell_BASE::queryInterface(type);
632 //------------------------------------------------------------------------------
633 Sequence< Type > SAL_CALL FmXFormShell::getTypes( ) throw(RuntimeException)
635 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getTypes" );
636 return FmXFormShell_BASE::getTypes();
638 //------------------------------------------------------------------------------
639 Sequence< sal_Int8 > SAL_CALL FmXFormShell::getImplementationId() throw(RuntimeException)
641 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getImplementationId" );
642 static ::cppu::OImplementationId* pId = 0;
643 if (! pId)
645 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
646 if (! pId)
648 static ::cppu::OImplementationId aId;
649 pId = &aId;
652 return pId->getImplementationId();
654 // EventListener
655 //------------------------------------------------------------------------------
656 void SAL_CALL FmXFormShell::disposing(const EventObject& e) throw( RuntimeException )
658 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::disposing" );
659 impl_checkDisposed();
661 if (m_xActiveController == e.Source)
663 // wird der Controller freigeben dann alles loslassen
664 stopListening();
665 m_xActiveForm = NULL;
666 m_xActiveController = NULL;
667 m_xNavigationController = NULL;
669 m_aActiveControllerFeatures.dispose();
670 m_aNavControllerFeatures.dispose();
672 if ( m_pShell )
673 m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell);
676 if (e.Source == m_xExternalViewController)
678 Reference< XFormController> xFormController(m_xExternalViewController, UNO_QUERY);
679 if (xFormController.is())
680 xFormController->removeActivateListener((XFormControllerListener*)this);
682 Reference< ::com::sun::star::lang::XComponent> xComp(m_xExternalViewController, UNO_QUERY);
683 if (xComp.is())
684 xComp->removeEventListener((XEventListener*)(XPropertyChangeListener*)this);
686 m_xExternalViewController = NULL;
687 m_xExternalDisplayedForm = NULL;
688 m_xExtViewTriggerController = NULL;
690 InvalidateSlot( SID_FM_VIEW_AS_GRID, sal_False );
694 //------------------------------------------------------------------------------
695 void SAL_CALL FmXFormShell::propertyChange(const PropertyChangeEvent& evt) throw(::com::sun::star::uno::RuntimeException)
697 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::propertyChange" );
698 if ( impl_checkDisposed() )
699 return;
701 if (evt.PropertyName == FM_PROP_ROWCOUNT)
703 // Das gleich folgenden Update erzwingt ein Neu-Painten der entsprechenden Slots. Wenn ich mich aber hier nicht
704 // in dem HauptThread der Applikation befinde (weil zum Beispiel ein Cursor gerade Datensaetze zaehlt und mir dabei
705 // immer diese PropertyChanges beschert), kann sich das mit en normalen Paints im HauptThread der Applikation beissen.
706 // (Solche Paints passieren zum Beispiel, wenn man einfach nur eine andere Applikation ueber das Office legt und wieder
707 // zurueckschaltet).
708 // Deshalb die Benutzung des SolarMutex, der sichert das ab.
709 ::vos::IMutex& rSolarSafety = Application::GetSolarMutex();
710 if (rSolarSafety.tryToAcquire())
712 m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(SID_FM_RECORD_TOTAL , sal_True, sal_False);
713 m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Update(SID_FM_RECORD_TOTAL);
714 rSolarSafety.release();
716 else
718 // with the following the slot is invalidated asynchron
719 LockSlotInvalidation(sal_True);
720 InvalidateSlot(SID_FM_RECORD_TOTAL, sal_False);
721 LockSlotInvalidation(sal_False);
725 // this may be called from a non-main-thread so invalidate the shell asynchronously
726 LockSlotInvalidation(sal_True);
727 InvalidateSlot(0, 0); // special meaning : invalidate m_pShell
728 LockSlotInvalidation(sal_False);
731 //------------------------------------------------------------------------------
732 void FmXFormShell::invalidateFeatures( const ::std::vector< sal_Int32 >& _rFeatures )
734 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::invalidateFeatures" );
735 if ( impl_checkDisposed() )
736 return;
738 OSL_ENSURE( _rFeatures.size() > 0, "FmXFormShell::invalidateFeatures: invalid arguments!" );
740 if ( m_pShell->GetViewShell() && m_pShell->GetViewShell()->GetViewFrame() )
742 // unfortunately, SFX requires sal_uInt16
743 ::std::vector< sal_uInt16 > aSlotIds;
744 aSlotIds.reserve( _rFeatures.size() );
745 ::std::copy( _rFeatures.begin(),
746 _rFeatures.end(),
747 ::std::insert_iterator< ::std::vector< sal_uInt16 > >( aSlotIds, aSlotIds.begin() )
750 // furthermore, SFX wants a terminating 0
751 aSlotIds.push_back( 0 );
753 // and, last but not least, SFX wants the ids to be sorted
754 ::std::sort( aSlotIds.begin(), aSlotIds.end() - 1 );
756 sal_uInt16 *pSlotIds = aSlotIds.empty() ? 0 : &(aSlotIds[0]);
757 m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate( pSlotIds );
761 //------------------------------------------------------------------------------
762 void SAL_CALL FmXFormShell::formActivated(const EventObject& rEvent) throw( RuntimeException )
764 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::formActivated" );
765 if ( impl_checkDisposed() )
766 return;
768 Reference< XFormController > xController( rEvent.Source, UNO_QUERY_THROW );
769 m_pTextShell->formActivated( xController );
770 setActiveController( xController );
773 //------------------------------------------------------------------------------
774 void SAL_CALL FmXFormShell::formDeactivated(const EventObject& rEvent) throw( RuntimeException )
776 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::formDeactivated" );
777 if ( impl_checkDisposed() )
778 return;
780 Reference< XFormController > xController( rEvent.Source, UNO_QUERY_THROW );
781 m_pTextShell->formDeactivated( xController );
784 //------------------------------------------------------------------------------
785 void FmXFormShell::disposing()
787 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::disposing" );
788 OSL_TRACE( "--- FmXFormShell::disposing : %p, ........, ........\n", this );
789 impl_checkDisposed();
791 FmXFormShell_BASE::disposing();
793 if ( m_pShell && !m_pShell->IsDesignMode() )
794 setActiveController( NULL, sal_True );
795 // do NOT save the content of the old form (the second parameter tells this)
796 // if we're here, then we expect that PrepareClose has been called, and thus the user
797 // got a chance to commit or reject any changes. So in case we're here and there
798 // are still uncommitted changes, the user explicitly wanted this.
799 // 2002-11-11 - 104702 - fs@openoffice.org
801 // dispose our interceptor helpers
802 if (m_pExternalViewInterceptor)
804 m_pExternalViewInterceptor->dispose();
805 m_pExternalViewInterceptor->release();
806 m_pExternalViewInterceptor = NULL;
809 m_pTextShell->dispose();
811 m_xAttachedFrame = NULL;
813 CloseExternalFormViewer();
815 while ( m_aLoadingPages.size() )
817 Application::RemoveUserEvent( m_aLoadingPages.front().nEventId );
818 m_aLoadingPages.pop();
822 ::osl::MutexGuard aGuard(m_aInvalidationSafety);
823 if (m_nInvalidationEvent)
825 Application::RemoveUserEvent(m_nInvalidationEvent);
826 m_nInvalidationEvent = 0;
828 if ( m_nActivationEvent )
830 Application::RemoveUserEvent( m_nActivationEvent );
831 m_nActivationEvent = 0;
836 ::osl::ClearableMutexGuard aGuard(m_aAsyncSafety);
837 if (HasAnyPendingCursorAction())
838 CancelAnyPendingCursorAction();
839 aGuard.clear();
841 DBG_ASSERT(!m_nInvalidationEvent, "FmXFormShell::~FmXFormShell : still have an invalidation event !");
842 // should habe been deleted while beeing disposed
844 m_aMarkTimer.Stop();
847 DisableNotification();
849 RemoveElement( m_xForms );
850 m_xForms.clear();
852 impl_switchActiveControllerListening( false );
853 m_xActiveController = NULL;
854 m_xActiveForm = NULL;
856 m_pShell = NULL;
857 m_xNavigationController = NULL;
858 m_xCurrentForm = NULL;
859 m_xLastGridFound = NULL;
860 m_xAttachedFrame = NULL;
861 m_xExternalViewController = NULL;
862 m_xExtViewTriggerController = NULL;
863 m_xExternalDisplayedForm = NULL;
864 m_xLastGridFound = NULL;
866 InterfaceBag aEmpty;
867 m_aCurrentSelection.swap( aEmpty );
869 m_aActiveControllerFeatures.dispose();
870 m_aNavControllerFeatures.dispose();
873 //------------------------------------------------------------------------------
874 void FmXFormShell::UpdateSlot( sal_Int16 _nId )
876 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::UpdateSlot" );
877 if ( impl_checkDisposed() )
878 return;
880 ::osl::MutexGuard aGuard(m_aInvalidationSafety);
882 if ( m_nLockSlotInvalidation )
884 OSL_ENSURE( sal_False, "FmXFormShell::UpdateSlot: cannot update if invalidation is currently locked!" );
885 InvalidateSlot( _nId, sal_False );
887 else
889 OSL_ENSURE( _nId, "FmXFormShell::UpdateSlot: can't update the complete shell!" );
890 m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate( _nId, sal_True, sal_True );
891 m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Update( _nId );
895 //------------------------------------------------------------------------------
896 void FmXFormShell::InvalidateSlot( sal_Int16 nId, sal_Bool bWithId )
898 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::InvalidateSlot" );
899 if ( impl_checkDisposed() )
900 return;
902 ::osl::MutexGuard aGuard(m_aInvalidationSafety);
903 if (m_nLockSlotInvalidation)
905 m_arrInvalidSlots.Insert(nId, m_arrInvalidSlots.Count());
906 BYTE nFlags = ( bWithId ? 0x01 : 0 );
907 m_arrInvalidSlots_Flags.Insert(nFlags, m_arrInvalidSlots_Flags.Count());
909 else
910 if (nId)
911 m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(nId, sal_True, bWithId);
912 else
913 m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell);
916 //------------------------------------------------------------------------------
917 void FmXFormShell::LockSlotInvalidation(sal_Bool bLock)
919 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::LockSlotInvalidation" );
920 if ( impl_checkDisposed() )
921 return;
923 ::osl::MutexGuard aGuard(m_aInvalidationSafety);
924 DBG_ASSERT(bLock || m_nLockSlotInvalidation>0, "FmXFormShell::LockSlotInvalidation : invalid call !");
926 if (bLock)
927 ++m_nLockSlotInvalidation;
928 else if (!--m_nLockSlotInvalidation)
930 // alles, was sich waehrend der gelockten Phase angesammelt hat, (asynchron) invalidieren
931 if (!m_nInvalidationEvent)
932 m_nInvalidationEvent = Application::PostUserEvent(LINK(this, FmXFormShell, OnInvalidateSlots));
936 //------------------------------------------------------------------------------
937 IMPL_LINK(FmXFormShell, OnInvalidateSlots, void*, EMPTYARG)
939 if ( impl_checkDisposed() )
940 return 0L;
942 ::osl::MutexGuard aGuard(m_aInvalidationSafety);
943 m_nInvalidationEvent = 0;
945 DBG_ASSERT(m_arrInvalidSlots.Count() == m_arrInvalidSlots_Flags.Count(),
946 "FmXFormShell::OnInvalidateSlots : inconsistent slot arrays !");
947 BYTE nFlags;
948 for (sal_Int16 i=0; i<m_arrInvalidSlots.Count(); ++i)
950 nFlags = m_arrInvalidSlots_Flags[i];
952 if (m_arrInvalidSlots[i])
953 m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(m_arrInvalidSlots[i], sal_True, (nFlags & 0x01));
954 else
955 m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell);
958 m_arrInvalidSlots.Remove(0, m_arrInvalidSlots.Count());
959 m_arrInvalidSlots_Flags.Remove(0, m_arrInvalidSlots_Flags.Count());
960 return 0L;
963 //------------------------------------------------------------------------------
964 void FmXFormShell::ForceUpdateSelection(sal_Bool bAllowInvalidation)
966 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ForceUpdateSelection" );
967 if ( impl_checkDisposed() )
968 return;
970 if (IsSelectionUpdatePending())
972 m_aMarkTimer.Stop();
974 // die Invalidierung der Slots, die implizit von SetSelection besorgt wird, eventuell abschalten
975 if (!bAllowInvalidation)
976 LockSlotInvalidation(sal_True);
978 SetSelection(m_pShell->GetFormView()->GetMarkedObjectList());
980 if (!bAllowInvalidation)
981 LockSlotInvalidation(sal_False);
985 //------------------------------------------------------------------------------
986 PopupMenu* FmXFormShell::GetConversionMenu()
988 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::GetConversionMenu" );
989 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
990 BOOL bIsHiContrastMode = rSettings.GetMenuColor().IsDark();
992 PopupMenu* pNewMenu = new PopupMenu(SVX_RES( RID_FMSHELL_CONVERSIONMENU ));
994 ImageList aImageList( SVX_RES( bIsHiContrastMode ? RID_SVXIMGLIST_FMEXPL_HC : RID_SVXIMGLIST_FMEXPL) );
995 for ( size_t i = 0; i < sizeof( nConvertSlots ) / sizeof( nConvertSlots[0] ); ++i )
997 // das entsprechende Image dran
998 pNewMenu->SetItemImage(nConvertSlots[i], aImageList.GetImage(nCreateSlots[i]));
1001 return pNewMenu;
1004 //------------------------------------------------------------------------------
1005 bool FmXFormShell::isControlConversionSlot( sal_uInt16 nSlotId )
1007 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::isControlConversionSlot" );
1008 for ( size_t i = 0; i < sizeof( nConvertSlots ) / sizeof( nConvertSlots[0] ); ++i )
1009 if (nConvertSlots[i] == nSlotId)
1010 return true;
1011 return false;
1014 //------------------------------------------------------------------------------
1015 bool FmXFormShell::executeControlConversionSlot( sal_uInt16 _nSlotId )
1017 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::executeControlConversionSlot" );
1018 OSL_PRECOND( canConvertCurrentSelectionToControl( _nSlotId ), "FmXFormShell::executeControlConversionSlot: illegal call!" );
1019 InterfaceBag::const_iterator aSelectedElement = m_aCurrentSelection.begin();
1020 if ( aSelectedElement == m_aCurrentSelection.end() )
1021 return false;
1023 return executeControlConversionSlot( Reference< XFormComponent >( *aSelectedElement, UNO_QUERY ), _nSlotId );
1026 //------------------------------------------------------------------------------
1027 bool FmXFormShell::executeControlConversionSlot( const Reference< XFormComponent >& _rxObject, sal_uInt16 _nSlotId )
1029 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::executeControlConversionSlot" );
1030 if ( impl_checkDisposed() )
1031 return false;
1033 OSL_ENSURE( _rxObject.is(), "FmXFormShell::executeControlConversionSlot: invalid object!" );
1034 if ( !_rxObject.is() )
1035 return false;
1037 SdrPage* pPage = m_pShell->GetCurPage();
1038 FmFormPage* pFormPage = pPage ? dynamic_cast< FmFormPage* >( pPage ) : NULL;
1039 OSL_ENSURE( pFormPage, "FmXFormShell::executeControlConversionSlot: no current (form) page!" );
1040 if ( !pFormPage )
1041 return false;
1043 OSL_ENSURE( isSolelySelected( _rxObject ),
1044 "FmXFormShell::executeControlConversionSlot: hmm ... shouldn't this parameter be redundant?" );
1046 for ( size_t lookupSlot = 0; lookupSlot < sizeof( nConvertSlots ) / sizeof( nConvertSlots[0] ); ++lookupSlot )
1048 if (nConvertSlots[lookupSlot] == _nSlotId)
1050 Reference< XInterface > xNormalizedObject( _rxObject, UNO_QUERY );
1052 FmFormObj* pFormObject = NULL;
1053 SdrObjListIter aPageIter( *pFormPage );
1054 while ( aPageIter.IsMore() )
1056 SdrObject* pCurrent = aPageIter.Next();
1057 pFormObject = FmFormObj::GetFormObject( pCurrent );
1058 if ( !pFormObject )
1059 continue;
1061 Reference< XInterface > xCurrentNormalized( pFormObject->GetUnoControlModel(), UNO_QUERY );
1062 if ( xCurrentNormalized.get() == xNormalizedObject.get() )
1063 break;
1065 pFormObject = NULL;
1068 if ( !pFormObject )
1069 return false;
1071 ::rtl::OUString sNewName( getServiceNameByControlType( nObjectTypes[ lookupSlot ] ) );
1072 Reference< XControlModel> xNewModel( ::comphelper::getProcessServiceFactory()->createInstance( sNewName ), UNO_QUERY );
1073 if (!xNewModel.is())
1074 return false;
1076 Reference< XControlModel> xOldModel( pFormObject->GetUnoControlModel() );
1077 Reference< XServiceInfo> xModelInfo(xOldModel, UNO_QUERY);
1079 // Properties uebertragen
1080 Reference< XPropertySet> xOldSet(xOldModel, UNO_QUERY);
1081 Reference< XPropertySet> xNewSet(xNewModel, UNO_QUERY);
1084 Locale aNewLanguage = Application::GetSettings().GetUILocale();
1085 TransferFormComponentProperties(xOldSet, xNewSet, aNewLanguage);
1087 Sequence< ::com::sun::star::script::ScriptEventDescriptor> aOldScripts;
1088 Reference< XChild> xChild(xOldModel, UNO_QUERY);
1089 if (xChild.is())
1091 Reference< XIndexAccess> xParent(xChild->getParent(), UNO_QUERY);
1093 // remember old script events
1094 Reference< ::com::sun::star::script::XEventAttacherManager> xEvManager(xChild->getParent(), UNO_QUERY);
1095 if (xParent.is() && xEvManager.is())
1097 sal_Int32 nIndex = getElementPos(xParent, xOldModel);
1098 if (nIndex>=0 && nIndex<xParent->getCount())
1099 aOldScripts = xEvManager->getScriptEvents(nIndex);
1102 // replace the mdoel within the parent container
1103 Reference< XIndexContainer> xIndexParent(xChild->getParent(), UNO_QUERY); //Modified by BerryJia for fixing Bug102516 Time(China):2002-9-5 16:00
1104 if (xIndexParent.is())
1106 // the form container works with FormComponents
1107 Reference< XFormComponent> xComponent(xNewModel, UNO_QUERY);
1108 DBG_ASSERT(xComponent.is(), "FmXFormShell::executeControlConversionSlot: the new model is no form component !");
1109 Any aNewModel(makeAny(xComponent));
1112 //Modified by BerryJia for fixing Bug102516 Time(China):2002-9-5 16:00
1113 sal_Int32 nIndex = getElementPos(xParent, xOldModel);
1114 if (nIndex>=0 && nIndex<xParent->getCount())
1115 xIndexParent->replaceByIndex(nIndex, aNewModel);
1116 else
1118 DBG_ERROR("FmXFormShell::executeControlConversionSlot: could not replace the model !");
1119 Reference< ::com::sun::star::lang::XComponent> xNewComponent(xNewModel, UNO_QUERY);
1120 if (xNewComponent.is())
1121 xNewComponent->dispose();
1122 return false;
1125 catch(Exception&)
1127 DBG_ERROR("FmXFormShell::executeControlConversionSlot: could not replace the model !");
1128 Reference< ::com::sun::star::lang::XComponent> xNewComponent(xNewModel, UNO_QUERY);
1129 if (xNewComponent.is())
1130 xNewComponent->dispose();
1131 return false;
1137 // special handling for the LabelControl-property : can only be set when the model is placed
1138 // within the forms hierarchy
1139 if (::comphelper::hasProperty(FM_PROP_CONTROLLABEL, xOldSet) && ::comphelper::hasProperty(FM_PROP_CONTROLLABEL, xNewSet))
1143 xNewSet->setPropertyValue(FM_PROP_CONTROLLABEL, xOldSet->getPropertyValue(FM_PROP_CONTROLLABEL));
1145 catch(Exception&)
1151 // neues Model setzen
1152 pFormObject->SetChanged();
1153 pFormObject->SetUnoControlModel(xNewModel);
1155 // transfer script events
1156 // (do this _after_ SetUnoControlModel as we need the new (implicitly created) control)
1157 if (aOldScripts.getLength())
1159 // das Control zum Model suchen
1160 Reference< XControlContainer > xControlContainer( getControlContainerForView() );
1162 Sequence< Reference< XControl> > aControls( xControlContainer->getControls() );
1163 const Reference< XControl>* pControls = aControls.getConstArray();
1165 sal_uInt32 nLen = aControls.getLength();
1166 Reference< XControl> xControl;
1167 for (sal_uInt32 i=0 ; i<nLen; ++i)
1169 if (pControls[i]->getModel() == xNewModel)
1171 xControl = pControls[i];
1172 break;
1175 TransferEventScripts(xNewModel, xControl, aOldScripts);
1178 // transfer value bindings, if possible
1180 Reference< XBindableValue > xOldBindable( xOldModel, UNO_QUERY );
1181 Reference< XBindableValue > xNewBindable( xNewModel, UNO_QUERY );
1182 if ( xOldBindable.is() )
1186 if ( xNewBindable.is() )
1187 xNewBindable->setValueBinding( xOldBindable->getValueBinding() );
1188 xOldBindable->setValueBinding( NULL );
1190 catch(const Exception&)
1192 DBG_UNHANDLED_EXCEPTION();
1196 // same for list entry sources
1198 Reference< XListEntrySink > xOldSink( xOldModel, UNO_QUERY );
1199 Reference< XListEntrySink > xNewSink( xNewModel, UNO_QUERY );
1200 if ( xOldSink.is() )
1204 if ( xNewSink.is() )
1205 xNewSink->setListEntrySource( xOldSink->getListEntrySource() );
1206 xOldSink->setListEntrySource( NULL );
1208 catch(const Exception&)
1210 DBG_UNHANDLED_EXCEPTION();
1215 // create an undo action
1216 FmFormModel* pModel = m_pShell->GetFormModel();
1217 DBG_ASSERT(pModel != NULL, "FmXFormShell::executeControlConversionSlot: my shell has no model !");
1218 if (pModel && pModel->IsUndoEnabled() )
1220 pModel->AddUndo(new FmUndoModelReplaceAction(*pModel, pFormObject, xOldModel));
1222 else
1224 FmUndoModelReplaceAction::DisposeElement( xOldModel );
1227 return true;
1230 return false;
1233 //------------------------------------------------------------------------------
1234 bool FmXFormShell::canConvertCurrentSelectionToControl( sal_Int16 nConversionSlot )
1236 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::canConvertCurrentSelectionToControl" );
1237 if ( m_aCurrentSelection.empty() )
1238 return false;
1240 InterfaceBag::const_iterator aCheck = m_aCurrentSelection.begin();
1241 Reference< XServiceInfo > xElementInfo( *aCheck, UNO_QUERY );
1242 if ( !xElementInfo.is() )
1243 // no service info -> cannot determine this
1244 return false;
1246 if ( ++aCheck != m_aCurrentSelection.end() )
1247 // more than one element
1248 return false;
1250 if ( Reference< XForm >::query( xElementInfo ).is() )
1251 // it's a form
1252 return false;
1254 sal_Int16 nObjectType = getControlTypeByObject( xElementInfo );
1256 if ( ( OBJ_FM_HIDDEN == nObjectType )
1257 || ( OBJ_FM_CONTROL == nObjectType )
1258 || ( OBJ_FM_GRID == nObjectType )
1260 return false; // those types cannot be converted
1262 DBG_ASSERT(sizeof(nConvertSlots)/sizeof(nConvertSlots[0]) == sizeof(nObjectTypes)/sizeof(nObjectTypes[0]),
1263 "FmXFormShell::canConvertCurrentSelectionToControl: nConvertSlots & nObjectTypes must have the same size !");
1265 for ( size_t i = 0; i < sizeof( nConvertSlots ) / sizeof( nConvertSlots[0] ); ++i )
1266 if (nConvertSlots[i] == nConversionSlot)
1267 return nObjectTypes[i] != nObjectType;
1269 return sal_True; // all other slots: assume "yes"
1272 //------------------------------------------------------------------------------
1273 void FmXFormShell::checkControlConversionSlotsForCurrentSelection( Menu& rMenu )
1275 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::checkControlConversionSlotsForCurrentSelection" );
1276 for (sal_Int16 i=0; i<rMenu.GetItemCount(); ++i)
1277 // der Context ist schon von einem Typ, der dem Eitnrag entspricht -> disable
1278 rMenu.EnableItem( rMenu.GetItemId(i), canConvertCurrentSelectionToControl( rMenu.GetItemId( i ) ) );
1281 //------------------------------------------------------------------------------
1282 void FmXFormShell::LoopGrids(sal_Int16 nWhat)
1284 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::LoopGrids" );
1285 if ( impl_checkDisposed() )
1286 return;
1288 Reference< XIndexContainer> xControlModels(m_xActiveForm, UNO_QUERY);
1289 if (xControlModels.is())
1291 for (sal_Int16 i=0; i<xControlModels->getCount(); ++i)
1293 Reference< XPropertySet> xModelSet;
1294 xControlModels->getByIndex(i) >>= xModelSet;
1295 if (!xModelSet.is())
1296 continue;
1298 if (!::comphelper::hasProperty(FM_PROP_CLASSID, xModelSet))
1299 continue;
1300 sal_Int16 nClassId = ::comphelper::getINT16(xModelSet->getPropertyValue(FM_PROP_CLASSID));
1301 if (FormComponentType::GRIDCONTROL != nClassId)
1302 continue;
1304 if (!::comphelper::hasProperty(FM_PROP_CURSORCOLOR, xModelSet) || !::comphelper::hasProperty(FM_PROP_ALWAYSSHOWCURSOR, xModelSet) || !::comphelper::hasProperty(FM_PROP_DISPLAYSYNCHRON, xModelSet))
1305 continue;
1307 switch (nWhat & GA_SYNC_MASK)
1309 case GA_DISABLE_SYNC:
1311 sal_Bool bB(sal_False);
1312 xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(&bB,getBooleanCppuType()));
1314 break;
1315 case GA_FORCE_SYNC:
1317 Any aOldVal( xModelSet->getPropertyValue(FM_PROP_DISPLAYSYNCHRON) );
1318 sal_Bool bB(sal_True);
1319 xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(&bB,getBooleanCppuType()));
1320 xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, aOldVal);
1322 break;
1323 case GA_ENABLE_SYNC:
1325 sal_Bool bB(sal_True);
1326 xModelSet->setPropertyValue(FM_PROP_DISPLAYSYNCHRON, Any(&bB,getBooleanCppuType()));
1328 break;
1331 if (nWhat & GA_DISABLE_ROCTRLR)
1333 sal_Bool bB(sal_False);
1334 xModelSet->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR, Any(&bB,getBooleanCppuType()));
1335 Reference< XPropertyState> xModelPropState(xModelSet, UNO_QUERY);
1336 if (xModelPropState.is())
1337 xModelPropState->setPropertyToDefault(FM_PROP_CURSORCOLOR);
1338 else
1339 xModelSet->setPropertyValue(FM_PROP_CURSORCOLOR, Any()); // this should be the default
1341 else if (nWhat & GA_ENABLE_ROCTRLR)
1343 sal_Bool bB(sal_True);
1344 xModelSet->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR, Any(&bB,getBooleanCppuType()));
1345 xModelSet->setPropertyValue(FM_PROP_CURSORCOLOR, makeAny(sal_Int32(COL_LIGHTRED)));
1351 //------------------------------------------------------------------------------
1352 Reference< XControlContainer > FmXFormShell::getControlContainerForView()
1354 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getControlContainerForView" );
1355 if ( impl_checkDisposed() )
1356 return NULL;
1358 SdrPageView* pPageView = NULL;
1359 if ( m_pShell && m_pShell->GetFormView() )
1360 pPageView = m_pShell->GetFormView()->GetSdrPageView();
1362 Reference< XControlContainer> xControlContainer;
1363 if ( pPageView )
1364 xControlContainer = pPageView->GetPageWindow(0)->GetControlContainer();
1366 return xControlContainer;
1369 //------------------------------------------------------------------------------
1370 void FmXFormShell::ExecuteTabOrderDialog( const Reference< XTabControllerModel >& _rxForForm )
1372 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ExecuteTabOrderDialog" );
1373 if ( impl_checkDisposed() )
1374 return;
1376 OSL_PRECOND( _rxForForm.is(), "FmXFormShell::ExecuteTabOrderDialog: invalid tabbing model!" );
1377 if ( !_rxForForm.is() )
1378 return;
1382 Sequence< Any > aDialogArgs( 3 );
1383 aDialogArgs[0] <<= NamedValue(
1384 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TabbingModel" ) ),
1385 makeAny( _rxForForm )
1387 aDialogArgs[1] <<= NamedValue(
1388 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ControlContext" ) ),
1389 makeAny( getControlContainerForView() )
1392 Reference< XWindow > xParentWindow;
1393 if ( m_pShell->GetViewShell() && m_pShell->GetViewShell()->GetViewFrame() )
1394 xParentWindow = VCLUnoHelper::GetInterface ( &m_pShell->GetViewShell()->GetViewFrame()->GetWindow() );
1395 aDialogArgs[2] <<= NamedValue(
1396 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ParentWindow" ) ),
1397 makeAny( xParentWindow )
1400 Reference< dialogs::XExecutableDialog > xDialog(
1401 ::comphelper::getProcessServiceFactory()->createInstanceWithArguments(
1402 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.form.ui.TabOrderDialog" ) ),
1403 aDialogArgs
1405 UNO_QUERY
1407 OSL_ENSURE( xDialog.is(), "FmXFormShell::ExecuteTabOrderDialog: could not create the dialog!" );
1409 if ( xDialog.is() )
1410 xDialog->execute();
1412 catch( const Exception& )
1414 OSL_ENSURE( sal_False, "FmXFormShell::ExecuteTabOrderDialog: caught an exception!" );
1418 //------------------------------------------------------------------------------
1419 void FmXFormShell::ExecuteSearch()
1421 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ExecuteSearch" );
1422 if ( impl_checkDisposed() )
1423 return;
1425 // eine Sammlung aller (logischen) Formulare
1426 FmFormArray aEmpty;
1427 m_aSearchForms.swap( aEmpty );
1428 ::std::vector< String > aContextNames;
1429 impl_collectFormSearchContexts_nothrow( m_pShell->GetCurPage()->GetForms(), ::rtl::OUString(), m_aSearchForms, aContextNames );
1430 OSL_POSTCOND( m_aSearchForms.size() == aContextNames.size(),
1431 "FmXFormShell::ExecuteSearch: nonsense!" );
1432 if ( m_aSearchForms.size() != aContextNames.size() )
1433 return;
1435 // filter out the forms which do not contain valid controls at all
1436 FmFormArray::reverse_iterator form = m_aSearchForms.rbegin();
1437 ::std::vector< String >::reverse_iterator contextName = aContextNames.rbegin();
1438 sal_Int32 i = m_aSearchForms.size();
1439 for ( ;
1440 form != m_aSearchForms.rend();
1441 ++form, ++contextName, --i
1444 FmSearchContext aTestContext;
1445 aTestContext.nContext = static_cast< sal_Int16 >( i-1 );
1446 sal_uInt32 nValidControls = OnSearchContextRequest( &aTestContext );
1447 if ( nValidControls == 0 )
1449 m_aSearchForms.erase( form.base() - 1 );
1450 aContextNames.erase( contextName.base() - 1 );
1454 if (m_aSearchForms.size() == 0)
1455 { // es gibt keine Controls, die alle Bedingungen fuer eine Suche erfuellen
1456 ErrorBox(NULL, WB_OK, SVX_RESSTR(RID_STR_NODATACONTROLS)).Execute();
1457 return;
1460 // jetzt brauche ich noch einen 'initial context'
1461 sal_Int16 nInitialContext = 0;
1462 Reference< XForm> xActiveForm( getActiveForm());
1463 for (i=0; i<(sal_Int32)m_aSearchForms.size(); ++i)
1465 if (m_aSearchForms.at(i) == xActiveForm)
1467 nInitialContext = (sal_Int16)i;
1468 break;
1472 // wenn der Dialog initial den Text des aktiven Controls anbieten soll, muss dieses ein XTextComponent-Interface habe,
1473 // ausserdem macht das nur Sinn, wenn das aktuelle Feld auch an ein Tabellen- (oder was-auch-immer-)Feld gebunden ist
1474 UniString strActiveField;
1475 UniString strInitialText;
1476 // ... das bekomme ich von meinem FormController
1477 DBG_ASSERT(m_xActiveController.is(), "FmXFormShell::ExecuteSearch : no active controller !");
1478 Reference< XControl> xActiveControl( m_xActiveController->getCurrentControl());
1479 if (xActiveControl.is())
1481 // das Control kann mir sein Model sagen ...
1482 Reference< XControlModel> xActiveModel( xActiveControl->getModel());
1483 DBG_ASSERT(xActiveModel.is(), "FmXFormShell::ExecuteSearch : active control has no model !");
1485 // das Model frage ich nach der ControlSource-Eigenschaft ...
1486 Reference< XPropertySet> xProperties(xActiveControl->getModel(), UNO_QUERY);
1487 if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCE, xProperties) && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xProperties))
1489 Reference< XPropertySet> xField;
1490 xProperties->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
1491 if (xField.is()) // (nur wenn das Ding wirklich gebunden ist)
1493 // und das Control selber nach einem TextComponent-Interface (damit ich mir dort den Text abholen kann)
1494 Reference< XTextComponent> xText(xActiveControl, UNO_QUERY);
1495 if (xText.is())
1497 strActiveField = getLabelName(xProperties).getStr();
1498 strInitialText = xText->getText().getStr();
1502 else
1504 // das Control selber hat keine ControlSource, aber vielleicht ist es ein GridControl
1505 Reference< XGrid> xGrid(xActiveControl, UNO_QUERY);
1506 if (xGrid.is())
1508 // fuer strActiveField brauche ich die die ControlSource der Column, dafuer den Columns-Container, dafuer die
1509 // GridPeer
1510 Reference< XGridPeer> xGridPeer(xActiveControl->getPeer(), UNO_QUERY);
1511 Reference< XIndexAccess> xColumns;
1512 if (xGridPeer.is())
1513 xColumns = Reference< XIndexAccess>(xGridPeer->getColumns(),UNO_QUERY);
1515 sal_Int16 nViewCol = xGrid->getCurrentColumnPosition();
1516 sal_Int16 nModelCol = GridView2ModelPos(xColumns, nViewCol);
1517 Reference< XPropertySet> xCurrentCol;
1518 if(xColumns.is())
1519 xColumns->getByIndex(nModelCol) >>= xCurrentCol;
1520 if (xCurrentCol.is())
1521 strActiveField = ::comphelper::getString(xCurrentCol->getPropertyValue(FM_PROP_LABEL)).getStr();
1523 // the text fo the current column
1524 Reference< XIndexAccess> xColControls(xGridPeer, UNO_QUERY);
1525 Reference< XInterface> xCurControl;
1526 xColControls->getByIndex(nViewCol) >>= xCurControl;
1527 ::rtl::OUString sInitialText;
1528 if (IsSearchableControl(xCurControl, &sInitialText))
1529 strInitialText = sInitialText.getStr();
1534 // um eventuelle GridControls, die ich kenne, kuemmern
1535 LoopGrids(GA_DISABLE_SYNC /*| GA_ENABLE_ROCTRLR*/);
1537 // jetzt bin ich reif fuer den Dialog
1538 // wenn die potentiellen Deadlocks, die durch die Benutzung des Solar-Mutex in MTs VCLX...-Klasen entstehen, irgendwann mal
1539 // ausgeraeumt sind, sollte hier ein SM_USETHREAD rein, denn die Suche in einem eigenen Thread ist doch etwas fluessiger
1540 // sollte allerdings irgendwie von dem unterliegenden Cursor abhaengig gemacht werden, DAO zum Beispiel ist nicht thread-sicher
1541 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
1542 AbstractFmSearchDialog* pDialog = NULL;
1543 if ( pFact )
1544 pDialog = pFact->CreateFmSearchDialog( &m_pShell->GetViewShell()->GetViewFrame()->GetWindow(), strInitialText, aContextNames, nInitialContext, LINK( this, FmXFormShell, OnSearchContextRequest ) );
1545 DBG_ASSERT( pDialog, "FmXFormShell::ExecuteSearch: could not create the search dialog!" );
1546 if ( pDialog )
1548 pDialog->SetActiveField( strActiveField );
1549 pDialog->SetFoundHandler( LINK( this, FmXFormShell, OnFoundData ) );
1550 pDialog->SetCanceledNotFoundHdl( LINK( this, FmXFormShell, OnCanceledNotFound ) );
1551 pDialog->Execute();
1552 delete pDialog;
1555 // GridControls wieder restaurieren
1556 LoopGrids(GA_ENABLE_SYNC | GA_DISABLE_ROCTRLR);
1558 m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView());
1559 // da ich in OnFoundData (fals ich dort war) Controls markiert habe
1562 //------------------------------------------------------------------------------
1563 sal_Bool FmXFormShell::GetY2KState(sal_uInt16& n)
1565 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::GetY2KState" );
1566 if ( impl_checkDisposed() )
1567 return sal_False;
1569 if (m_pShell->IsDesignMode())
1570 // im Design-Modus (ohne aktive Controls) soll sich das Haupt-Dokument darum kuemmern
1571 return sal_False;
1573 Reference< XForm> xForm( getActiveForm());
1574 if (!xForm.is())
1575 // kein aktuelles Formular (also insbesondere kein aktuelles Control) -> das Haupt-Dokument soll sich kuemmern
1576 return sal_False;
1578 Reference< XRowSet> xDB(xForm, UNO_QUERY);
1579 DBG_ASSERT(xDB.is(), "FmXFormShell::GetY2KState : current form has no dbform-interface !");
1581 Reference< XNumberFormatsSupplier> xSupplier( getNumberFormats(OStaticDataAccessTools().getRowSetConnection(xDB), sal_False));
1582 if (xSupplier.is())
1584 Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings());
1585 if (xSet.is())
1589 Any aVal( xSet->getPropertyValue(::rtl::OUString::createFromAscii("TwoDigitDateStart")) );
1590 aVal >>= n;
1591 return sal_True;
1593 catch(Exception&)
1599 return sal_False;
1602 //------------------------------------------------------------------------------
1603 void FmXFormShell::SetY2KState(sal_uInt16 n)
1605 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetY2KState" );
1606 if ( impl_checkDisposed() )
1607 return;
1609 Reference< XForm > xActiveForm( getActiveForm());
1610 Reference< XRowSet > xActiveRowSet( xActiveForm, UNO_QUERY );
1611 if ( xActiveRowSet.is() )
1613 Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( getRowSetConnection( xActiveRowSet ), sal_False ) );
1614 if (xSupplier.is())
1616 Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings());
1617 if (xSet.is())
1621 Any aVal;
1622 aVal <<= n;
1623 xSet->setPropertyValue(::rtl::OUString::createFromAscii("TwoDigitDateStart"), aVal);
1625 catch(Exception&)
1627 DBG_ERROR("FmXFormShell::SetY2KState: Exception occured!");
1631 return;
1635 // kein aktives Formular gefunden -> alle aktuell vorhandenen Formulare durchiterieren
1636 Reference< XIndexAccess> xCurrentForms( m_xForms);
1637 if (!xCurrentForms.is())
1638 { // im alive-Modus sind meine Forms nicht gesetzt, wohl aber die an der Page
1639 if (m_pShell->GetCurPage())
1640 xCurrentForms = Reference< XIndexAccess>( m_pShell->GetCurPage()->GetForms( false ), UNO_QUERY );
1642 if (!xCurrentForms.is())
1643 return;
1645 ::comphelper::IndexAccessIterator aIter(xCurrentForms);
1646 Reference< XInterface> xCurrentElement( aIter.Next());
1647 while (xCurrentElement.is())
1649 // ist das aktuelle Element eine DatabaseForm ?
1650 Reference< XRowSet> xElementAsRowSet( xCurrentElement, UNO_QUERY );
1651 if ( xElementAsRowSet.is() )
1653 Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( getRowSetConnection( xElementAsRowSet ), sal_False ) );
1654 if (!xSupplier.is())
1655 continue;
1657 Reference< XPropertySet> xSet(xSupplier->getNumberFormatSettings());
1658 if (xSet.is())
1662 Any aVal;
1663 aVal <<= n;
1664 xSet->setPropertyValue(::rtl::OUString::createFromAscii("TwoDigitDateStart"), aVal);
1666 catch(Exception&)
1668 DBG_ERROR("FmXFormShell::SetY2KState: Exception occured!");
1673 xCurrentElement = aIter.Next();
1677 //------------------------------------------------------------------------------
1678 void FmXFormShell::CloseExternalFormViewer()
1680 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::CloseExternalFormViewer" );
1681 if ( impl_checkDisposed() )
1682 return;
1684 if (!m_xExternalViewController.is())
1685 return;
1687 Reference< ::com::sun::star::frame::XFrame> xExternalViewFrame( m_xExternalViewController->getFrame());
1688 Reference< ::com::sun::star::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY);
1689 if (!xCommLink.is())
1690 return;
1692 xExternalViewFrame->setComponent(NULL,NULL);
1693 ::comphelper::disposeComponent(xExternalViewFrame);
1694 m_xExternalViewController = NULL;
1695 m_xExtViewTriggerController = NULL;
1696 m_xExternalDisplayedForm = NULL;
1699 //------------------------------------------------------------------------------
1700 Reference< XResultSet> FmXFormShell::getInternalForm(const Reference< XResultSet>& _xForm) const
1702 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getInternalForm" );
1703 if ( impl_checkDisposed() )
1704 return NULL;
1706 Reference< XFormController> xExternalCtrlr(m_xExternalViewController, UNO_QUERY);
1707 if (xExternalCtrlr.is() && (_xForm == xExternalCtrlr->getModel()))
1709 DBG_ASSERT(m_xExternalDisplayedForm.is(), "FmXFormShell::getInternalForm : invalid external form !");
1710 return m_xExternalDisplayedForm;
1712 return _xForm;
1715 //------------------------------------------------------------------------------
1716 Reference< XForm> FmXFormShell::getInternalForm(const Reference< XForm>& _xForm) const
1718 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getInternalForm" );
1719 if ( impl_checkDisposed() )
1720 return NULL;
1722 Reference< XFormController> xExternalCtrlr(m_xExternalViewController, UNO_QUERY);
1723 if (xExternalCtrlr.is() && (_xForm == xExternalCtrlr->getModel()))
1725 DBG_ASSERT(m_xExternalDisplayedForm.is(), "FmXFormShell::getInternalForm : invalid external form !");
1726 return Reference< XForm>(m_xExternalDisplayedForm, UNO_QUERY);
1728 return _xForm;
1731 //------------------------------------------------------------------------
1732 namespace
1734 static bool lcl_isNavigationRelevant( sal_Int32 _nWhich )
1736 return ( _nWhich == SID_FM_RECORD_FIRST )
1737 || ( _nWhich == SID_FM_RECORD_PREV )
1738 || ( _nWhich == SID_FM_RECORD_NEXT )
1739 || ( _nWhich == SID_FM_RECORD_LAST )
1740 || ( _nWhich == SID_FM_RECORD_NEW );
1744 //------------------------------------------------------------------------------
1745 bool FmXFormShell::IsFormSlotEnabled( sal_Int32 _nSlot, FeatureState* _pCompleteState )
1747 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::IsFormSlotEnabled" );
1748 const ::svx::ControllerFeatures& rController =
1749 lcl_isNavigationRelevant( _nSlot )
1750 ? getNavControllerFeatures()
1751 : getActiveControllerFeatures();
1753 if ( !_pCompleteState )
1754 return rController->isEnabled( _nSlot );
1756 rController->getState( _nSlot, *_pCompleteState );
1757 return _pCompleteState->Enabled;
1760 //------------------------------------------------------------------------------
1761 void FmXFormShell::ExecuteFormSlot( sal_Int32 _nSlot )
1763 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ExecuteFormSlot" );
1764 const ::svx::ControllerFeatures& rController =
1765 lcl_isNavigationRelevant( _nSlot )
1766 ? getNavControllerFeatures()
1767 : getActiveControllerFeatures();
1769 rController->execute( _nSlot );
1771 if ( _nSlot == SID_FM_RECORD_UNDO )
1773 // if we're doing an UNDO, *and* if the affected form is the form which we also display
1774 // as external view, then we need to reset the controls of the external form, too
1775 if ( getInternalForm( getActiveForm() ) == m_xExternalDisplayedForm )
1777 Reference< XIndexAccess > xContainer( m_xExternalDisplayedForm, UNO_QUERY );
1778 if ( xContainer.is() )
1780 Reference< XReset > xReset;
1781 for ( sal_Int32 i = 0; i < xContainer->getCount(); ++i )
1783 if ( ( xContainer->getByIndex( i ) >>= xReset ) && xReset.is() )
1785 // no resets on sub forms
1786 Reference< XForm > xAsForm( xReset, UNO_QUERY );
1787 if ( !xAsForm.is() )
1788 xReset->reset();
1796 //------------------------------------------------------------------------------
1797 void FmXFormShell::impl_switchActiveControllerListening( const bool _bListen )
1799 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::impl_switchActiveControllerListening" );
1800 Reference< XComponent> xComp( m_xActiveController, UNO_QUERY );
1801 if ( !xComp.is() )
1802 return;
1804 if ( _bListen )
1805 xComp->addEventListener( (XFormControllerListener*)this );
1806 else
1807 xComp->removeEventListener( (XFormControllerListener*)this );
1810 //------------------------------------------------------------------------------
1811 void FmXFormShell::setActiveController( const Reference< XFormController>& xController, sal_Bool _bNoSaveOldContent )
1813 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::setActiveController" );
1814 if ( impl_checkDisposed() )
1815 return;
1817 if (m_bChangingDesignMode)
1818 return;
1819 DBG_ASSERT(!m_pShell->IsDesignMode(), "nur im alive mode verwenden");
1821 // Ist die Routine ein zweites Mal gerufen worden,
1822 // dann sollte der Focus nicht mehr umgesetzt werden
1823 if (m_bInActivate)
1825 m_bSetFocus = xController != m_xActiveController;
1826 return;
1829 if (xController != m_xActiveController)
1831 // if there is a async cursor action running we have to restore the locking state of the controls of the old controller
1832 if (HasPendingCursorAction(Reference< XResultSet>(m_xActiveForm, UNO_QUERY)))
1833 restoreControlLocks();
1835 ::osl::ClearableMutexGuard aGuard(m_aAsyncSafety);
1836 // switch all nav dispatchers belonging to the form of the current nav controller to 'non active'
1837 Reference< XResultSet> xNavigationForm;
1838 if (m_xNavigationController.is())
1839 xNavigationForm = Reference< XResultSet>(m_xNavigationController->getModel(), UNO_QUERY);
1840 aGuard.clear();
1842 m_bInActivate = sal_True;
1844 // check if the 2 controllers serve different forms
1845 Reference< XResultSet> xOldForm;
1846 if (m_xActiveController.is())
1847 xOldForm = Reference< XResultSet>(m_xActiveController->getModel(), UNO_QUERY);
1848 Reference< XResultSet> xNewForm;
1849 if (xController.is())
1850 xNewForm = Reference< XResultSet>(xController->getModel(), UNO_QUERY);
1851 xOldForm = getInternalForm(xOldForm);
1852 xNewForm = getInternalForm(xNewForm);
1854 sal_Bool bDifferentForm = ( xOldForm.get() != xNewForm.get() );
1855 sal_Bool bNeedSave = bDifferentForm && !_bNoSaveOldContent;
1856 // we save the content of the old form if we move to a new form, and saving old content is allowed
1858 if ( m_xActiveController.is() && bNeedSave )
1860 // beim Wechsel des Controllers den Inhalt speichern, ein Commit
1861 // wurde bereits ausgefuehrt
1862 if ( m_aActiveControllerFeatures->commitCurrentControl() )
1864 m_bSetFocus = sal_True;
1865 if ( m_aActiveControllerFeatures->isModifiedRow() )
1867 sal_Bool bIsNew = m_aActiveControllerFeatures->isInsertionRow();
1868 sal_Bool bResult = m_aActiveControllerFeatures->commitCurrentRecord();
1869 if ( !bResult && m_bSetFocus )
1871 // if we couldn't save the current record, set the focus back to the
1872 // current control
1873 Reference< XWindow > xWindow( m_xActiveController->getCurrentControl(), UNO_QUERY );
1874 if ( xWindow.is() )
1875 xWindow->setFocus();
1876 m_bInActivate = sal_False;
1877 return;
1879 else if ( bResult && bIsNew )
1881 Reference< XResultSet > xCursor( m_aActiveControllerFeatures->getCursor().get() );
1882 if ( xCursor.is() )
1884 DO_SAFE( xCursor->last(); );
1891 stopListening();
1893 impl_switchActiveControllerListening( false );
1895 m_aActiveControllerFeatures.dispose();
1896 m_xActiveController = xController;
1897 if ( m_xActiveController.is() )
1898 m_aActiveControllerFeatures.assign( m_xActiveController );
1900 impl_switchActiveControllerListening( true );
1902 if ( m_xActiveController.is() )
1903 m_xActiveForm = getInternalForm( Reference< XForm >( m_xActiveController->getModel(), UNO_QUERY ) );
1904 else
1905 m_xActiveForm = NULL;
1907 startListening();
1909 // activate all dispatchers belonging to form of the new navigation controller
1910 xNavigationForm = NULL;
1911 if (m_xNavigationController.is())
1912 xNavigationForm = Reference< XResultSet>(m_xNavigationController->getModel(), UNO_QUERY);
1914 // if there is a async cursor action running we have to lock the controls of the new controller
1915 if (HasPendingCursorAction(Reference< XResultSet>(m_xActiveForm, UNO_QUERY)))
1916 setControlLocks();
1918 m_bInActivate = sal_False;
1920 m_pShell->UIFeatureChanged();
1921 m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell);
1923 InvalidateSlot(SID_FM_FILTER_NAVIGATOR_CONTROL, sal_True);
1927 //------------------------------------------------------------------------------
1928 void FmXFormShell::getCurrentSelection( InterfaceBag& /* [out] */ _rSelection ) const
1930 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::getCurrentSelection" );
1931 _rSelection = m_aCurrentSelection;
1934 //------------------------------------------------------------------------------
1935 bool FmXFormShell::setCurrentSelectionFromMark( const SdrMarkList& _rMarkList )
1937 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::setCurrentSelectionFromMark" );
1938 m_aLastKnownMarkedControls.clear();
1940 if ( ( _rMarkList.GetMarkCount() > 0 ) && isControlList( _rMarkList ) )
1941 collectInterfacesFromMarkList( _rMarkList, m_aLastKnownMarkedControls );
1943 return setCurrentSelection( m_aLastKnownMarkedControls );
1946 //------------------------------------------------------------------------------
1947 bool FmXFormShell::selectLastMarkedControls()
1949 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::selectLastMarkedControls" );
1950 return setCurrentSelection( m_aLastKnownMarkedControls );
1953 //------------------------------------------------------------------------------
1954 bool FmXFormShell::setCurrentSelection( const InterfaceBag& _rSelection )
1956 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::setCurrentSelection" );
1957 if ( impl_checkDisposed() )
1958 return false;
1960 DBG_ASSERT( m_pShell->IsDesignMode(), "FmXFormShell::setCurrentSelection: only to be used in design mode!" );
1962 if ( _rSelection.empty() && m_aCurrentSelection.empty() )
1963 // nothing to do
1964 return false;
1966 if ( _rSelection.size() == m_aCurrentSelection.size() )
1968 InterfaceBag::const_iterator aNew = _rSelection.begin();
1969 InterfaceBag::const_iterator aOld = m_aCurrentSelection.begin();
1970 for ( ; aNew != _rSelection.end(); ++aNew, ++aOld )
1972 OSL_ENSURE( Reference< XInterface >( *aNew, UNO_QUERY ).get() == aNew->get(), "FmXFormShell::setCurrentSelection: new interface not normalized!" );
1973 OSL_ENSURE( Reference< XInterface >( *aOld, UNO_QUERY ).get() == aOld->get(), "FmXFormShell::setCurrentSelection: old interface not normalized!" );
1975 if ( aNew->get() != aOld->get() )
1976 break;
1979 if ( aNew == _rSelection.end() )
1980 // both bags equal
1981 return false;
1984 // the following is some strange code to ensure that when you have two grid controls in a document,
1985 // only one of them can have a selected column.
1986 // TODO: this should happen elsewhere, but not here - shouldn't it?
1987 if ( !m_aCurrentSelection.empty() )
1989 Reference< XChild > xCur; if ( m_aCurrentSelection.size() == 1 ) xCur = xCur.query( *m_aCurrentSelection.begin() );
1990 Reference< XChild > xNew; if ( _rSelection.size() == 1 ) xNew = xNew.query( *_rSelection.begin() );
1992 // is there nothing to be selected, or the parents differ, and the parent of the current object
1993 // is a selection supplier, then deselect
1994 if ( xCur.is() && ( !xNew.is() || ( xCur->getParent() != xNew->getParent() ) ) )
1996 Reference< XSelectionSupplier > xSel( xCur->getParent(), UNO_QUERY );
1997 if ( xSel.is() )
1998 xSel->select( Any() );
2002 m_aCurrentSelection = _rSelection;
2004 // determine the form which all the selected objécts belong to, if any
2005 Reference< XForm > xNewCurrentForm;
2006 for ( InterfaceBag::const_iterator loop = m_aCurrentSelection.begin();
2007 loop != m_aCurrentSelection.end();
2008 ++loop
2011 Reference< XForm > xThisRoundsForm( GetForm( *loop ) );
2012 OSL_ENSURE( xThisRoundsForm.is(), "FmXFormShell::setCurrentSelection: *everything* should belong to a form!" );
2014 if ( !xNewCurrentForm.is() )
2015 { // the first form we encounterd
2016 xNewCurrentForm = xThisRoundsForm;
2018 else if ( xNewCurrentForm != xThisRoundsForm )
2019 { // different forms -> no "current form" at all
2020 xNewCurrentForm.clear();
2021 break;
2025 if ( !m_aCurrentSelection.empty() )
2026 impl_updateCurrentForm( xNewCurrentForm );
2028 // ensure some slots are updated
2029 for ( size_t i = 0; i < sizeof( SelObjectSlotMap ) / sizeof( SelObjectSlotMap[0] ); ++i )
2030 InvalidateSlot( SelObjectSlotMap[i], sal_False);
2032 return true;
2035 //------------------------------------------------------------------------------
2036 bool FmXFormShell::isSolelySelected( const Reference< XInterface >& _rxObject )
2038 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::isSolelySelected" );
2039 return ( m_aCurrentSelection.size() == 1 ) && ( *m_aCurrentSelection.begin() == _rxObject );
2042 //------------------------------------------------------------------------------
2043 void FmXFormShell::forgetCurrentForm()
2045 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::forgetCurrentForm" );
2046 if ( !m_xCurrentForm.is() )
2047 return;
2049 // reset ...
2050 impl_updateCurrentForm( NULL );
2052 // ... and try finding a new current form
2053 // #i88186# / 2008-04-12 / frank.schoenheit@sun.com
2054 impl_defaultCurrentForm_nothrow();
2057 //------------------------------------------------------------------------------
2058 void FmXFormShell::impl_updateCurrentForm( const Reference< XForm >& _rxNewCurForm )
2060 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::impl_updateCurrentForm" );
2061 if ( impl_checkDisposed() )
2062 return;
2064 m_xCurrentForm = _rxNewCurForm;
2066 // propagate to the FormPage(Impl)
2067 FmFormPage* pPage = m_pShell->GetCurPage();
2068 if ( pPage )
2069 pPage->GetImpl().setCurForm( m_xCurrentForm );
2071 // ensure the UI which depends on the current form is up-to-date
2072 for ( size_t i = 0; i < sizeof( DlgSlotMap ) / sizeof( DlgSlotMap[0] ); ++i )
2073 InvalidateSlot( DlgSlotMap[i], sal_False );
2076 //------------------------------------------------------------------------------
2077 void FmXFormShell::startListening()
2079 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::startListening" );
2080 if ( impl_checkDisposed() )
2081 return;
2083 Reference< XRowSet> xDatabaseForm(m_xActiveForm, UNO_QUERY);
2084 if (xDatabaseForm.is() && getRowSetConnection(xDatabaseForm).is())
2086 Reference< XPropertySet> xActiveFormSet(m_xActiveForm, UNO_QUERY);
2087 if (xActiveFormSet.is())
2089 // wenn es eine Datenquelle gibt, dann den Listener aufbauen
2090 // TODO: this is strange - shouldn't this depend on a isLoaded instead of
2091 // a "has command value"? Finally, the command value only means that it was
2092 // intended to be loaded, not that it actually *is* loaded
2093 ::rtl::OUString aSource = ::comphelper::getString(xActiveFormSet->getPropertyValue(FM_PROP_COMMAND));
2094 if (aSource.getLength())
2096 m_bDatabaseBar = sal_True;
2098 xActiveFormSet->getPropertyValue(FM_PROP_NAVIGATION) >>= m_eNavigate;
2100 switch (m_eNavigate)
2102 case NavigationBarMode_PARENT:
2104 // suchen des Controllers, ueber den eine Navigation moeglich ist
2105 Reference< XChild> xChild(m_xActiveController, UNO_QUERY);
2106 Reference< XFormController> xParent;
2107 while (xChild.is())
2109 xChild = Reference< XChild>(xChild->getParent(), UNO_QUERY);
2110 xParent = Reference< XFormController>(xChild, UNO_QUERY);
2111 Reference< XPropertySet> xParentSet;
2112 if (xParent.is())
2113 xParentSet = Reference< XPropertySet>(xParent->getModel(), UNO_QUERY);
2114 if (xParentSet.is())
2116 xParentSet->getPropertyValue(FM_PROP_NAVIGATION) >>= m_eNavigate;
2117 if (m_eNavigate == NavigationBarMode_CURRENT)
2118 break;
2121 m_xNavigationController = xParent;
2123 break;
2125 case NavigationBarMode_CURRENT:
2126 m_xNavigationController = m_xActiveController;
2127 break;
2129 default:
2130 m_xNavigationController = NULL;
2131 m_bDatabaseBar = sal_False;
2134 m_aNavControllerFeatures.dispose();
2135 if ( m_xNavigationController.is() && ( m_xNavigationController != m_xActiveController ) )
2136 m_aNavControllerFeatures.assign( m_xNavigationController );
2138 // an dem Controller, der die Navigation regelt, wg. RecordCount lauschen
2139 Reference< XPropertySet> xNavigationSet;
2140 if (m_xNavigationController.is())
2142 xNavigationSet = Reference< XPropertySet>(m_xNavigationController->getModel(), UNO_QUERY);
2143 if (xNavigationSet.is())
2144 xNavigationSet->addPropertyChangeListener(FM_PROP_ROWCOUNT,this);
2146 return;
2151 m_eNavigate = NavigationBarMode_NONE;
2152 m_bDatabaseBar = sal_False;
2153 m_xNavigationController = NULL;
2156 //------------------------------------------------------------------------------
2157 void FmXFormShell::stopListening()
2159 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::stopListening" );
2160 if ( impl_checkDisposed() )
2161 return;
2163 Reference< XRowSet> xDatabaseForm(m_xActiveForm, UNO_QUERY);
2164 if ( xDatabaseForm.is() )
2166 if (m_xNavigationController.is())
2168 Reference< XPropertySet> xSet(m_xNavigationController->getModel(), UNO_QUERY);
2169 if (xSet.is())
2170 xSet->removePropertyChangeListener(FM_PROP_ROWCOUNT, this);
2175 m_bDatabaseBar = sal_False;
2176 m_eNavigate = NavigationBarMode_NONE;
2177 m_xNavigationController = NULL;
2180 //------------------------------------------------------------------------------
2181 void FmXFormShell::ShowSelectionProperties( sal_Bool bShow )
2183 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ShowSelectionProperties" );
2184 if ( impl_checkDisposed() )
2185 return;
2187 // if the window is already visible, only update the state
2188 sal_Bool bHasChild = m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow( SID_FM_SHOW_PROPERTIES );
2189 if ( bHasChild && bShow )
2190 UpdateSlot( SID_FM_PROPERTY_CONTROL );
2192 // else toggle state
2193 else
2194 m_pShell->GetViewShell()->GetViewFrame()->ToggleChildWindow(SID_FM_SHOW_PROPERTIES);
2196 InvalidateSlot( SID_FM_PROPERTIES, sal_False );
2197 InvalidateSlot( SID_FM_CTL_PROPERTIES, sal_False );
2200 //------------------------------------------------------------------------------
2201 IMPL_LINK(FmXFormShell, OnFoundData, FmFoundRecordInformation*, pfriWhere)
2203 if ( impl_checkDisposed() )
2204 return 0;
2206 DBG_ASSERT((pfriWhere->nContext >= 0) && (pfriWhere->nContext < (sal_Int16)m_aSearchForms.size()),
2207 "FmXFormShell::OnFoundData : ungueltiger Kontext !");
2208 Reference< XForm> xForm( m_aSearchForms.at(pfriWhere->nContext));
2209 DBG_ASSERT(xForm.is(), "FmXFormShell::OnFoundData : ungueltige Form !");
2211 Reference< XRowLocate> xCursor(xForm, UNO_QUERY);
2212 if (!xCursor.is())
2213 return 0; // was soll ich da machen ?
2215 // zum Datensatz
2218 xCursor->moveToBookmark(pfriWhere->aPosition);
2220 catch(const SQLException&)
2222 OSL_ENSURE(0,"Can position on bookmark!");
2225 LoopGrids(GA_FORCE_SYNC);
2227 // und zum Feld (dazu habe ich vor dem Start des Suchens die XVclComponent-Interfaces eingesammelt)
2228 DBG_ASSERT(pfriWhere->nFieldPos < m_arrSearchedControls.Count(), "FmXFormShell::OnFoundData : ungueltige Daten uebergeben !");
2229 SdrObject* pObject = m_arrSearchedControls.GetObject(pfriWhere->nFieldPos);
2230 DBG_ASSERT(pObject != NULL, "FmXFormShell::OnFoundData : unerwartet : ungueltiges VclControl-Interface");
2232 m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView());
2233 m_pShell->GetFormView()->MarkObj(pObject, m_pShell->GetFormView()->GetSdrPageView());
2235 FmFormObj* pFormObject = FmFormObj::GetFormObject( pObject );
2236 Reference< XControlModel > xControlModel( pFormObject ? pFormObject->GetUnoControlModel() : Reference< XControlModel >() );
2237 DBG_ASSERT( xControlModel.is(), "FmXFormShell::OnFoundData: invalid control!" );
2239 // disable the permanent cursor for the last grid we found a record
2240 if (m_xLastGridFound.is() && (m_xLastGridFound != xControlModel))
2242 Reference< XPropertySet> xOldSet(m_xLastGridFound, UNO_QUERY);
2243 xOldSet->setPropertyValue(FM_PROP_ALWAYSSHOWCURSOR, makeAny( (sal_Bool)sal_False ) );
2244 Reference< XPropertyState> xOldSetState(xOldSet, UNO_QUERY);
2245 if (xOldSetState.is())
2246 xOldSetState->setPropertyToDefault(FM_PROP_CURSORCOLOR);
2247 else
2248 xOldSet->setPropertyValue(FM_PROP_CURSORCOLOR, Any());
2251 // wenn das Feld sich in einem GridControl befindet, muss ich dort noch in die entsprechende Spalte gehen
2252 sal_Int32 nGridColumn = m_arrRelativeGridColumn.GetObject(pfriWhere->nFieldPos);
2253 if (nGridColumn != -1)
2254 { // dummer weise muss ich mir das Control erst wieder besorgen
2255 Reference< XControl> xControl( GetControlFromModel(xControlModel));
2256 Reference< XGrid> xGrid(xControl, UNO_QUERY);
2257 DBG_ASSERT(xGrid.is(), "FmXFormShell::OnFoundData : ungueltiges Control !");
2258 // wenn eine der Asserts anschlaegt, habe ich beim Aufbauen von m_arrSearchedControls wohl was falsch gemacht
2260 // enable a permanent cursor for the grid so we can see the found text
2261 Reference< XPropertySet> xModelSet(xControlModel, UNO_QUERY);
2262 DBG_ASSERT(xModelSet.is(), "FmXFormShell::OnFoundData : invalid control model (no property set) !");
2263 xModelSet->setPropertyValue( FM_PROP_ALWAYSSHOWCURSOR, makeAny( (sal_Bool)sal_True ) );
2264 xModelSet->setPropertyValue( FM_PROP_CURSORCOLOR, makeAny( sal_Int32( COL_LIGHTRED ) ) );
2265 m_xLastGridFound = xControlModel;
2267 xGrid->setCurrentColumnPosition((sal_Int16)nGridColumn);
2270 // als der Cursor neu positioniert wurde, habe ich (in positioned) meine Formularleisten-Slots invalidiert, aber das greift
2271 // hier dummerweise nicht, da i.A. ja der (modale) Suchdialog oben ist ... also Gewalt ...
2272 sal_uInt16 nPos = 0;
2273 while (DatabaseSlotMap[nPos])
2274 m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Update(DatabaseSlotMap[nPos++]);
2275 // leider geht das Update im Gegensatz zum Invalidate nur mit einzelnen Slots)
2277 return 0;
2280 //------------------------------------------------------------------------------
2281 IMPL_LINK(FmXFormShell, OnCanceledNotFound, FmFoundRecordInformation*, pfriWhere)
2283 if ( impl_checkDisposed() )
2284 return 0;
2286 DBG_ASSERT((pfriWhere->nContext >= 0) && (pfriWhere->nContext < (sal_Int16)m_aSearchForms.size()),
2287 "FmXFormShell::OnCanceledNotFound : ungueltiger Kontext !");
2288 Reference< XForm> xForm( m_aSearchForms.at(pfriWhere->nContext));
2289 DBG_ASSERT(xForm.is(), "FmXFormShell::OnCanceledNotFound : ungueltige Form !");
2291 Reference< XRowLocate> xCursor(xForm, UNO_QUERY);
2292 if (!xCursor.is())
2293 return 0; // was soll ich da machen ?
2295 // zum Datensatz
2298 xCursor->moveToBookmark(pfriWhere->aPosition);
2300 catch(const SQLException&)
2302 OSL_ENSURE(0,"Can position on bookmark!");
2306 m_pShell->GetFormView()->UnMarkAll(m_pShell->GetFormView()->GetSdrPageView());
2307 return 0L;
2310 //------------------------------------------------------------------------------
2311 IMPL_LINK(FmXFormShell, OnSearchContextRequest, FmSearchContext*, pfmscContextInfo)
2313 if ( impl_checkDisposed() )
2314 return 0;
2316 DBG_ASSERT(pfmscContextInfo->nContext < (sal_Int16)m_aSearchForms.size(), "FmXFormShell::OnSearchContextRequest : invalid parameter !");
2317 Reference< XForm> xForm( m_aSearchForms.at(pfmscContextInfo->nContext));
2318 DBG_ASSERT(xForm.is(), "FmXFormShell::OnSearchContextRequest : unexpected : invalid context !");
2320 Reference< XResultSet> xIter(xForm, UNO_QUERY);
2321 DBG_ASSERT(xIter.is(), "FmXFormShell::OnSearchContextRequest : unexpected : context has no iterator !");
2323 // --------------------------------------------------------------------------------------------
2324 // die Liste der zu involvierenden Felder zusammenstellen (sind die ControlSources aller Felder, die eine solche Eigenschaft habe)
2325 UniString strFieldList, sFieldDisplayNames;
2326 m_arrSearchedControls.Remove(0, m_arrSearchedControls.Count());
2327 m_arrRelativeGridColumn.Remove(0, m_arrRelativeGridColumn.Count());
2329 // folgendes kleines Problem : Ich brauche, um gefundene Felder zu markieren, SdrObjekte. Um hier festzustellen, welche Controls
2330 // ich in die Suche einbeziehen soll, brauche ich Controls (also XControl-Interfaces). Ich muss also ueber eines von beiden
2331 // iterieren und mir das jeweils andere besorgen. Dummerweise gibt es keine direkte Verbindung zwischen beiden Welten (abgesehen
2332 // von einem GetUnoControl an SdrUnoObject, das aber ein OutputDevice verlangt, womit ich nichts anfangen kann).
2333 // Allerdings komme ich sowohl von einem Control als auch von einem SdrObject zum Model, und damit ist mir mit einer doppelten
2334 // Schleife die Zuordnung SdrObject<->Control moeglich.
2335 // Die Alternative zu dieser (unschoenen und sicher auch nicht ganz fixen) Loesung waere, auf das Cachen der SdrObjects zu
2336 // verzichten, was dann aber in OnFoundData zu wesentlicher Mehrarbeit fuehren wuerde (da ich mir dort jedesmal das SdrObject
2337 // erst besorgen muesste). Da aber OnFoundData i.d.R. oefter aufgerufen wird als ExecuteSearch, erledige ich das hier.
2339 Reference< XNameAccess> xValidFormFields;
2340 Reference< XColumnsSupplier> xSupplyCols(xIter, UNO_QUERY);
2341 DBG_ASSERT(xSupplyCols.is(), "FmXFormShell::OnSearchContextRequest : invalid cursor : no columns supplier !");
2342 if (xSupplyCols.is())
2343 xValidFormFields = xSupplyCols->getColumns();
2344 DBG_ASSERT(xValidFormFields.is(), "FmXFormShell::OnSearchContextRequest : form has no fields !");
2346 // aktuelle(r) Page/Controller
2347 FmFormPage* pCurrentPage = m_pShell->GetCurPage();
2348 DBG_ASSERT(pCurrentPage!=NULL, "FmXFormShell::OnSearchContextRequest : no page !");
2349 // alle Sdr-Controls dieser Seite durchsuchen ...
2350 ::rtl::OUString sControlSource, aName;
2352 SdrObjListIter aPageIter( *pCurrentPage );
2353 while ( aPageIter.IsMore() )
2355 SdrObject* pCurrent = aPageIter.Next();
2356 FmFormObj* pFormObject = FmFormObj::GetFormObject( pCurrent );
2357 // note that in case pCurrent is a virtual object, pFormObject points to the referenced object
2359 if ( !pFormObject )
2360 continue;
2362 // the current object's model, in different tastes
2363 Reference< XControlModel> xControlModel( pFormObject->GetUnoControlModel() );
2364 Reference< XFormComponent > xCurrentFormComponent( xControlModel, UNO_QUERY );
2365 DBG_ASSERT( xCurrentFormComponent.is(), "FmXFormShell::OnSearchContextRequest: invalid objects!" );
2366 if ( !xCurrentFormComponent.is() )
2367 continue;
2369 // does the component belong to the form which we're interested in?
2370 if ( xCurrentFormComponent->getParent() != xForm )
2371 continue;
2373 // ... nach der ControlSource-Eigenschaft fragen
2374 SearchableControlIterator iter( xCurrentFormComponent );
2375 Reference< XControl> xControlBehindModel;
2376 // das Control, das als Model xControlModel hat
2377 // (das folgende while kann mehrmals durchlaufen werden, ohne dass das Control sich aendert, dann muss
2378 // ich nicht jedesmal neu suchen)
2380 Reference< XInterface > xSearchable( iter.Next() );
2381 while ( xSearchable.is() )
2383 sControlSource = iter.getCurrentValue();
2384 if ( sControlSource.getLength() == 0 )
2385 { // das aktuelle Element hat keine ControlSource, also ist es ein GridControl (das ist das einzige, was
2386 // der SearchableControlIterator noch zulaesst)
2387 xControlBehindModel = GetControlFromModel(xControlModel);
2388 DBG_ASSERT(xControlBehindModel.is(), "FmXFormShell::OnSearchContextRequest : didn't ::std::find a control with requested model !");
2390 Reference< XGridPeer> xGridPeer(xControlBehindModel->getPeer(), UNO_QUERY);
2393 if (!xGridPeer.is())
2394 break;
2396 Reference< XIndexAccess> xPeerContainer(xGridPeer, UNO_QUERY);
2397 if (!xPeerContainer.is())
2398 break;
2400 Reference< XIndexAccess> xModelColumns(xGridPeer->getColumns(), UNO_QUERY);
2401 DBG_ASSERT(xModelColumns.is(), "FmXFormShell::OnSearchContextRequest : there is a grid control without columns !");
2402 // the case 'no columns' should be indicated with an empty container, I think ...
2403 DBG_ASSERT(xModelColumns->getCount() >= xPeerContainer->getCount(), "FmXFormShell::OnSearchContextRequest : impossible : have more view than model columns !");
2405 Reference< XInterface> xCurrentColumn;
2406 for (sal_Int16 nViewPos=0; nViewPos<xPeerContainer->getCount(); ++nViewPos)
2408 xPeerContainer->getByIndex(nViewPos) >>= xCurrentColumn;
2409 if (!xCurrentColumn.is())
2410 continue;
2412 // can we use this column control fo searching ?
2413 if (!IsSearchableControl(xCurrentColumn))
2414 continue;
2416 sal_Int16 nModelPos = GridView2ModelPos(xModelColumns, nViewPos);
2417 Reference< XPropertySet> xCurrentColModel;
2418 xModelColumns->getByIndex(nModelPos) >>= xCurrentColModel;
2419 aName = ::comphelper::getString(xCurrentColModel->getPropertyValue(FM_PROP_CONTROLSOURCE));
2420 // the cursor has a field matching the control source ?
2421 if (xValidFormFields->hasByName(aName))
2423 strFieldList += aName.getStr();
2424 strFieldList += ';';
2426 sFieldDisplayNames += ::comphelper::getString(xCurrentColModel->getPropertyValue(FM_PROP_LABEL)).getStr();
2427 sFieldDisplayNames += ';';
2429 pfmscContextInfo->arrFields.push_back(xCurrentColumn);
2431 // und das SdrObjekt zum Feld
2432 m_arrSearchedControls.C40_INSERT(SdrObject, pCurrent, m_arrSearchedControls.Count());
2433 // die Nummer der Spalte
2434 m_arrRelativeGridColumn.Insert(nViewPos, m_arrRelativeGridColumn.Count());
2437 } while (sal_False);
2439 else
2441 if (sControlSource.getLength() && xValidFormFields->hasByName(sControlSource))
2443 // jetzt brauche ich das Control zum SdrObject
2444 if (!xControlBehindModel.is())
2446 xControlBehindModel = GetControlFromModel(xControlModel);
2447 DBG_ASSERT(xControlBehindModel.is(), "FmXFormShell::OnSearchContextRequest : didn't ::std::find a control with requested model !");
2450 if (IsSearchableControl(xControlBehindModel))
2451 { // alle Tests ueberstanden -> in die Liste mit aufnehmen
2452 strFieldList += sControlSource.getStr();
2453 strFieldList += ';';
2455 // the label which should appear for the control :
2456 sFieldDisplayNames += getLabelName(Reference< XPropertySet>(xControlModel, UNO_QUERY)).getStr();
2457 sFieldDisplayNames += ';';
2459 // das SdrObjekt merken (beschleunigt die Behandlung in OnFoundData)
2460 m_arrSearchedControls.C40_INSERT(SdrObject, pCurrent, m_arrSearchedControls.Count());
2462 // die Nummer der Spalte (hier ein Dummy, nur fuer GridControls interesant)
2463 m_arrRelativeGridColumn.Insert(-1, m_arrRelativeGridColumn.Count());
2465 // und fuer die formatierte Suche ...
2466 pfmscContextInfo->arrFields.push_back(Reference< XInterface>(xControlBehindModel, UNO_QUERY));
2471 xSearchable = iter.Next();
2475 strFieldList.EraseTrailingChars(';');
2476 sFieldDisplayNames.EraseTrailingChars(';');
2478 if (!pfmscContextInfo->arrFields.size())
2480 pfmscContextInfo->arrFields.clear();
2481 pfmscContextInfo->xCursor = NULL;
2482 pfmscContextInfo->strUsedFields.Erase();
2483 return 0L;
2486 pfmscContextInfo->xCursor = xIter;
2487 pfmscContextInfo->strUsedFields = strFieldList;
2488 pfmscContextInfo->sFieldDisplayNames = sFieldDisplayNames;
2490 // 66463 - 31.05.99 - FS
2491 // wenn der Cursor sich in einem anderen RecordMode als STANDARD befindet, ruecksetzen
2492 Reference< XPropertySet> xCursorSet(pfmscContextInfo->xCursor, UNO_QUERY);
2493 Reference< XResultSetUpdate> xUpdateCursor(pfmscContextInfo->xCursor, UNO_QUERY);
2494 if (xUpdateCursor.is() && xCursorSet.is() && xCursorSet.is())
2496 if (::comphelper::getBOOL(xCursorSet->getPropertyValue(FM_PROP_ISNEW)))
2497 xUpdateCursor->moveToCurrentRow();
2498 else if (::comphelper::getBOOL(xCursorSet->getPropertyValue(FM_PROP_ISMODIFIED)))
2499 xUpdateCursor->cancelRowUpdates();
2502 return pfmscContextInfo->arrFields.size();
2505 // XContainerListener
2506 //------------------------------------------------------------------------------
2507 void FmXFormShell::elementInserted(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException)
2509 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::elementInserted" );
2510 if ( impl_checkDisposed() )
2511 return;
2513 // neues Object zum lauschen
2514 Reference< XInterface> xTemp;
2515 evt.Element >>= xTemp;
2516 AddElement(xTemp);
2517 m_pShell->DetermineForms(sal_True);
2520 //------------------------------------------------------------------------------
2521 void FmXFormShell::elementReplaced(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException)
2523 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::elementReplaced" );
2524 if ( impl_checkDisposed() )
2525 return;
2527 Reference< XInterface> xTemp;
2528 evt.ReplacedElement >>= xTemp;
2529 RemoveElement(xTemp);
2530 evt.Element >>= xTemp;
2531 AddElement(xTemp);
2534 //------------------------------------------------------------------------------
2535 void FmXFormShell::elementRemoved(const ContainerEvent& evt) throw(::com::sun::star::uno::RuntimeException)
2537 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::elementRemoved" );
2538 if ( impl_checkDisposed() )
2539 return;
2541 Reference< XInterface> xTemp;
2542 evt.Element >>= xTemp;
2543 RemoveElement(xTemp);
2544 m_pShell->DetermineForms(sal_True);
2547 //------------------------------------------------------------------------------
2548 void FmXFormShell::UpdateForms( sal_Bool _bInvalidate )
2550 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::UpdateForms" );
2551 if ( impl_checkDisposed() )
2552 return;
2554 Reference< XIndexAccess > xForms;
2556 FmFormPage* pPage = m_pShell->GetCurPage();
2557 if ( pPage )
2559 if ( m_pShell->m_bDesignMode )
2560 xForms = xForms.query( pPage->GetForms( false ) );
2563 if ( m_xForms != xForms )
2565 RemoveElement( m_xForms );
2566 m_xForms = xForms;
2567 AddElement( m_xForms );
2570 m_pShell->DetermineForms( _bInvalidate );
2573 //------------------------------------------------------------------------------
2574 void FmXFormShell::AddElement(const Reference< XInterface>& _xElement)
2576 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::AddElement" );
2577 if ( impl_checkDisposed() )
2578 return;
2579 impl_AddElement_nothrow(_xElement);
2581 // -----------------------------------------------------------------------------
2582 void FmXFormShell::impl_AddElement_nothrow(const Reference< XInterface>& Element)
2584 // am Container horchen
2585 const Reference< XIndexContainer> xContainer(Element, UNO_QUERY);
2586 if (xContainer.is())
2588 const sal_uInt32 nCount = xContainer->getCount();
2589 Reference< XInterface> xElement;
2590 for (sal_uInt32 i = 0; i < nCount; ++i)
2592 xElement.set(xContainer->getByIndex(i),UNO_QUERY);
2593 impl_AddElement_nothrow(xElement);
2596 const Reference< XContainer> xCont(Element, UNO_QUERY);
2597 if (xCont.is())
2598 xCont->addContainerListener(this);
2601 const Reference< ::com::sun::star::view::XSelectionSupplier> xSelSupplier(Element, UNO_QUERY);
2602 if (xSelSupplier.is())
2603 xSelSupplier->addSelectionChangeListener(this);
2606 //------------------------------------------------------------------------------
2607 void FmXFormShell::RemoveElement(const Reference< XInterface>& Element)
2609 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::RemoveElement" );
2610 if ( impl_checkDisposed() )
2611 return;
2612 impl_RemoveElement_nothrow(Element);
2614 //------------------------------------------------------------------------------
2615 void FmXFormShell::impl_RemoveElement_nothrow(const Reference< XInterface>& Element)
2617 const Reference< ::com::sun::star::view::XSelectionSupplier> xSelSupplier(Element, UNO_QUERY);
2618 if (xSelSupplier.is())
2619 xSelSupplier->removeSelectionChangeListener(this);
2621 // Verbindung zu Kindern aufheben
2622 const Reference< XIndexContainer> xContainer(Element, UNO_QUERY);
2623 if (xContainer.is())
2625 const Reference< XContainer> xCont(Element, UNO_QUERY);
2626 if (xCont.is())
2627 xCont->removeContainerListener(this);
2629 const sal_uInt32 nCount = xContainer->getCount();
2630 Reference< XInterface> xElement;
2631 for (sal_uInt32 i = 0; i < nCount; i++)
2633 xElement.set(xContainer->getByIndex(i),UNO_QUERY);
2634 impl_RemoveElement_nothrow(xElement);
2638 InterfaceBag::iterator wasSelectedPos = m_aCurrentSelection.find( Element );
2639 if ( wasSelectedPos != m_aCurrentSelection.end() )
2640 m_aCurrentSelection.erase( wasSelectedPos );
2643 //------------------------------------------------------------------------------
2644 void FmXFormShell::selectionChanged(const EventObject& rEvent) throw(::com::sun::star::uno::RuntimeException)
2646 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::selectionChanged" );
2647 if ( impl_checkDisposed() )
2648 return;
2650 Reference< XSelectionSupplier > xSupplier( rEvent.Source, UNO_QUERY );
2651 Reference< XInterface > xSelObj( xSupplier->getSelection(), UNO_QUERY );
2652 // es wurde eine Selektion weggenommen, dieses kann nur durch die Shell vorgenommen werden
2653 if ( !xSelObj.is() )
2654 return;
2656 EnableTrackProperties(sal_False);
2658 sal_Bool bMarkChanged = m_pShell->GetFormView()->checkUnMarkAll(rEvent.Source);
2659 Reference< XForm > xNewForm( GetForm( rEvent.Source ) );
2661 InterfaceBag aNewSelection;
2662 aNewSelection.insert( Reference< XInterface >( xSelObj, UNO_QUERY ) );
2664 if ( setCurrentSelection( aNewSelection ) && IsPropBrwOpen() )
2665 ShowSelectionProperties( sal_True );
2667 EnableTrackProperties(sal_True);
2669 if ( bMarkChanged )
2670 m_pShell->NotifyMarkListChanged( m_pShell->GetFormView() );
2673 //------------------------------------------------------------------------------
2674 IMPL_LINK(FmXFormShell, OnTimeOut, void*, /*EMPTYTAG*/)
2676 if ( impl_checkDisposed() )
2677 return 0;
2679 if (m_pShell->IsDesignMode() && m_pShell->GetFormView())
2680 SetSelection(m_pShell->GetFormView()->GetMarkedObjectList());
2682 return 0;
2685 //------------------------------------------------------------------------
2686 void FmXFormShell::SetSelectionDelayed()
2688 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetSelectionDelayed" );
2689 if ( impl_checkDisposed() )
2690 return;
2692 if (m_pShell->IsDesignMode() && IsTrackPropertiesEnabled() && !m_aMarkTimer.IsActive())
2693 m_aMarkTimer.Start();
2696 //------------------------------------------------------------------------
2697 void FmXFormShell::SetSelection(const SdrMarkList& rMarkList)
2699 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetSelection" );
2700 if ( impl_checkDisposed() )
2701 return;
2703 DetermineSelection(rMarkList);
2704 m_pShell->NotifyMarkListChanged(m_pShell->GetFormView());
2707 //------------------------------------------------------------------------
2708 void FmXFormShell::DetermineSelection(const SdrMarkList& rMarkList)
2710 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::DetermineSelection" );
2711 if ( setCurrentSelectionFromMark( rMarkList ) && IsPropBrwOpen() )
2712 ShowSelectionProperties( sal_True );
2715 //------------------------------------------------------------------------------
2716 sal_Bool FmXFormShell::IsPropBrwOpen() const
2718 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::IsPropBrwOpen" );
2719 if ( impl_checkDisposed() )
2720 return sal_False;
2722 return( ( m_pShell->GetViewShell() && m_pShell->GetViewShell()->GetViewFrame() ) ?
2723 m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow(SID_FM_SHOW_PROPERTIES) : sal_False );
2726 //------------------------------------------------------------------------------
2727 class FmXFormShell::SuspendPropertyTracking
2729 private:
2730 FmXFormShell& m_rShell;
2731 sal_Bool m_bEnabled;
2733 public:
2734 SuspendPropertyTracking( FmXFormShell& _rShell )
2735 :m_rShell( _rShell )
2736 ,m_bEnabled( sal_False )
2738 if ( m_rShell.IsTrackPropertiesEnabled() )
2740 m_rShell.EnableTrackProperties( sal_False );
2741 m_bEnabled = sal_True;
2745 ~SuspendPropertyTracking( )
2747 if ( m_bEnabled ) // note that ( sal_False != m_bEnabled ) implies ( NULL != m_pShell )
2748 m_rShell.EnableTrackProperties( sal_True );
2752 //------------------------------------------------------------------------------
2753 void FmXFormShell::SetDesignMode(sal_Bool bDesign)
2755 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetDesignMode" );
2756 if ( impl_checkDisposed() )
2757 return;
2759 DBG_ASSERT(m_pShell->GetFormView(), "FmXFormShell::SetDesignMode : invalid call (have no shell or no view) !");
2760 m_bChangingDesignMode = sal_True;
2762 // 67506 - 15.07.99 - FS
2763 // if we're switching off the design mode we have to force the property browser to be closed
2764 // so it can commit it's changes _before_ we load the forms
2765 if (!bDesign)
2767 m_bHadPropertyBrowserInDesignMode = m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow(SID_FM_SHOW_PROPERTIES);
2768 if (m_bHadPropertyBrowserInDesignMode)
2769 m_pShell->GetViewShell()->GetViewFrame()->ToggleChildWindow(SID_FM_SHOW_PROPERTIES);
2772 FmFormView* pFormView = m_pShell->GetFormView();
2773 if (bDesign)
2775 // we are currently filtering, so stop filtering
2776 if (m_bFilterMode)
2777 stopFiltering(sal_False);
2779 // an den Objekten meiner MarkList als Listener abmelden
2780 pFormView->GetImpl()->stopMarkListWatching();
2782 else
2784 m_aMarkTimer.Stop();
2786 SuspendPropertyTracking aSuspend( *this );
2787 pFormView->GetImpl()->saveMarkList( sal_True );
2790 if (bDesign && m_xExternalViewController.is())
2791 CloseExternalFormViewer();
2793 pFormView->ChangeDesignMode(bDesign);
2795 // Listener benachrichtigen
2796 FmDesignModeChangedHint aChangedHint( bDesign );
2797 m_pShell->Broadcast(aChangedHint);
2799 m_pShell->m_bDesignMode = bDesign;
2800 UpdateForms( sal_False );
2802 m_pTextShell->designModeChanged( m_pShell->m_bDesignMode );
2804 if (bDesign)
2806 SdrMarkList aList;
2808 // during changing the mark list, don't track the selected objects in the property browser
2809 SuspendPropertyTracking aSuspend( *this );
2810 // restore the marks
2811 pFormView->GetImpl()->restoreMarkList( aList );
2814 // synchronize with the restored mark list
2815 if ( aList.GetMarkCount() )
2816 SetSelection( aList );
2818 else
2820 // am Model der View als Listener anmelden (damit ich mitbekomme, wenn jemand waehrend des Alive-Modus
2821 // Controls loescht, die ich eigentlich mit saveMarkList gespeichert habe) (60343)
2822 pFormView->GetImpl()->startMarkListWatching();
2825 m_pShell->UIFeatureChanged();
2827 // 67506 - 15.07.99 - FS
2828 if (bDesign && m_bHadPropertyBrowserInDesignMode)
2830 // The UIFeatureChanged performes an update (a check of the available features) asynchronously.
2831 // So we can't call ShowSelectionProperties directly as the according feature isn't enabled yet.
2832 // That's why we use an asynchron execution on the dispatcher.
2833 // (And that's why this has to be done AFTER the UIFeatureChanged.)
2834 m_pShell->GetViewShell()->GetViewFrame()->GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER, SFX_CALLMODE_ASYNCHRON );
2836 m_bChangingDesignMode = sal_False;
2839 //------------------------------------------------------------------------------
2840 Reference< XControl> FmXFormShell::GetControlFromModel(const Reference< XControlModel>& xModel)
2842 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::GetControlFromModel" );
2843 if ( impl_checkDisposed() )
2844 return NULL;
2846 Reference< XControlContainer> xControlContainer( getControlContainerForView() );
2848 Sequence< Reference< XControl> > seqControls( xControlContainer->getControls() );
2849 Reference< XControl>* pControls = seqControls.getArray();
2850 // ... die ich dann durchsuchen kann
2851 for (int i=0; i<seqControls.getLength(); ++i)
2853 Reference< XControlModel> xSearchLoopModel( pControls[i]->getModel());
2854 if ((XControlModel*)xSearchLoopModel.get() == (XControlModel*)xModel.get())
2855 return pControls[i];
2857 return Reference< XControl>(NULL);
2860 //------------------------------------------------------------------------------
2861 void FmXFormShell::impl_collectFormSearchContexts_nothrow( const Reference< XInterface>& _rxStartingPoint,
2862 const ::rtl::OUString& _rCurrentLevelPrefix, FmFormArray& _out_rForms, ::std::vector< String >& _out_rNames )
2864 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::impl_collectFormSearchContexts_nothrow" );
2867 Reference< XIndexAccess> xContainer( _rxStartingPoint, UNO_QUERY );
2868 if ( !xContainer.is() )
2869 return;
2871 sal_Int32 nCount( xContainer->getCount() );
2872 if ( nCount == 0 )
2873 return;
2875 ::rtl::OUString sCurrentFormName;
2876 ::rtl::OUStringBuffer aNextLevelPrefix;
2877 for ( sal_Int32 i=0; i<nCount; ++i )
2879 // is the current child a form?
2880 Reference< XForm > xCurrentAsForm( xContainer->getByIndex(i), UNO_QUERY );
2881 if ( !xCurrentAsForm.is() )
2882 continue;
2884 Reference< XNamed > xNamed( xCurrentAsForm, UNO_QUERY_THROW );
2885 sCurrentFormName = xNamed->getName();
2887 // the name of the current form
2888 ::rtl::OUStringBuffer sCompleteCurrentName( sCurrentFormName );
2889 if ( _rCurrentLevelPrefix.getLength() )
2891 sCompleteCurrentName.appendAscii( " (" );
2892 sCompleteCurrentName.append ( _rCurrentLevelPrefix );
2893 sCompleteCurrentName.appendAscii( ")" );
2896 // the prefix for the next level
2897 aNextLevelPrefix = _rCurrentLevelPrefix;
2898 if ( _rCurrentLevelPrefix.getLength() )
2899 aNextLevelPrefix.append( (sal_Unicode)'/' );
2900 aNextLevelPrefix.append( sCurrentFormName );
2902 // remember both the form and it's "display name"
2903 _out_rForms.push_back( xCurrentAsForm );
2904 _out_rNames.push_back( sCompleteCurrentName.makeStringAndClear() );
2906 // und absteigen
2907 impl_collectFormSearchContexts_nothrow( xCurrentAsForm, aNextLevelPrefix.makeStringAndClear(), _out_rForms, _out_rNames );
2910 catch( const Exception& )
2912 DBG_UNHANDLED_EXCEPTION();
2916 //------------------------------------------------------------------------------
2917 void FmXFormShell::startFiltering()
2919 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::startFiltering" );
2920 if ( impl_checkDisposed() )
2921 return;
2923 // setting all forms in filter mode
2924 FmXFormView* pXView = m_pShell->GetFormView()->GetImpl();
2926 // if the active controller is our external one we have to use the trigger controller
2927 Reference< XControlContainer> xContainer;
2928 if (getActiveController() == m_xExternalViewController)
2930 DBG_ASSERT(m_xExtViewTriggerController.is(), "FmXFormShell::startFiltering : inconsistent : active external controller, but noone triggered this !");
2931 xContainer = m_xExtViewTriggerController->getContainer();
2933 else
2934 xContainer = getActiveController()->getContainer();
2936 FmWinRecList::iterator i = pXView->findWindow(xContainer);
2937 if (i != pXView->getWindowList().end())
2939 const ::std::vector< Reference< XFormController> >& rControllerList = (*i)->GetList();
2940 for (::std::vector< Reference< XFormController> >::const_iterator j = rControllerList.begin();
2941 j != rControllerList.end(); ++j)
2943 Reference< XModeSelector> xModeSelector(*j, UNO_QUERY);
2944 if (xModeSelector.is())
2945 xModeSelector->setMode(FILTER_MODE);
2949 m_bFilterMode = sal_True;
2951 m_pShell->UIFeatureChanged();
2952 m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell);
2955 //------------------------------------------------------------------------------
2956 void saveFilter(const Reference< XFormController>& _rxController)
2958 Reference< XPropertySet> xFormAsSet(_rxController->getModel(), UNO_QUERY);
2959 Reference< XPropertySet> xControllerAsSet(_rxController, UNO_QUERY);
2960 Reference< XIndexAccess> xControllerAsIndex(_rxController, UNO_QUERY);
2962 // call the subcontroller
2963 Reference< XFormController> xController;
2964 for (sal_Int32 i = 0, nCount = xControllerAsIndex->getCount(); i < nCount; ++i)
2966 xControllerAsIndex->getByIndex(i) >>= xController;
2967 saveFilter(xController);
2973 xFormAsSet->setPropertyValue(FM_PROP_FILTER, xControllerAsSet->getPropertyValue(FM_PROP_FILTER));
2974 xFormAsSet->setPropertyValue(FM_PROP_APPLYFILTER, makeAny( (sal_Bool)sal_True ) );
2976 catch (const Exception& )
2978 DBG_UNHANDLED_EXCEPTION();
2983 //------------------------------------------------------------------------------
2984 void FmXFormShell::stopFiltering(sal_Bool bSave)
2986 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::stopFiltering" );
2987 if ( impl_checkDisposed() )
2988 return;
2990 m_bFilterMode = sal_False;
2992 FmXFormView* pXView = m_pShell->GetFormView()->GetImpl();
2994 // if the active controller is our external one we have to use the trigger controller
2995 Reference< XControlContainer> xContainer;
2996 if (getActiveController() == m_xExternalViewController)
2998 DBG_ASSERT(m_xExtViewTriggerController.is(), "FmXFormShell::startFiltering : inconsistent : active external controller, but noone triggered this !");
2999 xContainer = m_xExtViewTriggerController->getContainer();
3001 else
3002 xContainer = getActiveController()->getContainer();
3004 FmWinRecList::iterator i = pXView->findWindow(xContainer);
3005 if (i != pXView->getWindowList().end())
3007 const ::std::vector< Reference< XFormController> >& rControllerList = (*i)->GetList();
3008 ::std::vector < ::rtl::OUString > aOriginalFilters;
3009 ::std::vector < sal_Bool > aOriginalApplyFlags;
3011 if (bSave)
3013 for (::std::vector< Reference< XFormController> > ::const_iterator j = rControllerList.begin();
3014 j != rControllerList.end(); ++j)
3016 if (bSave)
3017 { // remember the current filter settings in case we're goin to reload the forms below (which may fail)
3020 Reference< XPropertySet > xFormAsSet((*j)->getModel(), UNO_QUERY);
3021 aOriginalFilters.push_back(::comphelper::getString(xFormAsSet->getPropertyValue(FM_PROP_FILTER)));
3022 aOriginalApplyFlags.push_back(::comphelper::getBOOL(xFormAsSet->getPropertyValue(FM_PROP_APPLYFILTER)));
3024 catch(Exception&)
3026 DBG_ERROR("FmXFormShell::stopFiltering : could not get the original filter !");
3027 // put dummies into the arrays so the they have the right size
3029 if (aOriginalFilters.size() == aOriginalApplyFlags.size())
3030 // the first getPropertyValue failed -> use two dummies
3031 aOriginalFilters.push_back( ::rtl::OUString() );
3032 aOriginalApplyFlags.push_back( sal_False );
3035 saveFilter(*j);
3038 for (::std::vector< Reference< XFormController> > ::const_iterator j = rControllerList.begin();
3039 j != rControllerList.end(); ++j)
3042 Reference< XModeSelector> xModeSelector(*j, UNO_QUERY);
3043 if (xModeSelector.is())
3044 xModeSelector->setMode(DATA_MODE);
3046 if (bSave) // execute the filter
3048 const ::std::vector< Reference< XFormController> > & rControllers = (*i)->GetList();
3049 for (::std::vector< Reference< XFormController> > ::const_iterator j = rControllers.begin();
3050 j != rControllers.end(); ++j)
3052 Reference< XLoadable> xReload((*j)->getModel(), UNO_QUERY);
3053 if (!xReload.is())
3054 continue;
3055 Reference< XPropertySet > xFormSet(xReload, UNO_QUERY);
3059 xReload->reload();
3061 catch(Exception&)
3063 DBG_ERROR("FmXFormShell::stopFiltering: Exception occured!");
3066 if (!isRowSetAlive(xFormSet))
3067 { // something went wrong -> restore the original state
3068 ::rtl::OUString sOriginalFilter = aOriginalFilters[ j - rControllers.begin() ];
3069 sal_Bool bOriginalApplyFlag = aOriginalApplyFlags[ j - rControllers.begin() ];
3072 xFormSet->setPropertyValue(FM_PROP_FILTER, makeAny(sOriginalFilter));
3073 xFormSet->setPropertyValue(FM_PROP_APPLYFILTER, makeAny(bOriginalApplyFlag));
3074 xReload->reload();
3076 catch(const Exception&)
3078 DBG_UNHANDLED_EXCEPTION();
3085 m_pShell->UIFeatureChanged();
3086 m_pShell->GetViewShell()->GetViewFrame()->GetBindings().InvalidateShell(*m_pShell);
3089 //------------------------------------------------------------------------------
3090 void clearFilter(const Reference< XFormController>& _rxController)
3092 Reference< XPropertySet> xControllerAsSet(_rxController, UNO_QUERY);
3093 Reference< XIndexAccess> xControllerAsIndex(_rxController, UNO_QUERY);
3095 // call the subcontroller
3096 Reference< XFormController> xController;
3097 for (sal_Int32 i = 0, nCount = xControllerAsIndex->getCount();
3098 i < nCount; i++)
3100 xControllerAsIndex->getByIndex(i) >>= xController;
3101 clearFilter(xController);
3104 // clear the filter
3105 Reference< XIndexContainer> xContainer;
3106 xControllerAsSet->getPropertyValue(FM_PROP_FILTERSUPPLIER) >>= xContainer;
3107 if (xContainer.is())
3109 // clear the current filter
3110 Sequence< PropertyValue> aCondition;
3112 // as there is always an empty row, if we have a filter:
3113 if (xContainer->getCount())
3115 xControllerAsSet->setPropertyValue(FM_PROP_CURRENTFILTER, makeAny(sal_Int32(xContainer->getCount() - 1)));
3116 while (xContainer->getCount() > 1)
3117 xContainer->removeByIndex(0);
3122 //------------------------------------------------------------------------------
3123 void FmXFormShell::clearFilter()
3125 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::clearFilter" );
3126 if ( impl_checkDisposed() )
3127 return;
3129 FmXFormView* pXView = m_pShell->GetFormView()->GetImpl();
3131 // if the active controller is our external one we have to use the trigger controller
3132 Reference< XControlContainer> xContainer;
3133 if (getActiveController() == m_xExternalViewController)
3135 DBG_ASSERT(m_xExtViewTriggerController.is(), "FmXFormShell::startFiltering : inconsistent : active external controller, but noone triggered this !");
3136 xContainer = m_xExtViewTriggerController->getContainer();
3138 else
3139 xContainer = getActiveController()->getContainer();
3141 FmWinRecList::iterator i = pXView->findWindow(xContainer);
3142 if (i != pXView->getWindowList().end())
3144 const ::std::vector< Reference< XFormController> > & rControllerList = (*i)->GetList();
3145 for (::std::vector< Reference< XFormController> > ::const_iterator j = rControllerList.begin();
3146 j != rControllerList.end(); ++j)
3148 ::clearFilter(*j);
3153 //------------------------------------------------------------------------------
3154 void FmXFormShell::setControlLocks()
3156 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::setControlLocks" );
3157 if ( impl_checkDisposed() )
3158 return;
3160 Reference< XTabController> xCtrler(getActiveController(), UNO_QUERY);
3161 if (!xCtrler.is())
3162 return;
3164 Reference< XControlContainer> xControls(xCtrler->getContainer(), UNO_QUERY);
3165 if (!xControls.is())
3166 return;
3168 DBG_ASSERT( m_aControlLocks.empty(), "FmXFormShell::setControlLocks: locking state array isn't empty (called me twice ?)!" );
3170 Sequence< Reference< XControl> > aControls = xControls->getControls();
3171 const Reference< XControl>* pControls = aControls.getConstArray();
3173 // iterate through all bound controls, remember the old locking state, set the lock
3174 for (sal_Int32 i=0; i<aControls.getLength(); ++i)
3176 Reference< XBoundControl> xCtrl(pControls[i], UNO_QUERY);
3177 if (!xCtrl.is())
3179 // it may be a container of controls
3180 Reference< XIndexAccess> xContainer(pControls[i], UNO_QUERY);
3181 if (xContainer.is())
3182 { // no recursion. we only know top level control containers (e.g. grid controls)
3183 for (sal_Int16 j=0; j<xContainer->getCount(); ++j)
3185 xContainer->getByIndex(j) >>= xCtrl;
3186 if (!xCtrl.is())
3187 continue;
3189 m_aControlLocks.push_back( xCtrl->getLock() );
3190 xCtrl->setLock(sal_True);
3193 continue;
3196 m_aControlLocks.push_back( xCtrl->getLock() );
3197 xCtrl->setLock(sal_True);
3201 //------------------------------------------------------------------------------
3202 void FmXFormShell::restoreControlLocks()
3204 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::restoreControlLocks" );
3205 if ( impl_checkDisposed() )
3206 return;
3208 Reference< XTabController> xCtrler(getActiveController(), UNO_QUERY);
3209 if (!xCtrler.is())
3210 return;
3212 Reference< XControlContainer> xControls(xCtrler->getContainer(), UNO_QUERY);
3213 if (!xControls.is())
3214 return;
3216 Sequence< Reference< XControl> > aControls(xControls->getControls());
3217 const Reference< XControl>* pControls = aControls.getConstArray();
3219 // iterate through all bound controls, restore the old locking state
3220 size_t nBoundControl = 0;
3221 for (sal_Int32 i=0; i<aControls.getLength(); ++i)
3223 Reference< XBoundControl> xCtrl(pControls[i], UNO_QUERY);
3224 if (!xCtrl.is())
3226 // it may be a container of controls
3227 Reference< XIndexAccess> xContainer(pControls[i], UNO_QUERY);
3228 if (xContainer.is())
3229 { // no recursion. we only know top level control containers (e.g. grid controls)
3230 for (sal_Int16 j=0; j<xContainer->getCount(); ++j)
3232 xContainer->getByIndex(j) >>= xCtrl;
3233 if (!xCtrl.is())
3234 continue;
3236 DBG_ASSERT( nBoundControl < m_aControlLocks.size(), "FmXFormShell::restoreControlLocks: m_aControlLocks is invalid!" );
3237 xCtrl->setLock( m_aControlLocks[ nBoundControl ] );
3238 ++nBoundControl;
3241 continue;
3244 DBG_ASSERT( nBoundControl < m_aControlLocks.size(), "FmXFormShell::restoreControlLocks: m_aControlLocks is invalid!" );
3245 // a violation of this condition would mean a) setControlLocks hasn't been called or b) the ControlContainer
3246 // has changed since the last call to setControlLocks.
3247 // a) clearly is a fault of the programmer and b) shouldn't be possible (as we are in alive mode)
3248 xCtrl->setLock( m_aControlLocks[ nBoundControl ] );
3249 ++nBoundControl;
3251 ::std::vector< sal_Bool > aEmpty;
3252 m_aControlLocks.swap( aEmpty );
3255 //------------------------------------------------------------------------------
3256 void FmXFormShell::DoAsyncCursorAction(const Reference< XFormController>& _xController, CURSOR_ACTION _eWhat)
3258 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::DoAsyncCursorAction" );
3259 if ( impl_checkDisposed() )
3260 return;
3262 DBG_ASSERT(_xController.is(), "FmXFormShell::DoAsyncCursorAction : invalid argument !");
3263 DoAsyncCursorAction(Reference< XResultSet>(_xController->getModel(), UNO_QUERY), _eWhat);
3266 //------------------------------------------------------------------------------
3267 void FmXFormShell::DoAsyncCursorAction(const Reference< XResultSet>& _xForm, CURSOR_ACTION _eWhat)
3269 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::DoAsyncCursorAction" );
3270 if ( impl_checkDisposed() )
3271 return;
3273 ::osl::MutexGuard aGuard(m_aAsyncSafety);
3274 DBG_ASSERT(_xForm.is(), "FmXFormShell::DoAsyncCursorAction : invalid argument !");
3276 // build the access path for the form
3277 if (HasPendingCursorAction(_xForm))
3279 DBG_ERROR("FmXFormShell::DoAsyncCursorAction : invalid call !");
3280 return;
3283 CursorActionDescription& rDesc = m_aCursorActions[ _xForm ];
3284 // [] will create a new one if non-existent
3285 DBG_ASSERT(rDesc.pThread == NULL, "FmXFormShell::DoAsyncCursorAction : the cursor action thread for this form is still alive !");
3287 Reference< XResultSet > xCursor( getInternalForm( _xForm ), UNO_QUERY );
3288 switch (_eWhat)
3290 case CA_MOVE_TO_LAST :
3291 rDesc.pThread = new FmMoveToLastThread( xCursor );
3292 break;
3293 case CA_MOVE_ABSOLUTE:
3294 DBG_ERROR("FmXFormShell::DoAsyncCursorAction : CA_MOVE_ABSOLUTE not supported yet !");
3295 return;
3297 rDesc.pThread->SetTerminationHdl(LINK(this, FmXFormShell, OnCursorActionDone));
3298 rDesc.pThread->EnableSelfDelete(sal_False);
3300 rDesc.bCanceling = sal_False;
3302 // set the control locks before starting the thread
3303 DBG_ASSERT(getInternalForm(m_xActiveForm) == m_xActiveForm, "FmXFormShell::DoAsyncCursorAction : the active form should always be a internal one !");
3304 if (getInternalForm(_xForm) == m_xActiveForm)
3305 setControlLocks();
3307 // go ...
3308 rDesc.pThread->create();
3310 // set a priority slightly below normal
3311 rDesc.pThread->setPriority(::vos::OThread::TPriority_BelowNormal);
3314 //------------------------------------------------------------------------------
3315 sal_Bool FmXFormShell::HasPendingCursorAction(const Reference< XResultSet>& _xForm) const
3317 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::HasPendingCursorAction" );
3318 if ( impl_checkDisposed() )
3319 return sal_False;
3321 if (!_xForm.is())
3322 return sal_False;
3324 // TODO: if we ever re-implement the asynchronous cursor actions, then this will happen
3325 // in the controller, and not in the form. In such a case, we here probably need to check
3326 // whether the controller for the form has this "pending cursor action"
3328 return sal_False;
3331 //------------------------------------------------------------------------------
3332 sal_Bool FmXFormShell::HasPendingCursorAction(const Reference< XFormController>& xController) const
3334 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::HasPendingCursorAction" );
3335 if ( impl_checkDisposed() )
3336 return sal_False;
3338 if (!xController.is())
3339 return sal_False;
3341 return HasPendingCursorAction(Reference< XResultSet>(xController->getModel(), UNO_QUERY));
3344 //------------------------------------------------------------------------------
3345 sal_Bool FmXFormShell::HasAnyPendingCursorAction() const
3347 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::HasAnyPendingCursorAction" );
3348 ::osl::MutexGuard aGuard( const_cast< FmXFormShell* >( this )->m_aAsyncSafety );
3350 for ( CursorActions::const_iterator aIter = m_aCursorActions.begin(); aIter != m_aCursorActions.end(); ++aIter )
3352 if (((*aIter).second.pThread != NULL) || ((*aIter).second.nFinishedEvent != 0))
3353 return sal_True;
3355 return sal_False;
3358 //------------------------------------------------------------------------------
3359 void FmXFormShell::CancelAnyPendingCursorAction()
3361 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::CancelAnyPendingCursorAction" );
3362 if ( impl_checkDisposed() )
3363 return;
3365 ::osl::ResettableMutexGuard aGuard( m_aAsyncSafety );
3367 CursorActions::iterator aIter;
3368 for (aIter = m_aCursorActions.begin(); aIter != m_aCursorActions.end(); ++aIter)
3370 if (!(*aIter).second.nFinishedEvent && (*aIter).second.pThread)
3371 { // the thread is really running
3372 (*aIter).second.bCanceling = sal_True;
3374 aGuard.clear();
3375 (*aIter).second.pThread->StopItWait();
3376 // StopItWait returns after the termination handler (our OnCursorActionDone) has been called
3377 aGuard.reset();
3381 // all threads are finished (means canceled), now do the cleanup
3382 for (aIter = m_aCursorActions.begin(); aIter != m_aCursorActions.end(); ++aIter)
3384 if ((*aIter).second.pThread)
3386 LINK(this, FmXFormShell, OnCursorActionDoneMainThread).Call((*aIter).second.pThread);
3387 DBG_ASSERT((*aIter).second.pThread == NULL, "FmXFormShell::CancelAnyPendingCursorAction : strange behaviour of OnCursorActionDoneMainThread !");
3392 //------------------------------------------------------------------------------
3393 IMPL_LINK(FmXFormShell, OnCursorActionDone, FmCursorActionThread*, pThread)
3395 if ( impl_checkDisposed() )
3396 return 0L;
3398 ::osl::MutexGuard aGuard(m_aAsyncSafety);
3400 // search the pos of the thread within m_aCursorActions
3401 CursorActions::iterator aIter;
3402 for (aIter = m_aCursorActions.begin(); aIter != m_aCursorActions.end(); ++aIter)
3404 if ((*aIter).second.pThread == pThread)
3405 break;
3408 DBG_ASSERT(aIter != m_aCursorActions.end(), "FmXFormShell::OnCursorActionDone : could not ::std::find the thread !");
3409 DBG_ASSERT((*aIter).second.nFinishedEvent == 0, "FmXFormShell::OnCursorActionDone : another 'ActionDone' for this thread is pending !");
3410 // as we allow only one async action at a time (per form) this shouldn't happen
3412 if (!(*aIter).second.bCanceling)
3413 (*aIter).second.nFinishedEvent = Application::PostUserEvent(LINK(this, FmXFormShell, OnCursorActionDoneMainThread), pThread);
3414 // if bCanceling is sal_True an other thread's execution is in CancelAnyPendingCursorAction
3415 return 0L;
3418 //------------------------------------------------------------------------------
3419 IMPL_LINK(FmXFormShell, OnCursorActionDoneMainThread, FmCursorActionThread*, pThread)
3421 if ( impl_checkDisposed() )
3422 return 0L;
3424 ::osl::MutexGuard aGuard(m_aAsyncSafety);
3426 // search the pos of the thread within m_aCursorActions
3427 CursorActions::iterator aIter = m_aCursorActions.find( pThread->getDataSource() );
3428 DBG_ASSERT(aIter != m_aCursorActions.end(), "FmXFormShell::OnCursorActionDoneMainThread : could not ::std::find the thread data !");
3429 DBG_ASSERT((*aIter).second.pThread == pThread, "FmXFormShell::OnCursorActionDoneMainThread : invalid thread data !");
3431 // remember some thread parameters
3432 Reference< XResultSet> xForm(pThread->getDataSource(), UNO_QUERY);
3434 // throw away the thread
3435 delete (*aIter).second.pThread;
3436 (*aIter).second.pThread = NULL;
3437 (*aIter).second.nFinishedEvent = 0;
3438 (*aIter).second.bCanceling = sal_False;
3439 // as we allow exactly one thread per form we may remove this ones data from m_aCursorActions
3440 m_aCursorActions.erase(aIter);
3442 DBG_ASSERT(getInternalForm(m_xActiveForm) == m_xActiveForm, "FmXFormShell::DoAsyncCursorAction : the active form should always be a internal one !");
3443 DBG_ASSERT(getInternalForm(xForm) == xForm, "FmXFormShell::DoAsyncCursorAction : the thread's form should always be a internal one !");
3444 // if one of the two asserts above fails the upcoming comparison is senseless
3445 if (xForm == m_xActiveForm)
3447 // the active controller belongs to the form where the action is finished
3448 // -> re-enable the controls if they are not locked because of another running thread
3449 if (!HasPendingCursorAction(xForm))
3450 restoreControlLocks();
3453 m_pShell->GetViewShell()->GetViewFrame()->GetBindings().Invalidate(DatabaseSlotMap);
3454 // it may not be neccessary but me thinks it's faster without the check if we really have to do this
3456 return 0L;
3459 //------------------------------------------------------------------------------
3460 void FmXFormShell::CreateExternalView()
3462 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::CreateExternalView" );
3463 if ( impl_checkDisposed() )
3464 return;
3466 DBG_ASSERT(m_xAttachedFrame.is(), "FmXFormShell::CreateExternalView : no frame !");
3468 // the frame the external view is displayed in
3469 sal_Bool bAlreadyExistent = m_xExternalViewController.is();
3470 Reference< ::com::sun::star::frame::XFrame> xExternalViewFrame;
3471 ::rtl::OUString sFrameName = ::rtl::OUString::createFromAscii("_beamer");
3472 sal_Int32 nSearchFlags = ::com::sun::star::frame::FrameSearchFlag::CHILDREN | ::com::sun::star::frame::FrameSearchFlag::CREATE;
3474 Reference< XFormController> xCurrentNavController( getNavController());
3475 // the creation of the "partwindow" may cause a deactivate of the document which will result in our nav controller to be set to NULL
3477 // _first_ check if we have any valid fields we can use for the grid view
3478 // FS - 21.10.99 - 69219
3480 FmXBoundFormFieldIterator aModelIterator(xCurrentNavController->getModel());
3481 Reference< XPropertySet> xCurrentModelSet;
3482 sal_Bool bHaveUsableControls = sal_False;
3483 while ((xCurrentModelSet = Reference< XPropertySet>(aModelIterator.Next(), UNO_QUERY)).is())
3485 // the FmXBoundFormFieldIterator only supplies controls with a valid control source
3486 // so we just have to check the field type
3487 sal_Int16 nClassId = ::comphelper::getINT16(xCurrentModelSet->getPropertyValue(FM_PROP_CLASSID));
3488 switch (nClassId)
3490 case FormComponentType::IMAGECONTROL:
3491 case FormComponentType::CONTROL:
3492 continue;
3494 bHaveUsableControls = sal_True;
3495 break;
3498 if (!bHaveUsableControls)
3500 ErrorBox(NULL, WB_OK, SVX_RESSTR(RID_STR_NOCONTROLS_FOR_EXTERNALDISPLAY)).Execute();
3501 return;
3505 // load the component for external form views
3506 if (!bAlreadyExistent)
3508 URL aWantToDispatch;
3509 aWantToDispatch.Complete = FMURL_COMPONENT_FORMGRIDVIEW;
3511 Reference< ::com::sun::star::frame::XDispatchProvider> xProv(m_xAttachedFrame, UNO_QUERY);
3512 Reference< ::com::sun::star::frame::XDispatch> xDisp;
3513 if (xProv.is())
3514 xDisp = xProv->queryDispatch(aWantToDispatch, sFrameName, nSearchFlags);
3515 if (xDisp.is())
3517 xDisp->dispatch(aWantToDispatch, Sequence< PropertyValue>());
3520 // with this the component should be loaded, now search the frame where it resides in
3521 xExternalViewFrame = m_xAttachedFrame->findFrame(sFrameName, ::com::sun::star::frame::FrameSearchFlag::CHILDREN);
3522 if (xExternalViewFrame.is())
3524 m_xExternalViewController = xExternalViewFrame->getController();
3525 Reference< ::com::sun::star::lang::XComponent> xComp(m_xExternalViewController, UNO_QUERY);
3526 if (xComp.is())
3527 xComp->addEventListener((XEventListener*)(XPropertyChangeListener*)this);
3530 else
3532 xExternalViewFrame = m_xExternalViewController->getFrame();
3533 Reference< ::com::sun::star::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY);
3535 // if we display the active form we interpret the slot as "remove it"
3536 Reference< XForm> xCurrentModel(xCurrentNavController->getModel(), UNO_QUERY);
3537 if ((xCurrentModel == m_xExternalDisplayedForm) || (getInternalForm(xCurrentModel) == m_xExternalDisplayedForm))
3539 if ( m_xExternalViewController == getActiveController() )
3541 Reference< XFormController > xAsFormController( m_xExternalViewController, UNO_QUERY );
3542 ControllerFeatures aHelper( ::comphelper::getProcessServiceFactory(), xAsFormController, NULL );
3543 aHelper->commitCurrentControl();
3546 Reference< XFormController> xNewController(m_xExtViewTriggerController);
3547 CloseExternalFormViewer();
3548 setActiveController(xNewController);
3549 return;
3552 URL aClearURL;
3553 aClearURL.Complete = FMURL_GRIDVIEW_CLEARVIEW;
3555 Reference< ::com::sun::star::frame::XDispatch> xClear( xCommLink->queryDispatch(aClearURL, ::rtl::OUString::createFromAscii(""), 0));
3556 if (xClear.is())
3557 xClear->dispatch(aClearURL, Sequence< PropertyValue>());
3560 // interception of slots of the external view
3561 if (m_pExternalViewInterceptor)
3562 { // already intercepting ...
3563 if (m_pExternalViewInterceptor->getIntercepted() != xExternalViewFrame)
3564 { // ... but another frame -> create a new interceptor
3565 m_pExternalViewInterceptor->dispose();
3566 m_pExternalViewInterceptor->release();
3567 m_pExternalViewInterceptor = NULL;
3571 if (!m_pExternalViewInterceptor)
3573 Reference< ::com::sun::star::frame::XDispatchProviderInterception> xSupplier(xExternalViewFrame, UNO_QUERY);
3574 ::rtl::OUString sInterceptorScheme = FMURL_FORMSLOTS_PREFIX;
3575 sInterceptorScheme += ::rtl::OUString::createFromAscii("*");
3576 // m_pExternalViewInterceptor = new FmXDispatchInterceptorImpl(xSupplier, this, 1, Sequence< ::rtl::OUString >(&sInterceptorScheme, 1));
3577 // m_pExternalViewInterceptor->acquire();
3578 // TODO: re-implement this in a easier way than before: We need an interceptor at the xSupplier, which
3579 // forwards all queryDispatch requests to the FormController instance for which this "external view"
3580 // was triggered
3583 // get the dispatch interface of the frame so we can communicate (interceptable) with the controller
3584 Reference< ::com::sun::star::frame::XDispatchProvider> xCommLink(xExternalViewFrame, UNO_QUERY);
3586 if (m_xExternalViewController.is())
3588 DBG_ASSERT(xCommLink.is(), "FmXFormShell::CreateExternalView : the component doesn't have the necessary interfaces !");
3589 // collect the dispatchers we will need
3590 URL aAddColumnURL;
3591 aAddColumnURL.Complete = FMURL_GRIDVIEW_ADDCOLUMN;
3592 Reference< ::com::sun::star::frame::XDispatch> xAddColumnDispatch( xCommLink->queryDispatch(aAddColumnURL, ::rtl::OUString::createFromAscii(""), 0));
3593 URL aAttachURL;
3594 aAttachURL.Complete = FMURL_GRIDVIEW_ATTACHTOFORM;
3595 Reference< ::com::sun::star::frame::XDispatch> xAttachDispatch( xCommLink->queryDispatch(aAttachURL, ::rtl::OUString::createFromAscii(""), 0));
3597 if (xAddColumnDispatch.is() && xAttachDispatch.is())
3599 DBG_ASSERT(xCurrentNavController.is(), "FmXFormShell::CreateExternalView : invalid call : have no nav controller !");
3600 // first : dispatch the descriptions for the columns to add
3601 Sequence< Reference< XControl> > aCurrentControls(xCurrentNavController->getControls());
3603 sal_Int16 nAddedColumns = 0;
3605 // for radio buttons we need some special structures
3606 DECLARE_STL_USTRINGACCESS_MAP(Sequence< ::rtl::OUString>, MapUString2UstringSeq);
3607 DECLARE_STL_ITERATORS(MapUString2UstringSeq);
3608 DECLARE_STL_USTRINGACCESS_MAP(::rtl::OUString, FmMapUString2UString);
3609 DECLARE_STL_USTRINGACCESS_MAP(sal_Int16, FmMapUString2Int16);
3610 DECLARE_STL_ITERATORS(FmMapUString2Int16);
3612 MapUString2UstringSeq aRadioValueLists;
3613 MapUString2UstringSeq aRadioListSources;
3614 FmMapUString2UString aRadioControlSources;
3615 FmMapUString2Int16 aRadioPositions;
3617 FmXBoundFormFieldIterator aModelIterator(xCurrentNavController->getModel());
3618 Reference< XPropertySet> xCurrentModelSet;
3619 Any aCurrentBoundField;
3620 ::rtl::OUString sColumnType,aGroupName,sControlSource;
3621 Sequence< Property> aProps;
3622 Reference< XPropertySet> xCurrentBoundField;
3623 while ((xCurrentModelSet = Reference< XPropertySet>(aModelIterator.Next(), UNO_QUERY)).is())
3625 xCurrentModelSet->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xCurrentBoundField;
3626 OSL_ENSURE(xCurrentModelSet.is(),"xCurrentModelSet is null!");
3627 // create a description of the column to be created
3628 // first : determine it's type
3630 sal_Int16 nClassId = ::comphelper::getINT16(xCurrentModelSet->getPropertyValue(FM_PROP_CLASSID));
3631 switch (nClassId)
3633 case FormComponentType::RADIOBUTTON:
3635 // get the label of the button (this is the access key for our structures)
3636 aGroupName = getLabelName(xCurrentModelSet);
3638 // add the reference value of the radio button to the list source sequence
3639 Sequence< ::rtl::OUString>& aThisGroupLabels = aRadioListSources[aGroupName];
3640 sal_Int32 nNewSizeL = aThisGroupLabels.getLength() + 1;
3641 aThisGroupLabels.realloc(nNewSizeL);
3642 aThisGroupLabels.getArray()[nNewSizeL - 1] = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_REFVALUE));
3644 // add the label to the value list sequence
3645 Sequence< ::rtl::OUString>& aThisGroupControlSources = aRadioValueLists[aGroupName];
3646 sal_Int32 nNewSizeC = aThisGroupControlSources.getLength() + 1;
3647 aThisGroupControlSources.realloc(nNewSizeC);
3648 aThisGroupControlSources.getArray()[nNewSizeC - 1] = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_LABEL));
3650 // remember the controls source of the radio group
3651 sControlSource = ::comphelper::getString(xCurrentModelSet->getPropertyValue(FM_PROP_CONTROLSOURCE));
3652 if (aRadioControlSources.find(aGroupName) == aRadioControlSources.end())
3653 aRadioControlSources[aGroupName] = sControlSource;
3654 #ifdef DBG_UTIL
3655 else
3656 DBG_ASSERT(aRadioControlSources[aGroupName] == sControlSource,
3657 "FmXFormShell::CreateExternalView : inconsistent radio buttons detected !");
3658 // (radio buttons with the same name should have the same control source)
3659 #endif
3660 // remember the position within the columns
3661 if (aRadioPositions.find(aGroupName) == aRadioPositions.end())
3662 aRadioPositions[aGroupName] = (sal_Int16)nAddedColumns;
3664 // any further handling is done below
3666 continue;
3668 case FormComponentType::IMAGECONTROL:
3669 case FormComponentType::CONTROL:
3670 // no grid columns for these types (though they have a control source)
3671 continue;
3672 case FormComponentType::CHECKBOX:
3673 sColumnType = FM_COL_CHECKBOX; break;
3674 case FormComponentType::LISTBOX:
3675 sColumnType = FM_COL_LISTBOX; break;
3676 case FormComponentType::COMBOBOX:
3677 sColumnType = FM_COL_COMBOBOX; break;
3678 case FormComponentType::DATEFIELD:
3679 sColumnType = FM_COL_DATEFIELD; break;
3680 case FormComponentType::TIMEFIELD:
3681 sColumnType = FM_COL_TIMEFIELD; break;
3682 case FormComponentType::NUMERICFIELD:
3683 sColumnType = FM_COL_NUMERICFIELD; break;
3684 case FormComponentType::CURRENCYFIELD:
3685 sColumnType = FM_COL_CURRENCYFIELD; break;
3686 case FormComponentType::PATTERNFIELD:
3687 sColumnType = FM_COL_PATTERNFIELD; break;
3689 case FormComponentType::TEXTFIELD:
3691 sColumnType = FM_COL_TEXTFIELD;
3692 // we know at least two different controls which are TextFields : the basic edit field and the formatted
3693 // field. we distinguish them by their service name
3694 Reference< XServiceInfo> xInfo(xCurrentModelSet, UNO_QUERY);
3695 if (xInfo.is())
3697 sal_Int16 nObjectType = getControlTypeByObject(xInfo);
3698 if (OBJ_FM_FORMATTEDFIELD == nObjectType)
3699 sColumnType = FM_COL_FORMATTEDFIELD;
3702 break;
3703 default:
3704 sColumnType = FM_COL_TEXTFIELD; break;
3707 const sal_Int16 nDispatchArgs = 3;
3708 Sequence< PropertyValue> aDispatchArgs(nDispatchArgs);
3709 PropertyValue* pDispatchArgs = aDispatchArgs.getArray();
3711 // properties describing "meta data" about the column
3712 // the type
3713 pDispatchArgs->Name = FMARG_ADDCOL_COLUMNTYPE;
3714 pDispatchArgs->Value <<= sColumnType;
3715 ++pDispatchArgs;
3717 // the pos : append the col
3718 pDispatchArgs->Name = FMARG_ADDCOL_COLUMNPOS;
3719 pDispatchArgs->Value <<= nAddedColumns;
3720 ++pDispatchArgs;
3722 // the properties to forward to the new column
3723 Sequence< PropertyValue> aColumnProps(1);
3724 PropertyValue* pColumnProps = aColumnProps.getArray();
3726 // the label
3727 pColumnProps->Name = FM_PROP_LABEL;
3728 pColumnProps->Value <<= getLabelName(xCurrentModelSet);
3729 ++pColumnProps;
3731 // for all other props : transfer them
3732 Reference< XPropertySetInfo> xControlModelInfo( xCurrentModelSet->getPropertySetInfo());
3733 DBG_ASSERT(xControlModelInfo.is(), "FmXFormShell::CreateExternalView : the control model has no property info ! This will crash !");
3734 aProps = xControlModelInfo->getProperties();
3735 const Property* pProps = aProps.getConstArray();
3737 // realloc the control description sequence
3738 sal_Int32 nExistentDescs = pColumnProps - aColumnProps.getArray();
3739 aColumnProps.realloc(nExistentDescs + aProps.getLength());
3740 pColumnProps = aColumnProps.getArray() + nExistentDescs;
3742 for (sal_Int32 i=0; i<aProps.getLength(); ++i, ++pProps)
3744 if (pProps->Name.equals(FM_PROP_LABEL))
3745 // already set
3746 continue;
3747 if (pProps->Name.equals(FM_PROP_DEFAULTCONTROL))
3748 // allow the column's own "default control"
3749 continue;
3750 if (pProps->Attributes & PropertyAttribute::READONLY)
3751 // assume that properties which are readonly for the control are ro for the column to be created, too
3752 continue;
3754 pColumnProps->Name = pProps->Name;
3755 pColumnProps->Value = xCurrentModelSet->getPropertyValue(pProps->Name);
3756 ++pColumnProps;
3758 aColumnProps.realloc(pColumnProps - aColumnProps.getArray());
3760 // columns props are a dispatch argument
3761 pDispatchArgs->Name = ::rtl::OUString::createFromAscii("ColumnProperties"); // TODO : fmurl.*
3762 pDispatchArgs->Value = makeAny(aColumnProps);
3763 ++pDispatchArgs;
3764 DBG_ASSERT(nDispatchArgs == (pDispatchArgs - aDispatchArgs.getConstArray()),
3765 "FmXFormShell::CreateExternalView : forgot to adjust nDispatchArgs ?");
3767 // dispatch the "add column"
3768 xAddColumnDispatch->dispatch(aAddColumnURL, aDispatchArgs);
3769 ++nAddedColumns;
3772 // now for the radio button handling
3773 sal_Int16 nOffset(0);
3774 // properties describing the "direct" column properties
3775 const sal_Int16 nListBoxDescription = 6;
3776 Sequence< PropertyValue> aListBoxDescription(nListBoxDescription);
3777 for ( ConstFmMapUString2UStringIterator aCtrlSource = aRadioControlSources.begin();
3778 aCtrlSource != aRadioControlSources.end();
3779 ++aCtrlSource, ++nOffset
3783 PropertyValue* pListBoxDescription = aListBoxDescription.getArray();
3784 // label
3785 pListBoxDescription->Name = FM_PROP_LABEL;
3786 pListBoxDescription->Value <<= (*aCtrlSource).first;
3787 ++pListBoxDescription;
3789 // control source
3790 pListBoxDescription->Name = FM_PROP_CONTROLSOURCE;
3791 pListBoxDescription->Value <<= (*aCtrlSource).second;
3792 ++pListBoxDescription;
3794 // bound column
3795 pListBoxDescription->Name = FM_PROP_BOUNDCOLUMN;
3796 pListBoxDescription->Value <<= (sal_Int16)1;
3797 ++pListBoxDescription;
3799 // content type
3800 pListBoxDescription->Name = FM_PROP_LISTSOURCETYPE;
3801 ListSourceType eType = ListSourceType_VALUELIST;
3802 pListBoxDescription->Value = makeAny(eType);
3803 ++pListBoxDescription;
3805 // list source
3806 MapUString2UstringSeq::const_iterator aCurrentListSource = aRadioListSources.find((*aCtrlSource).first);
3807 DBG_ASSERT(aCurrentListSource != aRadioListSources.end(),
3808 "FmXFormShell::CreateExternalView : inconsistent radio descriptions !");
3809 pListBoxDescription->Name = FM_PROP_LISTSOURCE;
3810 pListBoxDescription->Value = makeAny((*aCurrentListSource).second);
3811 ++pListBoxDescription;
3813 // value list
3814 MapUString2UstringSeq::const_iterator aCurrentValueList = aRadioValueLists.find((*aCtrlSource).first);
3815 DBG_ASSERT(aCurrentValueList != aRadioValueLists.end(),
3816 "FmXFormShell::CreateExternalView : inconsistent radio descriptions !");
3817 pListBoxDescription->Name = FM_PROP_STRINGITEMLIST;
3818 pListBoxDescription->Value = makeAny(((*aCurrentValueList).second));
3819 ++pListBoxDescription;
3821 DBG_ASSERT(nListBoxDescription == (pListBoxDescription - aListBoxDescription.getConstArray()),
3822 "FmXFormShell::CreateExternalView : forgot to adjust nListBoxDescription ?");
3824 // properties describing the column "meta data"
3825 const sal_Int16 nDispatchArgs = 3;
3826 Sequence< PropertyValue> aDispatchArgs(nDispatchArgs);
3827 PropertyValue* pDispatchArgs = aDispatchArgs.getArray();
3829 // column type : listbox
3830 pDispatchArgs->Name = FMARG_ADDCOL_COLUMNTYPE;
3831 ::rtl::OUString fColName = FM_COL_LISTBOX;
3832 pDispatchArgs->Value <<= fColName;
3833 // pDispatchArgs->Value <<= (::rtl::OUString)FM_COL_LISTBOX;
3834 ++pDispatchArgs;
3836 // column position
3837 pDispatchArgs->Name = FMARG_ADDCOL_COLUMNPOS;
3838 FmMapUString2Int16::const_iterator aOffset = aRadioPositions.find((*aCtrlSource).first);
3839 DBG_ASSERT(aOffset != aRadioPositions.end(),
3840 "FmXFormShell::CreateExternalView : inconsistent radio descriptions !");
3841 sal_Int16 nPosition = (*aOffset).second;
3842 nPosition = nPosition + nOffset;
3843 // we alread inserted nOffset additinal columns ....
3844 pDispatchArgs->Value <<= nPosition;
3845 ++pDispatchArgs;
3847 // the
3848 pDispatchArgs->Name = ::rtl::OUString::createFromAscii("ColumnProperties"); // TODO : fmurl.*
3849 pDispatchArgs->Value = makeAny(aListBoxDescription);
3850 ++pDispatchArgs;
3851 DBG_ASSERT(nDispatchArgs == (pDispatchArgs - aDispatchArgs.getConstArray()),
3852 "FmXFormShell::CreateExternalView : forgot to adjust nDispatchArgs ?");
3854 // dispatch the "add column"
3855 xAddColumnDispatch->dispatch(aAddColumnURL, aDispatchArgs);
3856 ++nAddedColumns;
3860 DBG_ASSERT(nAddedColumns > 0, "FmXFormShell::CreateExternalView : no controls (inconsistent) !");
3861 // we should have checked if we have any usable controls (see above).
3863 // "load" the "form" of the external view
3864 PropertyValue aArg;
3865 aArg.Name = FMARG_ATTACHTO_MASTERFORM;
3866 Reference< XResultSet> xForm(xCurrentNavController->getModel(), UNO_QUERY);
3867 aArg.Value <<= xForm;
3869 m_xExternalDisplayedForm = Reference< XResultSet>(xForm, UNO_QUERY);
3870 // do this before dispatching the "attach" command, as the atach may result in a call to our queryDispatch (for the FormSlots)
3871 // whichs needs the m_xExternalDisplayedForm
3873 xAttachDispatch->dispatch(aAttachURL, Sequence< PropertyValue>(&aArg, 1));
3875 m_xExtViewTriggerController = xCurrentNavController;
3877 // we want to know modifications done in the external view
3878 // if the external controller is a XFormController we can use all our default handlings for it
3879 Reference< XFormController> xFormController(m_xExternalViewController, UNO_QUERY);
3880 if (xFormController.is())
3881 xFormController->addActivateListener((XFormControllerListener*)this);
3884 #ifdef DBG_UTIL
3885 else
3887 DBG_ERROR("FmXFormShell::CreateExternalView : could not create the external form view !");
3889 #endif
3890 InvalidateSlot( SID_FM_VIEW_AS_GRID, sal_False );
3893 //------------------------------------------------------------------------
3894 void FmXFormShell::implAdjustConfigCache()
3896 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::implAdjustConfigCache" );
3897 // get (cache) the wizard usage flag
3898 Sequence< ::rtl::OUString > aNames(1);
3899 aNames[0] = ::rtl::OUString::createFromAscii("FormControlPilotsEnabled");
3900 Sequence< Any > aFlags = GetProperties(aNames);
3901 if (1 == aFlags.getLength())
3902 m_bUseWizards = ::cppu::any2bool(aFlags[0]);
3905 //------------------------------------------------------------------------
3906 void FmXFormShell::Notify( const com::sun::star::uno::Sequence< rtl::OUString >& _rPropertyNames)
3908 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::Notify" );
3909 if ( impl_checkDisposed() )
3910 return;
3912 const ::rtl::OUString* pSearch = _rPropertyNames.getConstArray();
3913 const ::rtl::OUString* pSearchTil = pSearch + _rPropertyNames.getLength();
3914 for (;pSearch < pSearchTil; ++pSearch)
3915 if (0 == pSearch->compareToAscii("FormControlPilotsEnabled"))
3917 implAdjustConfigCache();
3918 InvalidateSlot( SID_FM_USE_WIZARDS, sal_True );
3922 //------------------------------------------------------------------------
3923 void FmXFormShell::SetWizardUsing(sal_Bool _bUseThem)
3925 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetWizardUsing" );
3926 m_bUseWizards = _bUseThem;
3928 Sequence< ::rtl::OUString > aNames(1);
3929 aNames[0] = ::rtl::OUString::createFromAscii("FormControlPilotsEnabled");
3930 Sequence< Any > aValues(1);
3931 aValues[0] = ::cppu::bool2any(m_bUseWizards);
3932 PutProperties(aNames, aValues);
3935 //------------------------------------------------------------------------
3936 void FmXFormShell::viewDeactivated( FmFormView& _rCurrentView, sal_Bool _bDeactivateController /* = sal_True */ )
3938 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::viewDeactivated" );
3939 OSL_TRACE( "--- FmXFormShell::viewDeactivated: %p, %p, ........\n", this, &_rCurrentView );
3941 if ( _rCurrentView.GetImpl() && !_rCurrentView.IsDesignMode() )
3943 _rCurrentView.GetImpl()->Deactivate( _bDeactivateController );
3946 // if we have an async load operation pending for the 0-th page for this view,
3947 // we need to cancel this
3948 // 103727 - 2002-09-26 - fs@openoffice.org
3949 FmFormPage* pPage = _rCurrentView.GetCurPage();
3950 if ( pPage )
3952 // move all events from our queue to a new one, omit the events for the deactivated
3953 // page
3954 ::std::queue< FmLoadAction > aNewEvents;
3955 while ( m_aLoadingPages.size() )
3957 FmLoadAction aAction = m_aLoadingPages.front();
3958 m_aLoadingPages.pop();
3959 if ( pPage != aAction.pPage )
3961 aNewEvents.push( aAction );
3963 else
3965 Application::RemoveUserEvent( aAction.nEventId );
3968 m_aLoadingPages = aNewEvents;
3971 // remove callbacks at the page
3972 if ( pPage )
3974 OSL_TRACE( "--- FmXFormShell::resetHandler : %p, ........, %p\n", this, pPage );
3975 pPage->GetImpl().SetFormsCreationHdl( Link() );
3977 UpdateForms( sal_True );
3980 //------------------------------------------------------------------------
3981 IMPL_LINK( FmXFormShell, OnFirstTimeActivation, void*, /*NOTINTERESTEDIN*/ )
3983 if ( impl_checkDisposed() )
3984 return 0L;
3986 m_nActivationEvent = 0;
3987 SfxObjectShell* pDocument = m_pShell->GetObjectShell();
3989 if ( pDocument && !pDocument->HasName() )
3991 if ( isEnhancedForm() )
3993 // show the data navigator
3994 if ( !m_pShell->GetViewShell()->GetViewFrame()->HasChildWindow( SID_FM_SHOW_DATANAVIGATOR ) )
3995 m_pShell->GetViewShell()->GetViewFrame()->ToggleChildWindow( SID_FM_SHOW_DATANAVIGATOR );
3999 return 0L;
4002 //------------------------------------------------------------------------
4003 IMPL_LINK( FmXFormShell, OnFormsCreated, FmFormPage*, /*_pPage*/ )
4005 UpdateForms( sal_True );
4006 return 0L;
4009 //------------------------------------------------------------------------
4010 void FmXFormShell::viewActivated( FmFormView& _rCurrentView, sal_Bool _bSyncAction /* = sal_False */ )
4012 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::viewActivated" );
4013 OSL_TRACE( "--- FmXFormShell::viewActivated : %p, %p, ........\n", this, &_rCurrentView );
4015 FmFormPage* pPage = _rCurrentView.GetCurPage();
4017 // activate our view if we are activated ourself
4018 // FS - 30.06.99 - 67308
4019 if ( _rCurrentView.GetImpl() && !_rCurrentView.IsDesignMode() )
4021 // load forms for the page the current view belongs to
4022 if ( pPage )
4024 if ( !pPage->GetImpl().hasEverBeenActivated() )
4025 loadForms( pPage, FORMS_LOAD | ( _bSyncAction ? FORMS_SYNC : FORMS_ASYNC ) );
4026 pPage->GetImpl().setHasBeenActivated( );
4029 // first-time initializations for the views
4030 if ( !_rCurrentView.GetImpl()->hasEverBeenActivated( ) )
4032 _rCurrentView.GetImpl()->onFirstViewActivation( PTR_CAST( FmFormModel, _rCurrentView.GetModel() ) );
4033 _rCurrentView.GetImpl()->setHasBeenActivated( );
4036 // activate the current view
4037 _rCurrentView.GetImpl()->Activate( _bSyncAction );
4040 // set callbacks at the page
4041 if ( pPage )
4043 OSL_TRACE( "--- FmXFormShell::setHandler : %p, ........, %p\n", this, pPage );
4044 pPage->GetImpl().SetFormsCreationHdl( LINK( this, FmXFormShell, OnFormsCreated ) );
4047 UpdateForms( sal_True );
4049 if ( !hasEverBeenActivated() )
4051 m_nActivationEvent = Application::PostUserEvent( LINK( this, FmXFormShell, OnFirstTimeActivation ) );
4052 setHasBeenActivated();
4055 // find a default "current form", if there is none, yet
4056 // #i88186# / 2008-04-12 / frank.schoenheit@sun.com
4057 impl_defaultCurrentForm_nothrow();
4060 //------------------------------------------------------------------------------
4061 void FmXFormShell::impl_defaultCurrentForm_nothrow()
4063 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::impl_defaultCurrentForm_nothrow" );
4064 if ( impl_checkDisposed() )
4065 return;
4067 if ( m_xCurrentForm.is() )
4068 // no action required
4069 return;
4071 FmFormView* pFormView = m_pShell->GetFormView();
4072 FmFormPage* pPage = pFormView ? pFormView->GetCurPage() : NULL;
4073 if ( !pPage )
4074 return;
4078 Reference< XIndexAccess > xForms( pPage->GetForms( false ), UNO_QUERY );
4079 if ( !xForms.is() || !xForms->hasElements() )
4080 return;
4082 Reference< XForm > xNewCurrentForm( xForms->getByIndex(0), UNO_QUERY_THROW );
4083 impl_updateCurrentForm( xNewCurrentForm );
4085 catch( const Exception& )
4087 DBG_UNHANDLED_EXCEPTION();
4091 //------------------------------------------------------------------------------
4092 void FmXFormShell::smartControlReset( const Reference< XIndexAccess >& _rxModels )
4094 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::smartControlReset" );
4095 if (!_rxModels.is())
4097 DBG_ERROR("FmXFormShell::smartControlReset: invalid container!");
4098 return;
4101 static const ::rtl::OUString sClassIdPropertyName = FM_PROP_CLASSID;
4102 static const ::rtl::OUString sBoundFieldPropertyName = FM_PROP_BOUNDFIELD;
4103 sal_Int32 nCount = _rxModels->getCount();
4104 Reference< XPropertySet > xCurrent;
4105 Reference< XPropertySetInfo > xCurrentInfo;
4106 Reference< XPropertySet > xBoundField;
4108 for (sal_Int32 i=0; i<nCount; ++i)
4110 _rxModels->getByIndex(i) >>= xCurrent;
4111 if (xCurrent.is())
4112 xCurrentInfo = xCurrent->getPropertySetInfo();
4113 else
4114 xCurrentInfo.clear();
4115 if (!xCurrentInfo.is())
4116 continue;
4118 if (xCurrentInfo->hasPropertyByName(sClassIdPropertyName))
4119 { // it's a control model
4121 // check if this control is bound to a living database field
4122 if (xCurrentInfo->hasPropertyByName(sBoundFieldPropertyName))
4123 xCurrent->getPropertyValue(sBoundFieldPropertyName) >>= xBoundField;
4124 else
4125 xBoundField.clear();
4127 // reset only if it's *not* bound
4128 bool bReset = !xBoundField.is();
4130 // and additionally, check if it has an external value binding
4131 Reference< XBindableValue > xBindable( xCurrent, UNO_QUERY );
4132 if ( xBindable.is() && xBindable->getValueBinding().is() )
4133 bReset = false;
4135 if ( bReset )
4137 Reference< XReset > xControlReset( xCurrent, UNO_QUERY );
4138 if ( xControlReset.is() )
4139 xControlReset->reset();
4142 else
4144 Reference< XIndexAccess > xContainer(xCurrent, UNO_QUERY);
4145 if (xContainer.is())
4146 smartControlReset(xContainer);
4151 //------------------------------------------------------------------------
4152 IMPL_LINK( FmXFormShell, OnLoadForms, FmFormPage*, /*_pPage*/ )
4154 FmLoadAction aAction = m_aLoadingPages.front();
4155 m_aLoadingPages.pop();
4157 loadForms( aAction.pPage, aAction.nFlags & ~FORMS_ASYNC );
4158 return 0L;
4161 //------------------------------------------------------------------------
4162 void FmXFormShell::loadForms( FmFormPage* _pPage, const sal_uInt16 _nBehaviour /* FORMS_LOAD | FORMS_SYNC */ )
4164 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::loadForms" );
4165 DBG_ASSERT( ( _nBehaviour & ( FORMS_ASYNC | FORMS_UNLOAD ) ) != ( FORMS_ASYNC | FORMS_UNLOAD ),
4166 "FmXFormShell::loadForms: async loading not supported - this will heavily fail!" );
4168 if ( _nBehaviour & FORMS_ASYNC )
4170 m_aLoadingPages.push( FmLoadAction(
4171 _pPage,
4172 _nBehaviour,
4173 Application::PostUserEvent( LINK( this, FmXFormShell, OnLoadForms ), _pPage )
4174 ) );
4175 return;
4178 DBG_ASSERT( _pPage, "FmXFormShell::loadForms: invalid page!" );
4179 if ( _pPage )
4181 // lock the undo env so the forms can change non-transient properties while loading
4182 // (without this my doc's modified flag would be set)
4183 FmFormModel* pModel = PTR_CAST( FmFormModel, _pPage->GetModel() );
4184 DBG_ASSERT( pModel, "FmXFormShell::loadForms: invalid model!" );
4185 if ( pModel )
4186 pModel->GetUndoEnv().Lock();
4188 // load all forms
4189 Reference< XIndexAccess > xForms;
4190 xForms = xForms.query( _pPage->GetForms( false ) );
4192 if ( xForms.is() )
4194 Reference< XLoadable > xForm;
4195 sal_Bool bFormWasLoaded = sal_False;
4196 for ( sal_Int32 j = 0, nCount = xForms->getCount(); j < nCount; ++j )
4198 xForms->getByIndex( j ) >>= xForm;
4199 bFormWasLoaded = sal_False;
4200 // a database form must be loaded for
4203 if ( 0 == ( _nBehaviour & FORMS_UNLOAD ) )
4205 if ( ::isLoadable( xForm ) && !xForm->isLoaded() )
4206 xForm->load();
4208 else
4210 if ( xForm->isLoaded() )
4212 bFormWasLoaded = sal_True;
4213 xForm->unload();
4217 catch( const Exception& )
4219 DBG_UNHANDLED_EXCEPTION();
4222 // reset the form if it was loaded
4223 if ( bFormWasLoaded )
4225 Reference< XIndexAccess > xContainer( xForm, UNO_QUERY );
4226 DBG_ASSERT( xContainer.is(), "FmXFormShell::loadForms: the form is no container!" );
4227 if ( xContainer.is() )
4228 smartControlReset( xContainer );
4233 if ( pModel )
4234 // unlock the environment
4235 pModel->GetUndoEnv().UnLock();
4239 //------------------------------------------------------------------------
4240 void FmXFormShell::ExecuteTextAttribute( SfxRequest& _rReq )
4242 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ExecuteTextAttribute" );
4243 m_pTextShell->ExecuteTextAttribute( _rReq );
4246 //------------------------------------------------------------------------
4247 void FmXFormShell::GetTextAttributeState( SfxItemSet& _rSet )
4249 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::GetTextAttributeState" );
4250 m_pTextShell->GetTextAttributeState( _rSet );
4253 //------------------------------------------------------------------------
4254 bool FmXFormShell::IsActiveControl( bool _bCountRichTextOnly ) const
4256 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::IsActiveControl" );
4257 return m_pTextShell->IsActiveControl( _bCountRichTextOnly );
4260 //------------------------------------------------------------------------
4261 void FmXFormShell::ForgetActiveControl()
4263 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::ForgetActiveControl" );
4264 m_pTextShell->ForgetActiveControl();
4267 //------------------------------------------------------------------------
4268 void FmXFormShell::SetControlActivationHandler( const Link& _rHdl )
4270 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::SetControlActivationHandler" );
4271 m_pTextShell->SetControlActivationHandler( _rHdl );
4273 //------------------------------------------------------------------------
4274 void FmXFormShell::handleShowPropertiesRequest()
4276 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::handleShowPropertiesRequest" );
4277 if ( onlyControlsAreMarked() )
4278 ShowSelectionProperties( sal_True );
4281 //------------------------------------------------------------------------
4282 void FmXFormShell::handleMouseButtonDown( const SdrViewEvent& _rViewEvent )
4284 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmXFormShell::handleMouseButtonDown" );
4285 // catch simple double clicks
4286 if ( ( _rViewEvent.nMouseClicks == 2 ) && ( _rViewEvent.nMouseCode == MOUSE_LEFT ) )
4288 if ( _rViewEvent.eHit == SDRHIT_MARKEDOBJECT )
4290 if ( onlyControlsAreMarked() )
4291 ShowSelectionProperties( sal_True );
4296 //==============================================================================
4297 //==============================================================================
4298 SearchableControlIterator::SearchableControlIterator(Reference< XInterface> xStartingPoint)
4299 :IndexAccessIterator(xStartingPoint)
4303 //------------------------------------------------------------------------------
4304 sal_Bool SearchableControlIterator::ShouldHandleElement(const Reference< XInterface>& xElement)
4306 // wenn das Ding eine ControlSource und einen BoundField-Property hat
4307 Reference< XPropertySet> xProperties(xElement, UNO_QUERY);
4308 if (::comphelper::hasProperty(FM_PROP_CONTROLSOURCE, xProperties) && ::comphelper::hasProperty(FM_PROP_BOUNDFIELD, xProperties))
4310 // und das BoundField gueltig ist
4311 Reference< XPropertySet> xField;
4312 xProperties->getPropertyValue(FM_PROP_BOUNDFIELD) >>= xField;
4313 if (xField.is())
4315 // nehmen wir's
4316 m_sCurrentValue = ::comphelper::getString(xProperties->getPropertyValue(FM_PROP_CONTROLSOURCE));
4317 return sal_True;
4321 // wenn es ein Grid-Control ist
4322 if (::comphelper::hasProperty(FM_PROP_CLASSID, xProperties))
4324 Any aClassId( xProperties->getPropertyValue(FM_PROP_CLASSID) );
4325 if (::comphelper::getINT16(aClassId) == FormComponentType::GRIDCONTROL)
4327 m_sCurrentValue = ::rtl::OUString();
4328 return sal_True;
4332 return sal_False;
4335 //------------------------------------------------------------------------------
4336 sal_Bool SearchableControlIterator::ShouldStepInto(const Reference< XInterface>& /*xContainer*/) const
4338 return sal_True;
4341 //==============================================================================
4342 //==============================================================================
4344 SV_IMPL_PTRARR(StatusForwarderArray, SfxStatusForwarder*)
4346 SFX_IMPL_MENU_CONTROL(ControlConversionMenuController, SfxBoolItem);
4348 //------------------------------------------------------------------------------
4349 ControlConversionMenuController::ControlConversionMenuController( sal_uInt16 _nId, Menu& _rMenu, SfxBindings& _rBindings )
4350 :SfxMenuControl( _nId, _rBindings )
4351 ,m_pMainMenu( &_rMenu )
4352 ,m_pConversionMenu( NULL )
4354 if ( _nId == SID_FM_CHANGECONTROLTYPE )
4356 m_pConversionMenu = FmXFormShell::GetConversionMenu();
4357 _rMenu.SetPopupMenu( _nId, m_pConversionMenu );
4359 for (sal_Int16 i=0; i<m_pConversionMenu->GetItemCount(); ++i)
4361 _rBindings.Invalidate(m_pConversionMenu->GetItemId(i));
4362 SfxStatusForwarder* pForwarder = new SfxStatusForwarder(m_pConversionMenu->GetItemId(i), *this);
4363 m_aStatusForwarders.C40_INSERT(SfxStatusForwarder, pForwarder, m_aStatusForwarders.Count());
4368 //------------------------------------------------------------------------------
4369 ControlConversionMenuController::~ControlConversionMenuController()
4371 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "ControlConversionMenuController::~ControlConversionMenuController" );
4372 m_pMainMenu->SetPopupMenu(SID_FM_CHANGECONTROLTYPE, NULL);
4373 delete m_pConversionMenu;
4376 //------------------------------------------------------------------------------
4377 void ControlConversionMenuController::StateChanged(sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState)
4379 if (nSID == GetId())
4380 SfxMenuControl::StateChanged(nSID, eState, pState);
4381 else if (FmXFormShell::isControlConversionSlot(nSID))
4383 if ((m_pConversionMenu->GetItemPos(nSID) != MENU_ITEM_NOTFOUND) && (eState == SFX_ITEM_DISABLED))
4385 m_pConversionMenu->RemoveItem(m_pConversionMenu->GetItemPos(nSID));
4387 else if ((m_pConversionMenu->GetItemPos(nSID) == MENU_ITEM_NOTFOUND) && (eState != SFX_ITEM_DISABLED))
4389 // We can't simply re-insert the item because we have a clear order for all the our items.
4390 // So first we have to determine the position of the item to insert.
4391 PopupMenu* pSource = FmXFormShell::GetConversionMenu();
4392 USHORT nSourcePos = pSource->GetItemPos(nSID);
4393 DBG_ASSERT(nSourcePos != MENU_ITEM_NOTFOUND, "ControlConversionMenuController::StateChanged : FmXFormShell supplied an invalid menu !");
4394 USHORT nPrevInSource = nSourcePos;
4395 USHORT nPrevInConversion = MENU_ITEM_NOTFOUND;
4396 while (nPrevInSource>0)
4398 sal_Int16 nPrevId = pSource->GetItemId(--nPrevInSource);
4400 // do we have the source's predecessor in our conversion menu, too ?
4401 nPrevInConversion = m_pConversionMenu->GetItemPos(nPrevId);
4402 if (nPrevInConversion != MENU_ITEM_NOTFOUND)
4403 break;
4405 if (MENU_ITEM_NOTFOUND == nPrevInConversion)
4406 // none of the items which precede the nSID-slot in the source menu are present in our conversion menu
4407 nPrevInConversion = sal::static_int_cast< USHORT >(-1); // put the item at the first position
4408 m_pConversionMenu->InsertItem(nSID, pSource->GetItemText(nSID), pSource->GetItemBits(nSID), ++nPrevInConversion);
4409 m_pConversionMenu->SetItemImage(nSID, pSource->GetItemImage(nSID));
4410 m_pConversionMenu->SetHelpId(nSID, pSource->GetHelpId(nSID));
4412 delete pSource;
4414 m_pMainMenu->EnableItem(SID_FM_CHANGECONTROLTYPE, m_pConversionMenu->GetItemCount() > 0);
4416 else
4418 DBG_ERROR("ControlConversionMenuController::StateChanged : unknown id !");
4422 //==================================================================
4424 FmCursorActionThread::FmCursorActionThread(const Reference< XResultSet>& _xDataSource, const UniString& _rStopperCaption)
4425 :m_xDataSource(_xDataSource)
4426 ,m_sStopperCaption(_rStopperCaption)
4427 ,m_bCanceled(sal_False)
4428 ,m_bDeleteMyself(sal_False)
4429 ,m_bDisposeCursor(sal_False)
4430 ,m_bTerminated(sal_False)
4431 ,m_bRunFailed(sal_False)
4433 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "svx", "Ocke.Janssen@sun.com", "FmCursorActionThread::FmCursorActionThread" );
4434 DBG_ASSERT(m_xDataSource.is() && Reference< XCancellable>(m_xDataSource, UNO_QUERY).is(),
4435 "FmCursorActionThread::FmCursorActionThread : invalid cursor !");
4438 //------------------------------------------------------------------------------
4439 void FmCursorActionThread::run()
4441 // On instantiation of a SfxCancellable the application is notified and 'switches on' the red stop button.
4442 // Unfortunally this is conditioned with the acquirement of the solar mutex, and the application tries
4443 // only once and ignores the notification if it fails.
4444 // To prevent that we get the solar mutex and _block_ 'til we got it.
4445 // As we are in the 'top level execution' of this thread (with a rather small stack and no other mutexes locked)
4446 // we shouldn't experience problems with deadlocks ...
4447 ::vos::OClearableGuard aSolarGuard(Application::GetSolarMutex());
4448 ThreadStopper* pStopper = new ThreadStopper(this, m_sStopperCaption);
4449 aSolarGuard.clear();
4451 // we're not canceled yet
4452 ::osl::ClearableMutexGuard aInitGuard(m_aAccessSafety);
4453 m_bCanceled = sal_False;
4454 m_bRunFailed = sal_False;
4455 aInitGuard.clear();
4457 // start it
4460 RunImpl();
4462 catch(SQLException e)
4464 ::osl::MutexGuard aErrorGuard(m_aAccessSafety);
4465 m_bRunFailed = sal_True;
4466 m_aRunException = e;
4468 catch(Exception&)
4470 DBG_ERROR("FmCursorActionThread::run : catched a non-database exception !");
4474 sal_Bool bReallyCanceled;
4475 ::osl::ClearableMutexGuard aEvalGuard(m_aAccessSafety);
4476 bReallyCanceled = m_bCanceled;
4477 aEvalGuard.clear();
4479 pStopper->OwnerTerminated();
4480 // this will cause the stopper to delete itself (in the main thread) so we don't have to care of the
4481 // solar mutex
4484 //------------------------------------------------------------------------------
4485 void FmCursorActionThread::onTerminated()
4487 ::osl::ClearableMutexGuard aResetGuard(m_aAccessSafety);
4488 if (m_aTerminationHandler.IsSet())
4489 m_aTerminationHandler.Call(this);
4491 if (IsCursorDisposeEnabled())
4493 Reference< ::com::sun::star::lang::XComponent> xDataSourceComponent(m_xDataSource, UNO_QUERY);
4494 if (xDataSourceComponent.is())
4495 xDataSourceComponent->dispose();
4498 aResetGuard.clear();
4499 // with this StopItWait has a chance to do it's Terminated()
4501 ::osl::MutexGuard aGuard(m_aFinalExitControl);
4502 // Terminated() in StopItWait still returns sal_False
4503 m_bTerminated = sal_True;
4504 // Terminated() now returns sal_True, but StopItWait can't exit until this method exits (because of the guarded m_aFinalExitControl)
4506 if (IsSelfDeleteEnabled())
4507 delete this;
4510 //------------------------------------------------------------------------------
4511 void FmCursorActionThread::StopIt()
4513 ::osl::MutexGuard aGuard(m_aAccessSafety);
4514 m_bCanceled = sal_True;
4516 Reference< XCancellable> xCancel(m_xDataSource, UNO_QUERY);
4517 DBG_ASSERT(xCancel.is(), "FmCursorActionThread::StopIt : invalid cursor !");
4518 xCancel->cancel();
4521 //------------------------------------------------------------------------------
4522 void FmCursorActionThread::StopItWait()
4524 StopIt();
4526 while (!Terminated())
4529 // OnTerminated has been called, but we can't simply exit : Suppose the caller want's to delete the thread object
4530 // immediately after returning from StopItWait. With the following guard we ensure that we exit this method
4531 // only after onTerminated has exited.
4532 ::osl::ClearableMutexGuard aGuard(m_aFinalExitControl);
4534 // now onTerminated has exited, so we can leave, too
4537 //------------------------------------------------------------------------------
4538 FmCursorActionThread::ThreadStopper::ThreadStopper(FmCursorActionThread* pOwner, const UniString& rTitle)
4539 :SfxCancellable(SFX_APP()->GetCancelManager(), rTitle)
4540 ,m_pOwner(pOwner)
4544 //------------------------------------------------------------------------------
4545 void FmCursorActionThread::ThreadStopper::Cancel()
4547 if (!m_pOwner) // the owner is already terminated and we're waiting for the OnDeleteInMainThread event
4548 return;
4550 ::osl::MutexGuard aGuard(m_pOwner->m_aAccessSafety);
4551 if (IsCancelled())
4552 // we already did pass this to our owner
4553 return;
4555 SfxCancellable::Cancel();
4556 m_pOwner->StopIt();
4559 //------------------------------------------------------------------------------
4560 void FmCursorActionThread::ThreadStopper::OwnerTerminated()
4562 m_pOwner = NULL;
4563 Application::PostUserEvent(LINK(this, FmCursorActionThread::ThreadStopper, OnDeleteInMainThread), this);
4566 //------------------------------------------------------------------------------
4567 IMPL_LINK(FmCursorActionThread::ThreadStopper, OnDeleteInMainThread, FmCursorActionThread::ThreadStopper*, pThis)
4569 delete pThis;
4570 return 0L;
4573 //==============================================================================