xref: /trunk/main/svx/source/fmcomp/fmgridif.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svx.hxx"
30 
31 #include "svx/fmgridif.hxx"
32 #include "fmprop.hrc"
33 #include "fmservs.hxx"
34 #include "svx/fmtools.hxx"
35 #include "fmurl.hxx"
36 #include "formcontrolfactory.hxx"
37 #include "gridcell.hxx"
38 #include "sdbdatacolumn.hxx"
39 #include "svx/fmgridcl.hxx"
40 #include "svx/svxids.hrc"
41 #include <tools/urlobj.hxx>
42 
43 /** === begin UNO includes === **/
44 #include <com/sun/star/awt/PosSize.hpp>
45 #include <com/sun/star/beans/PropertyAttribute.hpp>
46 #include <com/sun/star/form/FormComponentType.hpp>
47 #include <com/sun/star/form/XFormComponent.hpp>
48 #include <com/sun/star/form/XLoadable.hpp>
49 #include <com/sun/star/lang/DisposedException.hpp>
50 #include <com/sun/star/sdbc/ResultSetType.hpp>
51 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
52 #include <com/sun/star/util/XURLTransformer.hpp>
53 #include <com/sun/star/view/XSelectionSupplier.hpp>
54 #include <com/sun/star/sdbcx/XRowLocate.hpp>
55 /** === end UNO includes === **/
56 
57 #include <comphelper/container.hxx>
58 #include <comphelper/enumhelper.hxx>
59 #include <comphelper/extract.hxx>
60 #include <comphelper/processfactory.hxx>
61 #include <comphelper/property.hxx>
62 #include <comphelper/sequence.hxx>
63 #include <comphelper/types.hxx>
64 #include <cppuhelper/typeprovider.hxx>
65 #include <toolkit/helper/vclunohelper.hxx>
66 #include <tools/diagnose_ex.h>
67 
68 using namespace ::svxform;
69 using namespace ::com::sun::star::container;
70 using namespace ::com::sun::star::sdb;
71 using namespace ::com::sun::star::sdbc;
72 using namespace ::com::sun::star::uno;
73 using namespace ::com::sun::star::view;
74 using namespace ::com::sun::star::beans;
75 using namespace ::com::sun::star::lang;
76 using namespace ::com::sun::star::form;
77 using namespace ::com::sun::star::util;
78 using namespace ::com::sun::star;
79 
80 using ::com::sun::star::sdbcx::XColumnsSupplier;
81 using ::com::sun::star::frame::XDispatchProviderInterceptor;
82 using ::com::sun::star::frame::XDispatchProvider;
83 using ::com::sun::star::accessibility::XAccessible;
84 using ::com::sun::star::accessibility::XAccessibleContext;
85 using ::com::sun::star::sdb::XRowSetSupplier;
86 using ::com::sun::star::awt::XVclWindowPeer;
87 
88 
89 //------------------------------------------------------------------
90 ::com::sun::star::awt::FontDescriptor ImplCreateFontDescriptor( const Font& rFont )
91 {
92     ::com::sun::star::awt::FontDescriptor aFD;
93     aFD.Name = rFont.GetName();
94     aFD.StyleName = rFont.GetStyleName();
95     aFD.Height = (sal_Int16)rFont.GetSize().Height();
96     aFD.Width = (sal_Int16)rFont.GetSize().Width();
97     aFD.Family = (sal_Int16)rFont.GetFamily();
98     aFD.CharSet = rFont.GetCharSet();
99     aFD.Pitch = (sal_Int16)rFont.GetPitch();
100     aFD.CharacterWidth = VCLUnoHelper::ConvertFontWidth( rFont.GetWidthType() );
101     aFD.Weight= VCLUnoHelper::ConvertFontWeight( rFont.GetWeight() );
102     aFD.Slant = (::com::sun::star::awt::FontSlant)rFont.GetItalic();
103     aFD.Underline = (sal_Int16)rFont.GetUnderline();
104     aFD.Strikeout = (sal_Int16)rFont.GetStrikeout();
105     aFD.Orientation = rFont.GetOrientation();
106     aFD.Kerning = rFont.IsKerning();
107     aFD.WordLineMode = rFont.IsWordLineMode();
108     aFD.Type = 0;   // ??? => Nur an Metric...
109     return aFD;
110 }
111 
112 //------------------------------------------------------------------
113 Font ImplCreateFont( const ::com::sun::star::awt::FontDescriptor& rDescr )
114 {
115     Font aFont;
116     aFont.SetName( rDescr.Name );
117     aFont.SetStyleName( rDescr.StyleName );
118     aFont.SetSize( ::Size( rDescr.Width, rDescr.Height ) );
119     aFont.SetFamily( (FontFamily)rDescr.Family );
120     aFont.SetCharSet( (CharSet)rDescr.CharSet );
121     aFont.SetPitch( (FontPitch)rDescr.Pitch );
122     aFont.SetWidthType( VCLUnoHelper::ConvertFontWidth( rDescr.CharacterWidth ) );
123     aFont.SetWeight( VCLUnoHelper::ConvertFontWeight( rDescr.Weight ) );
124     aFont.SetItalic( (FontItalic)rDescr.Slant );
125     aFont.SetUnderline( (::FontUnderline)rDescr.Underline );
126     aFont.SetStrikeout( (::FontStrikeout)rDescr.Strikeout );
127     aFont.SetOrientation( (sal_Int16)rDescr.Orientation );
128     aFont.SetKerning( rDescr.Kerning );
129     aFont.SetWordLineMode( rDescr.WordLineMode );
130     return aFont;
131 }
132 
133 //==================================================================
134 //= FmXModifyMultiplexer
135 //==================================================================
136 //------------------------------------------------------------------
137 FmXModifyMultiplexer::FmXModifyMultiplexer( ::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex )
138                     :OWeakSubObject( rSource )
139                     ,OInterfaceContainerHelper( _rMutex )
140 {
141 }
142 
143 //------------------------------------------------------------------
144 Any SAL_CALL FmXModifyMultiplexer::queryInterface(const Type& _rType) throw (RuntimeException)
145 {
146     Any aReturn;
147     aReturn = ::cppu::queryInterface(_rType,
148         static_cast< ::com::sun::star::util::XModifyListener*>(this),
149         static_cast< XEventListener*>(this)
150     );
151 
152     if (!aReturn.hasValue())
153         aReturn = OWeakSubObject::queryInterface( _rType );
154 
155     return aReturn;
156 }
157 
158 //------------------------------------------------------------------
159 void FmXModifyMultiplexer::disposing(const EventObject& ) throw( RuntimeException )
160 {
161 }
162 
163 //------------------------------------------------------------------
164 void FmXModifyMultiplexer::modified(const EventObject& e) throw( RuntimeException )
165 {
166     EventObject aMulti( e);
167     aMulti.Source = &m_rParent;
168     notifyEach( &XModifyListener::modified, aMulti );
169 }
170 
171 //==================================================================
172 //= FmXUpdateMultiplexer
173 //==================================================================
174 //------------------------------------------------------------------
175 FmXUpdateMultiplexer::FmXUpdateMultiplexer( ::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex )
176                     :OWeakSubObject( rSource )
177                     ,OInterfaceContainerHelper( _rMutex )
178 {
179 }
180 
181 //------------------------------------------------------------------
182 Any SAL_CALL FmXUpdateMultiplexer::queryInterface(const Type& _rType) throw (RuntimeException)
183 {
184     Any aReturn;
185     aReturn = ::cppu::queryInterface(_rType,
186         static_cast< XUpdateListener*>(this),
187         static_cast< XEventListener*>(this)
188     );
189 
190     if (!aReturn.hasValue())
191         aReturn = OWeakSubObject::queryInterface( _rType );
192 
193     return aReturn;
194 }
195 
196 //------------------------------------------------------------------
197 void FmXUpdateMultiplexer::disposing(const EventObject& ) throw( RuntimeException )
198 {
199 }
200 
201 //------------------------------------------------------------------
202 sal_Bool FmXUpdateMultiplexer::approveUpdate(const EventObject &e) throw( RuntimeException )
203 {
204     EventObject aMulti( e );
205     aMulti.Source = &m_rParent;
206 
207     sal_Bool bResult = sal_True;
208     if (getLength())
209     {
210         ::cppu::OInterfaceIteratorHelper aIter(*this);
211         while ( bResult && aIter.hasMoreElements() )
212             bResult = static_cast< XUpdateListener* >( aIter.next() )->approveUpdate( aMulti );
213     }
214 
215     return bResult;
216 }
217 
218 //------------------------------------------------------------------
219 void FmXUpdateMultiplexer::updated(const EventObject &e) throw( RuntimeException )
220 {
221     EventObject aMulti( e );
222     aMulti.Source = &m_rParent;
223     notifyEach( &XUpdateListener::updated, aMulti );
224 }
225 
226 
227 //==================================================================
228 //= FmXSelectionMultiplexer
229 //==================================================================
230 //------------------------------------------------------------------
231 FmXSelectionMultiplexer::FmXSelectionMultiplexer( ::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex )
232     :OWeakSubObject( rSource )
233     ,OInterfaceContainerHelper( _rMutex )
234 {
235 }
236 
237 //------------------------------------------------------------------
238 Any SAL_CALL FmXSelectionMultiplexer::queryInterface(const Type& _rType) throw (RuntimeException)
239 {
240     Any aReturn;
241     aReturn = ::cppu::queryInterface(_rType,
242         static_cast< XSelectionChangeListener*>(this),
243         static_cast< XEventListener*>(this)
244     );
245 
246     if (!aReturn.hasValue())
247         aReturn = OWeakSubObject::queryInterface( _rType );
248 
249     return aReturn;
250 }
251 
252 //------------------------------------------------------------------
253 void FmXSelectionMultiplexer::disposing(const EventObject& ) throw( RuntimeException )
254 {
255 }
256 
257 //------------------------------------------------------------------
258 void SAL_CALL FmXSelectionMultiplexer::selectionChanged( const EventObject& _rEvent ) throw (RuntimeException)
259 {
260     EventObject aMulti(_rEvent);
261     aMulti.Source = &m_rParent;
262     notifyEach( &XSelectionChangeListener::selectionChanged, aMulti );
263 }
264 
265 //==================================================================
266 //= FmXContainerMultiplexer
267 //==================================================================
268 //------------------------------------------------------------------
269 FmXContainerMultiplexer::FmXContainerMultiplexer( ::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex )
270                         :OWeakSubObject( rSource )
271                         ,OInterfaceContainerHelper( _rMutex )
272 {
273 }
274 
275 //------------------------------------------------------------------
276 Any SAL_CALL FmXContainerMultiplexer::queryInterface(const Type& _rType) throw (RuntimeException)
277 {
278     Any aReturn;
279     aReturn = ::cppu::queryInterface(_rType,
280         static_cast< XContainerListener*>(this),
281         static_cast< XEventListener*>(this)
282     );
283 
284     if (!aReturn.hasValue())
285         aReturn = OWeakSubObject::queryInterface( _rType );
286 
287     return aReturn;
288 }
289 
290 //------------------------------------------------------------------
291 void FmXContainerMultiplexer::disposing(const EventObject& ) throw( RuntimeException )
292 {
293 }
294 //------------------------------------------------------------------
295 void FmXContainerMultiplexer::elementInserted(const ContainerEvent& e) throw( RuntimeException )
296 {
297     ContainerEvent aMulti( e );
298     aMulti.Source = &m_rParent;
299     notifyEach( &XContainerListener::elementInserted, aMulti );
300 }
301 
302 //------------------------------------------------------------------
303 void FmXContainerMultiplexer::elementRemoved(const ContainerEvent& e) throw( RuntimeException )
304 {
305     ContainerEvent aMulti( e );
306     aMulti.Source = &m_rParent;
307     notifyEach( &XContainerListener::elementRemoved, aMulti );
308 }
309 
310 
311 //------------------------------------------------------------------
312 void FmXContainerMultiplexer::elementReplaced(const ContainerEvent& e) throw( RuntimeException )
313 {
314     ContainerEvent aMulti( e );
315     aMulti.Source = &m_rParent;
316     notifyEach( &XContainerListener::elementReplaced, aMulti );
317 }
318 
319 //==================================================================
320 //= FmXGridControlMultiplexer
321 //==================================================================
322 //------------------------------------------------------------------
323 FmXGridControlMultiplexer::FmXGridControlMultiplexer( ::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex )
324     :OWeakSubObject( rSource )
325     ,OInterfaceContainerHelper( _rMutex )
326 {
327 }
328 
329 //------------------------------------------------------------------
330 Any SAL_CALL FmXGridControlMultiplexer::queryInterface(const Type& _rType) throw (RuntimeException)
331 {
332     Any aReturn;
333     aReturn = ::cppu::queryInterface( _rType,
334         static_cast< XGridControlListener*>(this)
335     );
336 
337     if (!aReturn.hasValue())
338         aReturn = OWeakSubObject::queryInterface( _rType );
339 
340     return aReturn;
341 }
342 
343 //------------------------------------------------------------------
344 void FmXGridControlMultiplexer::disposing( const EventObject& ) throw( RuntimeException )
345 {
346 }
347 
348 //------------------------------------------------------------------
349 void SAL_CALL FmXGridControlMultiplexer::columnChanged( const EventObject& _event ) throw (RuntimeException)
350 {
351     EventObject aForwardedEvent( _event );
352     aForwardedEvent.Source = &m_rParent;
353     notifyEach( &XGridControlListener::columnChanged, aForwardedEvent );
354 }
355 
356 //==================================================================
357 //= FmXGridControl
358 //==================================================================
359 
360 //------------------------------------------------------------------
361 Reference< XInterface > SAL_CALL FmXGridControl_NewInstance_Impl(const Reference< XMultiServiceFactory>& _rxFactory)
362 {
363     return *(new FmXGridControl(_rxFactory));
364 }
365 DBG_NAME(FmXGridControl )
366 //------------------------------------------------------------------------------
367 FmXGridControl::FmXGridControl(const Reference< XMultiServiceFactory >& _rxFactory)
368                :UnoControl( _rxFactory)
369                ,m_aModifyListeners(*this, GetMutex())
370                ,m_aUpdateListeners(*this, GetMutex())
371                ,m_aContainerListeners(*this, GetMutex())
372                ,m_aSelectionListeners(*this, GetMutex())
373                ,m_aGridControlListeners(*this, GetMutex())
374                ,m_nPeerCreationLevel(0)
375                ,m_bInDraw(sal_False)
376                ,m_xServiceFactory(_rxFactory)
377 {
378     DBG_CTOR(FmXGridControl ,NULL);
379 }
380 
381 //------------------------------------------------------------------------------
382 FmXGridControl::~FmXGridControl()
383 {
384     DBG_DTOR(FmXGridControl ,NULL);
385 }
386 
387 //------------------------------------------------------------------
388 Any SAL_CALL FmXGridControl::queryAggregation(const Type& _rType) throw (RuntimeException)
389 {
390     Any aReturn = FmXGridControl_BASE::queryInterface(_rType);
391 
392     if (!aReturn.hasValue())
393         aReturn = UnoControl::queryAggregation( _rType );
394     return aReturn;
395 }
396 
397 //------------------------------------------------------------------
398 Sequence< Type> SAL_CALL FmXGridControl::getTypes(  ) throw(RuntimeException)
399 {
400     return comphelper::concatSequences(UnoControl::getTypes(),FmXGridControl_BASE::getTypes());
401 }
402 
403 //------------------------------------------------------------------
404 Sequence<sal_Int8> SAL_CALL FmXGridControl::getImplementationId(  ) throw(RuntimeException)
405 {
406     static ::cppu::OImplementationId* pId = 0;
407     if (! pId)
408     {
409         ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
410         if (! pId)
411         {
412             static ::cppu::OImplementationId aId;
413             pId = &aId;
414         }
415     }
416     return pId->getImplementationId();
417 }
418 
419 // XServiceInfo
420 //------------------------------------------------------------------------------
421 sal_Bool SAL_CALL FmXGridControl::supportsService(const ::rtl::OUString& ServiceName) throw()
422 {
423     ::comphelper::StringSequence aSupported = getSupportedServiceNames();
424     const ::rtl::OUString * pArray = aSupported.getConstArray();
425     for( sal_Int32 i = 0; i < aSupported.getLength(); i++ )
426         if( pArray[i] == ServiceName )
427             return sal_True;
428     return sal_False;
429 }
430 
431 //------------------------------------------------------------------------------
432 ::rtl::OUString SAL_CALL FmXGridControl::getImplementationName() throw()
433 {
434     return ::rtl::OUString::createFromAscii("com.sun.star.form.FmXGridControl");
435 }
436 
437 //------------------------------------------------------------------------------
438 ::comphelper::StringSequence SAL_CALL FmXGridControl::getSupportedServiceNames() throw()
439 {
440     Sequence< ::rtl::OUString > aServiceNames(2);
441     aServiceNames[0] = FM_SUN_CONTROL_GRIDCONTROL;
442     aServiceNames[1] = ::rtl::OUString::createFromAscii("com.sun.star.awt.UnoControl");
443     return aServiceNames;
444 }
445 
446 //------------------------------------------------------------------------------
447 void SAL_CALL FmXGridControl::dispose() throw( RuntimeException )
448 {
449     ::vos::OGuard aGuard( Application::GetSolarMutex() );
450 
451     EventObject aEvt;
452     aEvt.Source = static_cast< ::cppu::OWeakObject* >(this);
453     m_aModifyListeners.disposeAndClear(aEvt);
454     m_aUpdateListeners.disposeAndClear(aEvt);
455     m_aContainerListeners.disposeAndClear(aEvt);
456 
457     UnoControl::dispose();
458 }
459 
460 //------------------------------------------------------------------------------
461 ::rtl::OUString FmXGridControl::GetComponentServiceName()
462 {
463     ::rtl::OUString aName = ::rtl::OUString::createFromAscii("DBGrid");
464     return aName;
465 }
466 
467 //------------------------------------------------------------------------------
468 sal_Bool SAL_CALL FmXGridControl::setModel(const Reference< ::com::sun::star::awt::XControlModel >& rModel) throw( RuntimeException )
469 {
470     ::vos::OGuard aGuard( Application::GetSolarMutex() );
471 
472     if (!UnoControl::setModel(rModel))
473         return sal_False;
474 
475     Reference< XGridPeer > xGridPeer(getPeer(), UNO_QUERY);
476     if (xGridPeer.is())
477     {
478         Reference< XIndexContainer > xCols(mxModel, UNO_QUERY);
479         xGridPeer->setColumns(xCols);
480     }
481     return sal_True;
482 }
483 
484 //------------------------------------------------------------------------------
485 FmXGridPeer* FmXGridControl::imp_CreatePeer(Window* pParent)
486 {
487     FmXGridPeer* pReturn = new FmXGridPeer(m_xServiceFactory);
488 
489     // translate properties into WinBits
490     WinBits nStyle = WB_TABSTOP;
491     Reference< XPropertySet >  xModelSet(getModel(), UNO_QUERY);
492     if (xModelSet.is())
493     {
494         try
495         {
496             if (::comphelper::getINT16(xModelSet->getPropertyValue(FM_PROP_BORDER)))
497                 nStyle |= WB_BORDER;
498         }
499         catch(const Exception&)
500         {
501             OSL_ASSERT(!"Can not get style");
502         }
503     }
504 
505     pReturn->Create(pParent, nStyle);
506     return pReturn;
507 }
508 
509 //------------------------------------------------------------------------------
510 void SAL_CALL FmXGridControl::createPeer(const Reference< ::com::sun::star::awt::XToolkit >& /*rToolkit*/, const Reference< ::com::sun::star::awt::XWindowPeer >& rParentPeer) throw( RuntimeException )
511 {
512     if ( !mxModel.is() )
513         throw DisposedException( ::rtl::OUString(), *this );
514 
515     DBG_ASSERT(/*(0 == m_nPeerCreationLevel) && */!mbCreatingPeer, "FmXGridControl::createPeer : recursion!");
516         // I think this should never assert, now that we're using the base class' mbCreatingPeer in addition to
517         // our own m_nPeerCreationLevel
518         // But I'm not sure as I don't _fully_ understand the underlying toolkit implementations ....
519         // (if this asserts, we still need m_nPeerCreationLevel. If not, we could omit it ....)
520         // 14.05.2001 - 86836 - frank.schoenheit@germany.sun.com
521 
522     // TODO: why the hell this whole class does not use any mutex?
523 
524     if (!getPeer().is())
525     {
526         mbCreatingPeer = sal_True;
527             // mbCreatingPeer is virtually the same as m_nPeerCreationLevel, but it's the base class' method
528             // to prevent recursion.
529 
530         Window* pParentWin = NULL;
531         if (rParentPeer.is())
532         {
533             VCLXWindow* pParent = VCLXWindow::GetImplementation(rParentPeer);
534             if (pParent)
535                 pParentWin = pParent->GetWindow();
536         }
537 
538         FmXGridPeer* pPeer = imp_CreatePeer(pParentWin);
539         DBG_ASSERT(pPeer != NULL, "FmXGridControl::createPeer : imp_CreatePeer didn't return a peer !");
540         setPeer( pPeer );
541 
542         // lesen der properties aus dem model
543 //      ++m_nPeerCreationLevel;
544         updateFromModel();
545 
546         // folgendes unschoene Szenario : updateFromModel fuehrt zu einem propertiesChanged am Control,
547         // das stellt fest, dass sich eine 'kritische' Property geaendert hat (zum Beispiel "Border") und
548         // legt daraufhin eine neue Peer an, was wieder hier im createPeer landet, wir legen also eine
549         // zweite FmXGridPeer an und initialisieren die. Dann kommen wir in der ersten Inkarnation aus
550         // dem updsateFromModel raus und arbeiten dort weiter mit dem pPeer, das jetzt eigentlich schon
551         // veraltet ist (da ja in der zweiten Inkarnation eine andere Peer angelegt wurde).
552         // Deswegen also der Aufwand mit dem PeerCreationLevel, das stellt sicher, dass wir die in dem
553         // tiefsten Level angelegte Peer wirklich verwenden, sie aber erst im top-level
554         // initialisieren.
555 //      if (--m_nPeerCreationLevel == 0)
556         {
557             DBG_ASSERT(getPeer().is(), "FmXGridControl::createPeer : something went wrong ... no top level peer !");
558             pPeer = FmXGridPeer::getImplementation(getPeer());
559 
560             setPosSize( maComponentInfos.nX, maComponentInfos.nY, maComponentInfos.nWidth, maComponentInfos.nHeight, ::com::sun::star::awt::PosSize::POSSIZE );
561 
562             Reference< XIndexContainer >  xColumns(getModel(), UNO_QUERY);
563             if (xColumns.is())
564                 pPeer->setColumns(xColumns);
565 
566             if (maComponentInfos.bVisible)
567                 pPeer->setVisible(sal_True);
568 
569             if (!maComponentInfos.bEnable)
570                 pPeer->setEnable(sal_False);
571 
572             if (maWindowListeners.getLength())
573                 pPeer->addWindowListener( &maWindowListeners );
574 
575             if (maFocusListeners.getLength())
576                 pPeer->addFocusListener( &maFocusListeners );
577 
578             if (maKeyListeners.getLength())
579                 pPeer->addKeyListener( &maKeyListeners );
580 
581             if (maMouseListeners.getLength())
582                 pPeer->addMouseListener( &maMouseListeners );
583 
584             if (maMouseMotionListeners.getLength())
585                 pPeer->addMouseMotionListener( &maMouseMotionListeners );
586 
587             if (maPaintListeners.getLength())
588                 pPeer->addPaintListener( &maPaintListeners );
589 
590             if (m_aModifyListeners.getLength())
591                 pPeer->addModifyListener( &m_aModifyListeners );
592 
593             if (m_aUpdateListeners.getLength())
594                 pPeer->addUpdateListener( &m_aUpdateListeners );
595 
596             if (m_aContainerListeners.getLength())
597                 pPeer->addContainerListener( &m_aContainerListeners );
598 
599             // forward the design mode
600             sal_Bool bForceAlivePeer = m_bInDraw && !maComponentInfos.bVisible;
601                 // (we force a alive-mode peer if we're in "draw", cause in this case the peer will be used for drawing in
602                 // foreign devices. We ensure this with the visibility check as an living peer is assumed to be noncritical
603                 // only if invisible)
604             Any aOldCursorBookmark;
605             if (!mbDesignMode || bForceAlivePeer)
606             {
607                 Reference< XFormComponent >  xComp(getModel(), UNO_QUERY);
608                 if (xComp.is())
609                 {
610                     Reference< XRowSet >  xForm(xComp->getParent(), UNO_QUERY);
611                     // is the form alive?
612                     // we can see that if the form contains columns
613                     Reference< ::com::sun::star::sdbcx::XColumnsSupplier >  xColumnsSupplier(xForm, UNO_QUERY);
614                     if (xColumnsSupplier.is())
615                     {
616                         if (Reference< XIndexAccess > (xColumnsSupplier->getColumns(),UNO_QUERY)->getCount())
617                         {
618                             // we get only a new bookmark if the resultset is not forwardonly
619                             if (::comphelper::getINT32(Reference< XPropertySet > (xForm, UNO_QUERY)->getPropertyValue(FM_PROP_RESULTSET_TYPE)) != ResultSetType::FORWARD_ONLY)
620                             {
621                                 // as the FmGridControl touches the data source it is connected to we have to remember the current
622                                 // cursor position (and restore afterwards)
623                                 // OJ: but only when we stand on a valid row
624                                 Reference< XResultSet > xResultSet(xForm, UNO_QUERY);
625                                 if ( !xResultSet->isBeforeFirst() && !xResultSet->isAfterLast() )
626                                 {
627                                     try
628                                     {
629                                         aOldCursorBookmark = Reference< ::com::sun::star::sdbcx::XRowLocate > (xForm, UNO_QUERY)->getBookmark();
630                                     }
631                                     catch( const Exception& e )
632                                     {
633                                         DBG_UNHANDLED_EXCEPTION();
634                                         (void)e;
635                                     }
636                                 }
637                             }
638                         }
639                     }
640                     pPeer->setRowSet(xForm);
641                 }
642             }
643             pPeer->setDesignMode(mbDesignMode && !bForceAlivePeer);
644 
645             try
646             {
647                 if (aOldCursorBookmark.hasValue())
648                 {   // we have a valid bookmark, so we have to restore the cursor's position
649                     Reference< XFormComponent >  xComp(getModel(), UNO_QUERY);
650                     Reference< ::com::sun::star::sdbcx::XRowLocate >  xLocate(xComp->getParent(), UNO_QUERY);
651                     xLocate->moveToBookmark(aOldCursorBookmark);
652                 }
653             }
654             catch( const Exception& e )
655             {
656                 DBG_UNHANDLED_EXCEPTION();
657                 (void)e;
658             }
659 
660             Reference< ::com::sun::star::awt::XView >  xPeerView(getPeer(), UNO_QUERY);
661             xPeerView->setZoom( maComponentInfos.nZoomX, maComponentInfos.nZoomY );
662             xPeerView->setGraphics( mxGraphics );
663         }
664         mbCreatingPeer = sal_False;
665     }
666 }
667 
668 //------------------------------------------------------------------------------
669 void FmXGridControl::addModifyListener(const Reference< ::com::sun::star::util::XModifyListener >& l) throw( RuntimeException )
670 {
671     m_aModifyListeners.addInterface( l );
672     if( getPeer().is() && m_aModifyListeners.getLength() == 1 )
673     {
674         Reference< ::com::sun::star::util::XModifyBroadcaster >  xGrid(getPeer(), UNO_QUERY);
675         xGrid->addModifyListener( &m_aModifyListeners);
676     }
677 }
678 
679 //------------------------------------------------------------------------------
680 sal_Bool SAL_CALL FmXGridControl::select( const Any& _rSelection ) throw (IllegalArgumentException, RuntimeException)
681 {
682     ::vos::OGuard aGuard( Application::GetSolarMutex() );
683     Reference< XSelectionSupplier > xPeer(getPeer(), UNO_QUERY);
684     return xPeer->select(_rSelection);
685 }
686 
687 //------------------------------------------------------------------------------
688 Any SAL_CALL FmXGridControl::getSelection(  ) throw (RuntimeException)
689 {
690     ::vos::OGuard aGuard( Application::GetSolarMutex() );
691     Reference< XSelectionSupplier > xPeer(getPeer(), UNO_QUERY);
692     return xPeer->getSelection();
693 }
694 
695 //------------------------------------------------------------------------------
696 void SAL_CALL FmXGridControl::addSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener ) throw (RuntimeException)
697 {
698     m_aSelectionListeners.addInterface( _rxListener );
699     if( getPeer().is() && 1 == m_aSelectionListeners.getLength() )
700     {
701         Reference< XSelectionSupplier > xGrid(getPeer(), UNO_QUERY);
702         xGrid->addSelectionChangeListener( &m_aSelectionListeners);
703     }
704 }
705 
706 //------------------------------------------------------------------------------
707 void SAL_CALL FmXGridControl::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener ) throw (RuntimeException)
708 {
709     if( getPeer().is() && 1 == m_aSelectionListeners.getLength() )
710     {
711         Reference< XSelectionSupplier > xGrid(getPeer(), UNO_QUERY);
712         xGrid->removeSelectionChangeListener( &m_aSelectionListeners);
713     }
714     m_aSelectionListeners.removeInterface( _rxListener );
715 }
716 
717 //------------------------------------------------------------------------------
718 Sequence< sal_Bool > SAL_CALL FmXGridControl::queryFieldDataType( const Type& xType ) throw(RuntimeException)
719 {
720     if (getPeer().is())
721     {
722         Reference< XGridFieldDataSupplier >  xPeerSupplier(getPeer(), UNO_QUERY);
723         if (xPeerSupplier.is())
724             return xPeerSupplier->queryFieldDataType(xType);
725     }
726 
727     return Sequence<sal_Bool>();
728 }
729 
730 //------------------------------------------------------------------------------
731 Sequence< Any > SAL_CALL FmXGridControl::queryFieldData( sal_Int32 nRow, const Type& xType ) throw(RuntimeException)
732 {
733     if (getPeer().is())
734     {
735         Reference< XGridFieldDataSupplier >  xPeerSupplier(getPeer(), UNO_QUERY);
736         if (xPeerSupplier.is())
737             return xPeerSupplier->queryFieldData(nRow, xType);
738     }
739 
740     return Sequence< Any>();
741 }
742 
743 //------------------------------------------------------------------------------
744 void SAL_CALL FmXGridControl::removeModifyListener(const Reference< ::com::sun::star::util::XModifyListener >& l) throw( RuntimeException )
745 {
746     if( getPeer().is() && m_aModifyListeners.getLength() == 1 )
747     {
748         Reference< ::com::sun::star::util::XModifyBroadcaster >  xGrid(getPeer(), UNO_QUERY);
749         xGrid->removeModifyListener( &m_aModifyListeners);
750     }
751     m_aModifyListeners.removeInterface( l );
752 }
753 
754 //------------------------------------------------------------------------------
755 void SAL_CALL FmXGridControl::draw( sal_Int32 x, sal_Int32 y ) throw( RuntimeException )
756 {
757     ::vos::OGuard aGuard( Application::GetSolarMutex() );
758     m_bInDraw = sal_True;
759     UnoControl::draw(x, y);
760     m_bInDraw = sal_False;
761 }
762 
763 //------------------------------------------------------------------------------
764 void SAL_CALL FmXGridControl::setDesignMode(sal_Bool bOn) throw( RuntimeException )
765 {
766     ::com::sun::star::util::ModeChangeEvent aModeChangeEvent;
767 
768     // --- <mutex_lock> ---
769     {
770         ::vos::OGuard aGuard( Application::GetSolarMutex() );
771 
772         Reference< XRowSetSupplier >  xGrid(getPeer(), UNO_QUERY);
773 
774         if (xGrid.is() && (bOn != mbDesignMode || (!bOn && !xGrid->getRowSet().is())))
775         {
776             if (bOn)
777             {
778                 xGrid->setRowSet(Reference< XRowSet > ());
779             }
780             else
781             {
782                 Reference< XFormComponent >  xComp(getModel(), UNO_QUERY);
783                 if (xComp.is())
784                 {
785                     Reference< XRowSet >  xForm(xComp->getParent(), UNO_QUERY);
786                     xGrid->setRowSet(xForm);
787                 }
788             }
789 
790             mbDesignMode = bOn;
791 
792             Reference< XVclWindowPeer >  xVclWindowPeer( getPeer(), UNO_QUERY );
793             if (xVclWindowPeer.is())
794                 xVclWindowPeer->setDesignMode(bOn);
795         }
796         mbDesignMode = bOn;
797 
798         // dispose our current AccessibleContext, if we have one
799         // (changing the design mode implies having a new implementation for this context,
800         // so the old one must be declared DEFUNC)
801         disposeAccessibleContext();
802 
803         // prepare firing an event
804         aModeChangeEvent.Source = *this;
805         aModeChangeEvent.NewMode = ::rtl::OUString::createFromAscii( mbDesignMode ? "design" : "alive" );
806     }
807 
808     // --- </mutex_lock> ---
809     maModeChangeListeners.notifyEach( &XModeChangeListener::modeChanged, aModeChangeEvent );
810 }
811 
812 // XBoundComponent
813 //------------------------------------------------------------------------------
814 void SAL_CALL FmXGridControl::addUpdateListener(const Reference< XUpdateListener >& l) throw( RuntimeException )
815 {
816     m_aUpdateListeners.addInterface( l );
817     if( getPeer().is() && m_aUpdateListeners.getLength() == 1 )
818     {
819         Reference< XBoundComponent >  xBound(getPeer(), UNO_QUERY);
820         xBound->addUpdateListener( &m_aUpdateListeners);
821     }
822 }
823 
824 //------------------------------------------------------------------------------
825 void SAL_CALL FmXGridControl::removeUpdateListener(const Reference< XUpdateListener >& l) throw( RuntimeException )
826 {
827     if( getPeer().is() && m_aUpdateListeners.getLength() == 1 )
828     {
829         Reference< XBoundComponent >  xBound(getPeer(), UNO_QUERY);
830         xBound->removeUpdateListener( &m_aUpdateListeners);
831     }
832     m_aUpdateListeners.removeInterface( l );
833 }
834 
835 //------------------------------------------------------------------------------
836 sal_Bool SAL_CALL FmXGridControl::commit() throw( RuntimeException )
837 {
838     Reference< XBoundComponent >  xBound(getPeer(), UNO_QUERY);
839     if (xBound.is())
840         return xBound->commit();
841     else
842         return sal_True;
843 }
844 
845 // XContainer
846 //------------------------------------------------------------------------------
847 void SAL_CALL FmXGridControl::addContainerListener(const Reference< XContainerListener >& l) throw( RuntimeException )
848 {
849     m_aContainerListeners.addInterface( l );
850     if( getPeer().is() && m_aContainerListeners.getLength() == 1 )
851     {
852         Reference< XContainer >  xContainer(getPeer(), UNO_QUERY);
853         xContainer->addContainerListener( &m_aContainerListeners);
854     }
855 }
856 
857 //------------------------------------------------------------------------------
858 void SAL_CALL FmXGridControl::removeContainerListener(const Reference< XContainerListener >& l) throw( RuntimeException )
859 {
860     if( getPeer().is() && m_aContainerListeners.getLength() == 1 )
861     {
862         Reference< XContainer >  xContainer(getPeer(), UNO_QUERY);
863         xContainer->removeContainerListener( &m_aContainerListeners);
864     }
865     m_aContainerListeners.removeInterface( l );
866 }
867 
868 //------------------------------------------------------------------------------
869 Reference< ::com::sun::star::frame::XDispatch >  SAL_CALL FmXGridControl::queryDispatch(const ::com::sun::star::util::URL& aURL, const ::rtl::OUString& aTargetFrameName, sal_Int32 nSearchFlags) throw( RuntimeException )
870 {
871     Reference< ::com::sun::star::frame::XDispatchProvider >  xPeerProvider(getPeer(), UNO_QUERY);
872     if (xPeerProvider.is())
873         return xPeerProvider->queryDispatch(aURL, aTargetFrameName, nSearchFlags);
874     else
875         return Reference< ::com::sun::star::frame::XDispatch > ();
876 }
877 
878 //------------------------------------------------------------------------------
879 Sequence< Reference< ::com::sun::star::frame::XDispatch > > SAL_CALL FmXGridControl::queryDispatches(const Sequence< ::com::sun::star::frame::DispatchDescriptor>& aDescripts) throw( RuntimeException )
880 {
881     Reference< ::com::sun::star::frame::XDispatchProvider >  xPeerProvider(getPeer(), UNO_QUERY);
882     if (xPeerProvider.is())
883         return xPeerProvider->queryDispatches(aDescripts);
884     else
885         return Sequence< Reference< ::com::sun::star::frame::XDispatch > >();
886 }
887 
888 //------------------------------------------------------------------------------
889 void SAL_CALL FmXGridControl::registerDispatchProviderInterceptor(const Reference< ::com::sun::star::frame::XDispatchProviderInterceptor >& _xInterceptor) throw( RuntimeException )
890 {
891     Reference< ::com::sun::star::frame::XDispatchProviderInterception >  xPeerInterception(getPeer(), UNO_QUERY);
892     if (xPeerInterception.is())
893         xPeerInterception->registerDispatchProviderInterceptor(_xInterceptor);
894 }
895 
896 //------------------------------------------------------------------------------
897 void SAL_CALL FmXGridControl::releaseDispatchProviderInterceptor(const Reference< ::com::sun::star::frame::XDispatchProviderInterceptor >& _xInterceptor) throw( RuntimeException )
898 {
899     Reference< ::com::sun::star::frame::XDispatchProviderInterception >  xPeerInterception(getPeer(), UNO_QUERY);
900     if (xPeerInterception.is())
901         xPeerInterception->releaseDispatchProviderInterceptor(_xInterceptor);
902 }
903 
904 //------------------------------------------------------------------------------
905 void SAL_CALL FmXGridControl::addGridControlListener( const Reference< XGridControlListener >& _listener ) throw( RuntimeException )
906 {
907     ::osl::MutexGuard aGuard( GetMutex() );
908 
909     m_aGridControlListeners.addInterface( _listener );
910     if ( getPeer().is() && 1 == m_aGridControlListeners.getLength() )
911     {
912         Reference< XGridControl > xPeerGrid( getPeer(), UNO_QUERY );
913         if ( xPeerGrid.is() )
914             xPeerGrid->addGridControlListener( &m_aGridControlListeners );
915     }
916 }
917 
918 //------------------------------------------------------------------------------
919 void SAL_CALL FmXGridControl::removeGridControlListener( const Reference< XGridControlListener >& _listener ) throw( RuntimeException )
920 {
921     ::osl::MutexGuard aGuard( GetMutex() );
922 
923     if( getPeer().is() && 1 == m_aGridControlListeners.getLength() )
924     {
925         Reference< XGridControl > xPeerGrid( getPeer(), UNO_QUERY );
926         if ( xPeerGrid.is() )
927             xPeerGrid->removeGridControlListener( &m_aGridControlListeners );
928     }
929 
930     m_aGridControlListeners.removeInterface( _listener );
931 }
932 
933 //------------------------------------------------------------------------------
934 sal_Int16 SAL_CALL FmXGridControl::getCurrentColumnPosition() throw( RuntimeException )
935 {
936     Reference< XGridControl > xGrid( getPeer(), UNO_QUERY );
937     return xGrid.is() ? xGrid->getCurrentColumnPosition() : -1;
938 }
939 
940 //------------------------------------------------------------------------------
941 void SAL_CALL FmXGridControl::setCurrentColumnPosition(sal_Int16 nPos) throw( RuntimeException )
942 {
943     Reference< XGridControl > xGrid( getPeer(), UNO_QUERY );
944     if ( xGrid.is() )
945     {
946         ::vos::OGuard aGuard( Application::GetSolarMutex() );
947         xGrid->setCurrentColumnPosition( nPos );
948     }
949 }
950 
951 // XElementAccess
952 //------------------------------------------------------------------------------
953 sal_Bool SAL_CALL FmXGridControl::hasElements() throw( RuntimeException )
954 {
955     Reference< XElementAccess >  xPeer(getPeer(), UNO_QUERY);
956     return xPeer.is() ? xPeer->hasElements() : 0;
957 }
958 
959 //------------------------------------------------------------------------------
960 Type SAL_CALL FmXGridControl::getElementType(  ) throw(RuntimeException)
961 {
962     return ::getCppuType((const Reference< ::com::sun::star::awt::XTextComponent >*)NULL);
963 }
964 
965 // XEnumerationAccess
966 //------------------------------------------------------------------------------
967 Reference< XEnumeration >  SAL_CALL FmXGridControl::createEnumeration() throw( RuntimeException )
968 {
969     Reference< XEnumerationAccess >  xPeer(getPeer(), UNO_QUERY);
970     if (xPeer.is())
971         return xPeer->createEnumeration();
972     else
973         return new ::comphelper::OEnumerationByIndex(this);
974 }
975 
976 // XIndexAccess
977 //------------------------------------------------------------------------------
978 sal_Int32 SAL_CALL FmXGridControl::getCount() throw( RuntimeException )
979 {
980     Reference< XIndexAccess >  xPeer(getPeer(), UNO_QUERY);
981     return xPeer.is() ? xPeer->getCount() : 0;
982 }
983 
984 //------------------------------------------------------------------------------
985 Any SAL_CALL FmXGridControl::getByIndex(sal_Int32 _nIndex) throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException )
986 {
987     Reference< XIndexAccess >  xPeer(getPeer(), UNO_QUERY);
988     if (!xPeer.is())
989         throw IndexOutOfBoundsException();
990 
991     return xPeer->getByIndex(_nIndex);
992 }
993 
994 // ::com::sun::star::util::XModeSelector
995 //------------------------------------------------------------------------------
996 void SAL_CALL FmXGridControl::setMode(const ::rtl::OUString& Mode) throw( NoSupportException, RuntimeException )
997 {
998     Reference< ::com::sun::star::util::XModeSelector >  xPeer(getPeer(), UNO_QUERY);
999     if (!xPeer.is())
1000         throw NoSupportException();
1001 
1002     xPeer->setMode(Mode);
1003 }
1004 
1005 //------------------------------------------------------------------------------
1006 ::rtl::OUString SAL_CALL FmXGridControl::getMode() throw( RuntimeException )
1007 {
1008     Reference< ::com::sun::star::util::XModeSelector >  xPeer(getPeer(), UNO_QUERY);
1009     return xPeer.is() ? xPeer->getMode() : ::rtl::OUString();
1010 }
1011 
1012 //------------------------------------------------------------------------------
1013 ::comphelper::StringSequence SAL_CALL FmXGridControl::getSupportedModes() throw( RuntimeException )
1014 {
1015     Reference< ::com::sun::star::util::XModeSelector >  xPeer(getPeer(), UNO_QUERY);
1016     return xPeer.is() ? xPeer->getSupportedModes() : ::comphelper::StringSequence();
1017 }
1018 
1019 //------------------------------------------------------------------------------
1020 sal_Bool SAL_CALL FmXGridControl::supportsMode(const ::rtl::OUString& Mode) throw( RuntimeException )
1021 {
1022     Reference< ::com::sun::star::util::XModeSelector >  xPeer(getPeer(), UNO_QUERY);
1023     return xPeer.is() ? xPeer->supportsMode(Mode) : sal_False;
1024 }
1025 
1026 //==============================================================================
1027 //= FmXGridPeer
1028 //==============================================================================
1029 // helper class which prevents that in the peer's header the FmGridListener must be known
1030 class FmXGridPeer::GridListenerDelegator : public FmGridListener
1031 {
1032 protected:
1033     FmXGridPeer*        m_pPeer;
1034 
1035 public:
1036     GridListenerDelegator( FmXGridPeer* _pPeer );
1037 
1038 protected:
1039     virtual void selectionChanged();
1040     virtual void columnChanged();
1041 };
1042 
1043 //------------------------------------------------------------------
1044 FmXGridPeer::GridListenerDelegator::GridListenerDelegator(FmXGridPeer* _pPeer)
1045     :m_pPeer(_pPeer)
1046 {
1047     DBG_ASSERT(m_pPeer, "GridListenerDelegator::GridListenerDelegator");
1048 }
1049 
1050 //------------------------------------------------------------------
1051 void FmXGridPeer::GridListenerDelegator::selectionChanged()
1052 {
1053     m_pPeer->selectionChanged();
1054 }
1055 
1056 //------------------------------------------------------------------
1057 void FmXGridPeer::GridListenerDelegator::columnChanged()
1058 {
1059     m_pPeer->columnChanged();
1060 }
1061 
1062 //==============================================================================
1063 //------------------------------------------------------------------
1064 Reference< XInterface >  FmXGridPeer_CreateInstance(const Reference< XMultiServiceFactory>& _rxFactory)
1065 {
1066     FmXGridPeer* pNewObject = new FmXGridPeer(_rxFactory);
1067     pNewObject->Create(NULL, WB_TABSTOP);
1068     return *pNewObject;
1069 }
1070 
1071 //------------------------------------------------------------------
1072 Sequence< Type> SAL_CALL FmXGridPeer::getTypes(  ) throw(RuntimeException)
1073 {
1074     return comphelper::concatSequences( VCLXWindow::getTypes(), FmXGridPeer_BASE::getTypes() );
1075 }
1076 
1077 //------------------------------------------------------------------
1078 Sequence<sal_Int8> SAL_CALL FmXGridPeer::getImplementationId(  ) throw(RuntimeException)
1079 {
1080     static ::cppu::OImplementationId* pId = 0;
1081     if (! pId)
1082     {
1083         ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
1084         if (! pId)
1085         {
1086             static ::cppu::OImplementationId aId;
1087             pId = &aId;
1088         }
1089     }
1090     return pId->getImplementationId();
1091 }
1092 
1093 //------------------------------------------------------------------
1094 Any SAL_CALL FmXGridPeer::queryInterface(const Type& _rType) throw (RuntimeException)
1095 {
1096     Any aReturn = FmXGridPeer_BASE::queryInterface(_rType);
1097 
1098     if (!aReturn.hasValue())
1099         aReturn = VCLXWindow::queryInterface( _rType );
1100 
1101     return aReturn;
1102 }
1103 
1104 //------------------------------------------------------------------
1105 void FmXGridPeer::selectionChanged()
1106 {
1107     EventObject aSource;
1108     aSource.Source = static_cast< ::cppu::OWeakObject* >(this);
1109     m_aSelectionListeners.notifyEach( &XSelectionChangeListener::selectionChanged, aSource);
1110 }
1111 
1112 //------------------------------------------------------------------
1113 void FmXGridPeer::columnChanged()
1114 {
1115     EventObject aEvent( *this );
1116     m_aGridControlListeners.notifyEach( &XGridControlListener::columnChanged, aEvent );
1117 }
1118 
1119 //------------------------------------------------------------------
1120 namespace fmgridif
1121 {
1122     const ::rtl::OUString getDataModeIdentifier()
1123     {
1124         static ::rtl::OUString s_sDataModeIdentifier = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DataMode" ) );
1125         return s_sDataModeIdentifier;
1126     }
1127 }
1128 using namespace fmgridif;
1129 
1130 //------------------------------------------------------------------
1131 FmXGridPeer::FmXGridPeer(const Reference< XMultiServiceFactory >& _rxFactory)
1132             :m_aModifyListeners(m_aMutex)
1133             ,m_aUpdateListeners(m_aMutex)
1134             ,m_aContainerListeners(m_aMutex)
1135             ,m_aSelectionListeners(m_aMutex)
1136             ,m_aGridControlListeners(m_aMutex)
1137             ,m_aMode( getDataModeIdentifier() )
1138             ,m_nCursorListening(0)
1139             ,m_bInterceptingDispatch(sal_False)
1140             ,m_pStateCache(NULL)
1141             ,m_pDispatchers(NULL)
1142             ,m_pGridListener(NULL)
1143             ,m_xServiceFactory(_rxFactory)
1144 {
1145     // nach diesem Constructor muss Create gerufen werden !
1146     m_pGridListener = new GridListenerDelegator( this );
1147 }
1148 
1149 //------------------------------------------------------------------------------
1150 FmGridControl* FmXGridPeer::imp_CreateControl(Window* pParent, WinBits nStyle)
1151 {
1152     return new FmGridControl(m_xServiceFactory, pParent, this, nStyle);
1153 }
1154 
1155 //------------------------------------------------------------------------------
1156 void FmXGridPeer::Create(Window* pParent, WinBits nStyle)
1157 {
1158     FmGridControl* pWin = imp_CreateControl(pParent, nStyle);
1159     DBG_ASSERT(pWin != NULL, "FmXGridPeer::Create : imp_CreateControl didn't return a control !");
1160 
1161     pWin->SetStateProvider(LINK(this, FmXGridPeer, OnQueryGridSlotState));
1162     pWin->SetSlotExecutor(LINK(this, FmXGridPeer, OnExecuteGridSlot));
1163 
1164     // want to hear about row selections
1165     pWin->setGridListener( m_pGridListener );
1166 
1167     // Init mu� immer aufgerufen werden
1168     pWin->Init();
1169     pWin->SetComponentInterface(this);
1170 
1171     getSupportedURLs();
1172 }
1173 
1174 //------------------------------------------------------------------------------
1175 FmXGridPeer::~FmXGridPeer()
1176 {
1177     setRowSet(Reference< XRowSet > ());
1178     setColumns(Reference< XIndexContainer > ());
1179 
1180     delete m_pGridListener;
1181 }
1182 
1183 //------------------------------------------------------------------------------
1184 const Sequence< sal_Int8 >& FmXGridPeer::getUnoTunnelImplementationId() throw()
1185 {
1186     static Sequence< sal_Int8 > * pSeq = 0;
1187     if( !pSeq )
1188     {
1189         ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
1190         if( !pSeq )
1191         {
1192             static Sequence< sal_Int8 > aSeq( 16 );
1193             rtl_createUuid( (sal_uInt8*)aSeq.getArray(), 0, sal_True );
1194             pSeq = &aSeq;
1195         }
1196     }
1197     return *pSeq;
1198 }
1199 
1200 //------------------------------------------------------------------------------
1201 FmXGridPeer* FmXGridPeer::getImplementation( const Reference< XInterface >& _rxIFace ) throw()
1202 {
1203     FmXGridPeer* pReturn = NULL;
1204     Reference< XUnoTunnel >  xTunnel(_rxIFace, UNO_QUERY);
1205     if (xTunnel.is())
1206         pReturn = reinterpret_cast<FmXGridPeer*>(xTunnel->getSomething(getUnoTunnelImplementationId()));
1207 
1208     return pReturn;
1209 }
1210 
1211 //------------------------------------------------------------------------------
1212 sal_Int64 SAL_CALL FmXGridPeer::getSomething( const Sequence< sal_Int8 >& _rIdentifier ) throw(RuntimeException)
1213 {
1214     sal_Int64 nReturn(0);
1215 
1216     if  (   (_rIdentifier.getLength() == 16)
1217         &&  (0 == rtl_compareMemory( getUnoTunnelImplementationId().getConstArray(), _rIdentifier.getConstArray(), 16 ))
1218         )
1219     {
1220         nReturn = reinterpret_cast<sal_Int64>(this);
1221     }
1222     else
1223         nReturn = VCLXWindow::getSomething(_rIdentifier);
1224 
1225     return nReturn;
1226 }
1227 
1228 // XEventListener
1229 //------------------------------------------------------------------------------
1230 void FmXGridPeer::disposing(const EventObject& e) throw( RuntimeException )
1231 {
1232 using namespace ::com::sun::star::util;
1233     bool bKnownSender = false;
1234 
1235     Reference< XIndexContainer >  xCols( e.Source, UNO_QUERY );
1236     if ( xCols.is() )
1237     {
1238         setColumns(Reference< XIndexContainer > ());
1239         bKnownSender = true;
1240     }
1241 
1242     Reference< XRowSet >  xCursor(e.Source, UNO_QUERY);
1243     if (xCursor.is())
1244     {
1245         setRowSet( m_xCursor );
1246         m_xCursor = NULL;
1247         bKnownSender = true;
1248     }
1249 
1250 
1251     if ( !bKnownSender && m_pDispatchers )
1252     {
1253         const Sequence< URL>& aSupportedURLs = getSupportedURLs();
1254         const URL* pSupportedURLs = aSupportedURLs.getConstArray();
1255         for ( sal_uInt16 i=0; i < ( aSupportedURLs.getLength() ) && !bKnownSender; ++i, ++pSupportedURLs )
1256         {
1257             if ( m_pDispatchers[i] == e.Source )
1258             {
1259                 m_pDispatchers[i]->removeStatusListener( static_cast< ::com::sun::star::frame::XStatusListener* >( this ), *pSupportedURLs );
1260                 m_pDispatchers[i] = NULL;
1261                 m_pStateCache[i] = 0;
1262                 bKnownSender = true;
1263             }
1264         }
1265     }
1266 
1267     if ( !bKnownSender )
1268         VCLXWindow::disposing(e);
1269 }
1270 
1271 //------------------------------------------------------------------------------
1272 void FmXGridPeer::addModifyListener(const Reference< ::com::sun::star::util::XModifyListener >& l) throw( RuntimeException )
1273 {
1274     m_aModifyListeners.addInterface( l );
1275 }
1276 
1277 //------------------------------------------------------------------------------
1278 void FmXGridPeer::removeModifyListener(const Reference< ::com::sun::star::util::XModifyListener >& l) throw( RuntimeException )
1279 {
1280     m_aModifyListeners.removeInterface( l );
1281 }
1282 
1283 //------------------------------------------------------------------------------
1284 #define LAST_KNOWN_TYPE     FormComponentType::PATTERNFIELD
1285 Sequence< sal_Bool > SAL_CALL FmXGridPeer::queryFieldDataType( const Type& xType ) throw(RuntimeException)
1286 {
1287     // eine 'Konvertierungstabelle'
1288     static sal_Bool bCanConvert[LAST_KNOWN_TYPE][4] =
1289     {
1290         { sal_False, sal_False, sal_False, sal_False }, //  FormComponentType::CONTROL
1291         { sal_False, sal_False, sal_False, sal_False }, //  FormComponentType::COMMANDBUTTON
1292         { sal_False, sal_False, sal_False, sal_False }, //  FormComponentType::RADIOBUTTON
1293         { sal_False, sal_False, sal_False, sal_False }, //  FormComponentType::IMAGEBUTTON
1294         { sal_False, sal_False, sal_False, sal_True  }, //  FormComponentType::CHECKBOX
1295         { sal_False, sal_False, sal_False, sal_False }, //  FormComponentType::LISTBOX
1296         { sal_False, sal_False, sal_False, sal_False }, //  FormComponentType::COMBOBOX
1297         { sal_False, sal_False, sal_False, sal_False }, //  FormComponentType::GROUPBOX
1298         { sal_True , sal_False, sal_False, sal_False }, //  FormComponentType::TEXTFIELD
1299         { sal_False, sal_False, sal_False, sal_False }, //  FormComponentType::FIXEDTEXT
1300         { sal_False, sal_False, sal_False, sal_False }, //  FormComponentType::GRIDCONTROL
1301         { sal_False, sal_False, sal_False, sal_False }, //  FormComponentType::FILECONTROL
1302         { sal_False, sal_False, sal_False, sal_False }, //  FormComponentType::HIDDENCONTROL
1303         { sal_False, sal_False, sal_False, sal_False }, //  FormComponentType::IMAGECONTROL
1304         { sal_True , sal_True , sal_True , sal_False }, //  FormComponentType::DATEFIELD
1305         { sal_True , sal_True , sal_False, sal_False }, //  FormComponentType::TIMEFIELD
1306         { sal_True , sal_True , sal_False, sal_False }, //  FormComponentType::NUMERICFIELD
1307         { sal_True , sal_True , sal_False, sal_False }, //  FormComponentType::CURRENCYFIELD
1308         { sal_True , sal_False, sal_False, sal_False }  //  FormComponentType::PATTERNFIELD
1309     };
1310 
1311 
1312     sal_Int16 nMapColumn = -1;
1313     switch (xType.getTypeClass())
1314     {
1315         case TypeClass_STRING           : nMapColumn = 0; break;
1316         case TypeClass_FLOAT:
1317         case TypeClass_DOUBLE           : nMapColumn = 1; break;
1318         case TypeClass_SHORT:
1319         case TypeClass_LONG:
1320         case TypeClass_UNSIGNED_LONG:
1321         case TypeClass_UNSIGNED_SHORT   : nMapColumn = 2; break;
1322         case TypeClass_BOOLEAN          : nMapColumn = 3; break;
1323         default:
1324             break;
1325     }
1326 
1327     Reference< XIndexContainer >  xColumns = getColumns();
1328 
1329     FmGridControl* pGrid = (FmGridControl*) GetWindow();
1330     sal_Int32 nColumns = pGrid->GetViewColCount();
1331 
1332     DbGridColumns aColumns = pGrid->GetColumns();
1333 
1334     Sequence<sal_Bool> aReturnSequence(nColumns);
1335     sal_Bool* pReturnArray = aReturnSequence.getArray();
1336 
1337     sal_Bool bRequestedAsAny = (xType.getTypeClass() == TypeClass_ANY);
1338 
1339     DbGridColumn* pCol;
1340     Reference< ::com::sun::star::sdb::XColumn >  xFieldContent;
1341     Reference< XPropertySet >  xCurrentColumn;
1342     for (sal_Int32 i=0; i<nColumns; ++i)
1343     {
1344         if (bRequestedAsAny)
1345         {
1346             pReturnArray[i] = sal_True;
1347             continue;
1348         }
1349 
1350         pReturnArray[i] = sal_False;
1351 
1352         sal_uInt16 nModelPos = pGrid->GetModelColumnPos(pGrid->GetColumnIdFromViewPos((sal_uInt16)i));
1353         DBG_ASSERT(nModelPos != (sal_uInt16)-1, "FmXGridPeer::queryFieldDataType : no model pos !");
1354 
1355         pCol = aColumns.GetObject(nModelPos);
1356         const DbGridRowRef xRow = pGrid->GetSeekRow();
1357         xFieldContent = (xRow.Is() && xRow->HasField(pCol->GetFieldPos())) ? xRow->GetField(pCol->GetFieldPos()).getColumn() : Reference< ::com::sun::star::sdb::XColumn > ();
1358         if (!xFieldContent.is())
1359             // can't supply anything without a field content
1360             // FS - 07.12.99 - 54391
1361             continue;
1362 
1363         xColumns->getByIndex(nModelPos) >>= xCurrentColumn;
1364         if (!::comphelper::hasProperty(FM_PROP_CLASSID, xCurrentColumn))
1365             continue;
1366 
1367         sal_Int16 nClassId = sal_Int16();
1368         xCurrentColumn->getPropertyValue(FM_PROP_CLASSID) >>= nClassId;
1369         if (nClassId>LAST_KNOWN_TYPE)
1370             continue;
1371         DBG_ASSERT(nClassId>0, "FmXGridPeer::queryFieldDataType : somebody changed the definition of the FormComponentType enum !");
1372 
1373         if (nMapColumn != -1)
1374             pReturnArray[i] = bCanConvert[nClassId-1][nMapColumn];
1375     }
1376 
1377     return aReturnSequence;
1378 }
1379 
1380 //------------------------------------------------------------------------------
1381 Sequence< Any > SAL_CALL FmXGridPeer::queryFieldData( sal_Int32 nRow, const Type& xType ) throw(RuntimeException)
1382 {
1383     FmGridControl* pGrid = (FmGridControl*) GetWindow();
1384     DBG_ASSERT(pGrid && pGrid->IsOpen(), "FmXGridPeer::queryFieldData : have no valid grid window !");
1385     if (!pGrid || !pGrid->IsOpen())
1386         return Sequence< Any>();
1387 
1388     // das Control zur angegebenen Row fahren
1389     if (!pGrid->SeekRow(nRow))
1390     {
1391         throw IllegalArgumentException();
1392     }
1393 
1394     // don't use GetCurrentRow as this isn't affected by the above SeekRow
1395     // FS - 30.09.99 - 68644
1396     DbGridRowRef xPaintRow = pGrid->GetPaintRow();
1397     ENSURE_OR_THROW( xPaintRow.Is(), "invalid paint row" );
1398 
1399     // die Columns des Controls brauche ich fuer GetFieldText
1400     DbGridColumns aColumns = pGrid->GetColumns();
1401 
1402     // und durch alle Spalten durch
1403     sal_Int32 nColumnCount = pGrid->GetViewColCount();
1404 
1405     Sequence< Any> aReturnSequence(nColumnCount);
1406     Any* pReturnArray = aReturnSequence.getArray();
1407 
1408     sal_Bool bRequestedAsAny = (xType.getTypeClass() == TypeClass_ANY);
1409     Reference< ::com::sun::star::sdb::XColumn >  xFieldContent;
1410     DbGridColumn* pCol;
1411     for (sal_Int32 i=0; i < nColumnCount; ++i)
1412     {
1413         sal_uInt16 nModelPos = pGrid->GetModelColumnPos(pGrid->GetColumnIdFromViewPos((sal_uInt16)i));
1414         DBG_ASSERT(nModelPos != (sal_uInt16)-1, "FmXGridPeer::queryFieldData : invalid model pos !");
1415 
1416         // don't use GetCurrentFieldValue to determine the field content as this isn't affected by the above SeekRow
1417         // FS - 30.09.99 - 68644
1418         pCol = aColumns.GetObject(nModelPos);
1419         xFieldContent = xPaintRow->HasField( pCol->GetFieldPos() )
1420                     ?   xPaintRow->GetField( pCol->GetFieldPos() ).getColumn()
1421                     :   Reference< XColumn > ();
1422 
1423         if ( !xFieldContent.is() )
1424             continue;
1425 
1426         if (bRequestedAsAny)
1427         {
1428             Reference< XPropertySet >  xFieldSet(xFieldContent, UNO_QUERY);
1429             pReturnArray[i] = xFieldSet->getPropertyValue(FM_PROP_VALUE);
1430         }
1431         else
1432         {
1433             switch (xType.getTypeClass())
1434             {
1435                 // Strings werden direkt ueber das GetFieldText abgehandelt
1436                 case TypeClass_STRING           :
1437                 {
1438                     String sText = aColumns.GetObject(nModelPos)->GetCellText( xPaintRow, pGrid->getNumberFormatter() );
1439                     pReturnArray[i] <<= ::rtl::OUString(sText);
1440                 }
1441                 break;
1442                 // alles andere wird an der DatabaseVariant erfragt
1443                 case TypeClass_FLOAT            : pReturnArray[i] <<= xFieldContent->getFloat(); break;
1444                 case TypeClass_DOUBLE           : pReturnArray[i] <<= xFieldContent->getDouble(); break;
1445                 case TypeClass_SHORT            : pReturnArray[i] <<= (sal_Int16)xFieldContent->getShort(); break;
1446                 case TypeClass_LONG             : pReturnArray[i] <<= (sal_Int32)xFieldContent->getLong(); break;
1447                 case TypeClass_UNSIGNED_SHORT   : pReturnArray[i] <<= (sal_uInt16)xFieldContent->getShort(); break;
1448                 case TypeClass_UNSIGNED_LONG    : pReturnArray[i] <<= (sal_uInt32)xFieldContent->getLong(); break;
1449                 case TypeClass_BOOLEAN          : ::comphelper::setBOOL(pReturnArray[i],xFieldContent->getBoolean()); break;
1450                 default:
1451                 {
1452                     throw IllegalArgumentException();
1453                 }
1454             }
1455         }
1456     }
1457     return aReturnSequence;
1458 }
1459 
1460 //------------------------------------------------------------------------------
1461 void FmXGridPeer::CellModified()
1462 {
1463     EventObject aEvt;
1464     aEvt.Source = static_cast< ::cppu::OWeakObject* >(this);
1465     m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvt );
1466 }
1467 
1468 // XPropertyChangeListener
1469 //------------------------------------------------------------------------------
1470 void FmXGridPeer::propertyChange(const PropertyChangeEvent& evt) throw( RuntimeException )
1471 {
1472     ::vos::OGuard aGuard( Application::GetSolarMutex() );
1473         // want to do a lot of VCL stuff here ...
1474         // this should not be (deadlock) critical, as by definition, every component should release
1475         // any own mutexes before notifying
1476 
1477     FmGridControl* pGrid = (FmGridControl*) GetWindow();
1478     if (!pGrid)
1479         return;
1480 
1481     // DatenbankEvent
1482     Reference< XRowSet >  xCursor(evt.Source, UNO_QUERY);
1483     if (evt.PropertyName == FM_PROP_VALUE || m_xCursor == evt.Source)
1484         pGrid->propertyChange(evt);
1485     else if (pGrid && m_xColumns.is() && m_xColumns->hasElements())
1486     {
1487         // zunaechst raussuchen welche Column sich geaendert hat
1488         ::comphelper::InterfaceRef xCurrent;
1489         sal_Int32 i;
1490 
1491         for ( i = 0; i < m_xColumns->getCount(); i++)
1492         {
1493             ::cppu::extractInterface(xCurrent, m_xColumns->getByIndex(i));
1494             if (evt.Source == xCurrent)
1495                 break;
1496         }
1497 
1498         if (i >= m_xColumns->getCount())
1499             // this is valid because we are listening at the cursor, too (RecordCount, -status, edit mode)
1500             return;
1501 
1502         sal_uInt16 nId = pGrid->GetColumnIdFromModelPos((sal_uInt16)i);
1503         sal_Bool bInvalidateColumn = sal_False;
1504 
1505         if (evt.PropertyName == FM_PROP_LABEL)
1506         {
1507             String aName = ::comphelper::getString(evt.NewValue);
1508             if (aName != pGrid->GetColumnTitle(nId))
1509                 pGrid->SetColumnTitle(nId, aName);
1510         }
1511         else if (evt.PropertyName == FM_PROP_WIDTH)
1512         {
1513             sal_Int32 nWidth = 0;
1514             if (evt.NewValue.getValueType().getTypeClass() == TypeClass_VOID)
1515                 nWidth = pGrid->GetDefaultColumnWidth(pGrid->GetColumnTitle(nId));
1516                 // GetDefaultColumnWidth already considerd the zoom factor
1517             else
1518             {
1519                 sal_Int32 nTest = 0;
1520                 if (evt.NewValue >>= nTest)
1521                 {
1522                     nWidth = pGrid->LogicToPixel(Point(nTest,0),MAP_10TH_MM).X();
1523                     // take the zoom factor into account
1524                     nWidth = pGrid->CalcZoom(nWidth);
1525                 }
1526             }
1527             if (nWidth != (sal_Int32(pGrid->GetColumnWidth(nId))))
1528             {
1529                 if (pGrid->IsEditing())
1530                 {
1531                     pGrid->DeactivateCell();
1532                     pGrid->ActivateCell();
1533                 }
1534                 pGrid->SetColumnWidth(nId, nWidth);
1535             }
1536         }
1537         else if (evt.PropertyName == FM_PROP_HIDDEN)
1538         {
1539             DBG_ASSERT(evt.NewValue.getValueType().getTypeClass() == TypeClass_BOOLEAN,
1540                 "FmXGridPeer::propertyChange : the property 'hidden' should be of type boolean !");
1541             if (::comphelper::getBOOL(evt.NewValue))
1542                 pGrid->HideColumn(nId);
1543             else
1544                 pGrid->ShowColumn(nId);
1545         }
1546         else if (evt.PropertyName == FM_PROP_ALIGN)
1547         {
1548             // it design mode it doesn't matter
1549             if (!isDesignMode())
1550             {
1551                 DbGridColumn* pCol = pGrid->GetColumns().GetObject(i);
1552 
1553                 pCol->SetAlignmentFromModel(-1);
1554                 bInvalidateColumn = sal_True;
1555             }
1556         }
1557         else if (evt.PropertyName == FM_PROP_FORMATKEY)
1558         {
1559             if (!isDesignMode())
1560                 bInvalidateColumn = sal_True;
1561         }
1562 
1563         // need to invalidate the affected column ?
1564         if (bInvalidateColumn)
1565         {
1566             sal_Bool bWasEditing = pGrid->IsEditing();
1567             if (bWasEditing)
1568                 pGrid->DeactivateCell();
1569 
1570             ::Rectangle aColRect = pGrid->GetFieldRect(nId);
1571             aColRect.Top() = 0;
1572             aColRect.Bottom() = pGrid->GetSizePixel().Height();
1573             pGrid->Invalidate(aColRect);
1574 
1575             if (bWasEditing)
1576                 pGrid->ActivateCell();
1577         }
1578     }
1579 }
1580 
1581 // XBoundComponent
1582 //------------------------------------------------------------------------------
1583 void FmXGridPeer::addUpdateListener(const Reference< XUpdateListener >& l) throw( RuntimeException )
1584 {
1585     m_aUpdateListeners.addInterface(l);
1586 }
1587 
1588 //------------------------------------------------------------------------------
1589 void FmXGridPeer::removeUpdateListener(const Reference< XUpdateListener >& l) throw( RuntimeException )
1590 {
1591     m_aUpdateListeners.removeInterface(l);
1592 }
1593 
1594 //------------------------------------------------------------------------------
1595 sal_Bool FmXGridPeer::commit() throw( RuntimeException )
1596 {
1597     FmGridControl* pGrid = (FmGridControl*) GetWindow();
1598     if (!m_xCursor.is() || !pGrid)
1599         return sal_True;
1600 
1601     EventObject aEvt(static_cast< ::cppu::OWeakObject* >(this));
1602     ::cppu::OInterfaceIteratorHelper aIter(m_aUpdateListeners);
1603     sal_Bool bCancel = sal_False;
1604     while (aIter.hasMoreElements() && !bCancel)
1605         if ( !static_cast< XUpdateListener* >( aIter.next() )->approveUpdate( aEvt ) )
1606             bCancel = sal_True;
1607 
1608     if (!bCancel)
1609         bCancel = !pGrid->commit();
1610 
1611     if (!bCancel)
1612         m_aUpdateListeners.notifyEach( &XUpdateListener::updated, aEvt );
1613     return !bCancel;
1614 }
1615 
1616 
1617 //------------------------------------------------------------------------------
1618 void FmXGridPeer::cursorMoved(const EventObject& _rEvent) throw( RuntimeException )
1619 {
1620     FmGridControl* pGrid = (FmGridControl*) GetWindow();
1621     // we are not interested in move to insert row only in the resetted event
1622     // which is fired after positioning an the insert row
1623     if (pGrid && pGrid->IsOpen() && !::comphelper::getBOOL(Reference< XPropertySet > (_rEvent.Source, UNO_QUERY)->getPropertyValue(FM_PROP_ISNEW)))
1624         pGrid->positioned(_rEvent);
1625 }
1626 
1627 //------------------------------------------------------------------------------
1628 void FmXGridPeer::rowChanged(const EventObject& _rEvent) throw( RuntimeException )
1629 {
1630     FmGridControl* pGrid = (FmGridControl*) GetWindow();
1631     if (pGrid && pGrid->IsOpen())
1632     {
1633         if (m_xCursor->rowUpdated() && !pGrid->IsCurrentAppending())
1634             pGrid->RowModified(pGrid->GetCurrentPos());
1635         else if (m_xCursor->rowInserted())
1636             pGrid->inserted(_rEvent);
1637     }
1638 }
1639 
1640 //------------------------------------------------------------------------------
1641 void FmXGridPeer::rowSetChanged(const EventObject& /*event*/) throw( RuntimeException )
1642 {
1643     // not interested in ...
1644     // (our parent is a form which means we get a loaded or reloaded after this rowSetChanged)
1645 }
1646 
1647 // XLoadListener
1648 //------------------------------------------------------------------------------
1649 void FmXGridPeer::loaded(const EventObject& /*rEvent*/) throw( RuntimeException )
1650 {
1651     updateGrid(m_xCursor);
1652 }
1653 
1654 //------------------------------------------------------------------------------
1655 void FmXGridPeer::unloaded(const EventObject& /*rEvent*/) throw( RuntimeException )
1656 {
1657     updateGrid( Reference< XRowSet > (NULL) );
1658 }
1659 
1660 //------------------------------------------------------------------------------
1661 void FmXGridPeer::reloading(const EventObject& /*aEvent*/) throw( RuntimeException )
1662 {
1663     // empty the grid
1664     updateGrid( Reference< XRowSet > (NULL) );
1665 }
1666 
1667 //------------------------------------------------------------------------------
1668 void FmXGridPeer::unloading(const EventObject& /*aEvent*/) throw( RuntimeException )
1669 {
1670     // empty the grid
1671     updateGrid( Reference< XRowSet > (NULL) );
1672 }
1673 
1674 //------------------------------------------------------------------------------
1675 void FmXGridPeer::reloaded(const EventObject& /*aEvent*/) throw( RuntimeException )
1676 {
1677     updateGrid(m_xCursor);
1678 }
1679 
1680 // XGridPeer
1681 //------------------------------------------------------------------------------
1682 Reference< XIndexContainer >  FmXGridPeer::getColumns() throw( RuntimeException )
1683 {
1684     return m_xColumns;
1685 }
1686 
1687 //------------------------------------------------------------------------------
1688 void FmXGridPeer::addColumnListeners(const Reference< XPropertySet >& xCol)
1689 {
1690     static const ::rtl::OUString aPropsListenedTo[] =
1691     {
1692         FM_PROP_LABEL, FM_PROP_WIDTH, FM_PROP_HIDDEN, FM_PROP_ALIGN, FM_PROP_FORMATKEY
1693     };
1694 
1695     // as not all properties have to be supported by all columns we have to check this
1696     // before adding a listener
1697     Reference< XPropertySetInfo > xInfo = xCol->getPropertySetInfo();
1698     Property aPropDesc;
1699     const ::rtl::OUString* pProps = aPropsListenedTo;
1700     const ::rtl::OUString* pPropsEnd = pProps + sizeof( aPropsListenedTo ) / sizeof( aPropsListenedTo[ 0 ] );
1701     for (; pProps != pPropsEnd; ++pProps)
1702     {
1703         if ( xInfo->hasPropertyByName( *pProps ) )
1704         {
1705             aPropDesc = xInfo->getPropertyByName( *pProps );
1706             if ( 0 != ( aPropDesc.Attributes & PropertyAttribute::BOUND ) )
1707                 xCol->addPropertyChangeListener( *pProps, this );
1708         }
1709     }
1710 }
1711 
1712 //------------------------------------------------------------------------------
1713 void FmXGridPeer::removeColumnListeners(const Reference< XPropertySet >& xCol)
1714 {
1715     // the same props as in addColumnListeners ... linux has problems with global static UStrings, so
1716     // we have to do it this way ....
1717     static ::rtl::OUString aPropsListenedTo[] =
1718     {
1719         FM_PROP_LABEL, FM_PROP_WIDTH, FM_PROP_HIDDEN, FM_PROP_ALIGN, FM_PROP_FORMATKEY
1720     };
1721 
1722     Reference< XPropertySetInfo >  xInfo = xCol->getPropertySetInfo();
1723     for (sal_uInt16 i=0; i<sizeof(aPropsListenedTo)/sizeof(aPropsListenedTo[0]); ++i)
1724         if (xInfo->hasPropertyByName(aPropsListenedTo[i]))
1725             xCol->removePropertyChangeListener(aPropsListenedTo[i], this);
1726 }
1727 
1728 //------------------------------------------------------------------------------
1729 void FmXGridPeer::setColumns(const Reference< XIndexContainer >& Columns) throw( RuntimeException )
1730 {
1731     ::vos::OGuard aGuard( Application::GetSolarMutex() );
1732 
1733     FmGridControl* pGrid = static_cast< FmGridControl* >( GetWindow() );
1734 
1735     if (m_xColumns.is())
1736     {
1737         Reference< XPropertySet > xCol;
1738         for (sal_Int32 i = 0; i < m_xColumns->getCount(); i++)
1739         {
1740             ::cppu::extractInterface(xCol, m_xColumns->getByIndex(i));
1741             removeColumnListeners(xCol);
1742         }
1743         Reference< XContainer >  xContainer(m_xColumns, UNO_QUERY);
1744         xContainer->removeContainerListener(this);
1745 
1746         Reference< XSelectionSupplier >  xSelSupplier(m_xColumns, UNO_QUERY);
1747         xSelSupplier->removeSelectionChangeListener(this);
1748 
1749         Reference< XReset >  xColumnReset(m_xColumns, UNO_QUERY);
1750         if (xColumnReset.is())
1751             xColumnReset->removeResetListener((XResetListener*)this);
1752     }
1753     if (Columns.is())
1754     {
1755         Reference< XContainer >  xContainer(Columns, UNO_QUERY);
1756         xContainer->addContainerListener(this);
1757 
1758         Reference< XSelectionSupplier >  xSelSupplier(Columns, UNO_QUERY);
1759         xSelSupplier->addSelectionChangeListener(this);
1760 
1761         Reference< XPropertySet >  xCol;
1762         for (sal_Int32 i = 0; i < Columns->getCount(); i++)
1763         {
1764             ::cppu::extractInterface(xCol, Columns->getByIndex(i));
1765             addColumnListeners(xCol);
1766         }
1767 
1768         Reference< XReset >  xColumnReset(Columns, UNO_QUERY);
1769         if (xColumnReset.is())
1770             xColumnReset->addResetListener((XResetListener*)this);
1771     }
1772     m_xColumns = Columns;
1773     if (pGrid)
1774     {
1775         pGrid->InitColumnsByModels(m_xColumns);
1776 
1777         if (m_xColumns.is())
1778         {
1779             EventObject aEvt(m_xColumns);
1780             selectionChanged(aEvt);
1781         }
1782     }
1783 }
1784 
1785 //------------------------------------------------------------------------------
1786 void FmXGridPeer::setDesignMode(sal_Bool bOn) throw( RuntimeException )
1787 {
1788     if (bOn != isDesignMode())
1789     {
1790         Window* pWin = GetWindow();
1791         if (pWin)
1792             ((FmGridControl*) pWin)->SetDesignMode(bOn);
1793     }
1794 
1795     if (bOn)
1796         DisConnectFromDispatcher();
1797     else
1798         UpdateDispatches(); // will connect if not already connected and just update else
1799 }
1800 
1801 //------------------------------------------------------------------------------
1802 sal_Bool FmXGridPeer::isDesignMode() throw( RuntimeException )
1803 {
1804     Window* pWin = GetWindow();
1805     if (pWin)
1806         return ((FmGridControl*) pWin)->IsDesignMode();
1807     else
1808         return sal_False;
1809 }
1810 
1811 //------------------------------------------------------------------------------
1812 void FmXGridPeer::elementInserted(const ContainerEvent& evt) throw( RuntimeException )
1813 {
1814     ::vos::OGuard aGuard( Application::GetSolarMutex() );
1815 
1816     FmGridControl* pGrid = (FmGridControl*) GetWindow();
1817     // Handle Column beruecksichtigen
1818     if (!pGrid || !m_xColumns.is() || pGrid->IsInColumnMove() || m_xColumns->getCount() == ((sal_Int32)pGrid->GetModelColCount()))
1819         return;
1820 
1821     Reference< XPropertySet >  xSet;
1822     ::cppu::extractInterface(xSet, evt.Element);
1823     addColumnListeners(xSet);
1824 
1825     Reference< XPropertySet >  xNewColumn(xSet);
1826     String aName = ::comphelper::getString(xNewColumn->getPropertyValue(FM_PROP_LABEL));
1827     Any aWidth = xNewColumn->getPropertyValue(FM_PROP_WIDTH);
1828     sal_Int32 nWidth = 0;
1829     if (aWidth >>= nWidth)
1830         nWidth = pGrid->LogicToPixel(Point(nWidth,0),MAP_10TH_MM).X();
1831 
1832     pGrid->AppendColumn(aName, (sal_uInt16)nWidth, (sal_Int16)::comphelper::getINT32(evt.Accessor));
1833 
1834     // jetzt die Spalte setzen
1835     DbGridColumn* pCol = pGrid->GetColumns().GetObject(::comphelper::getINT32(evt.Accessor));
1836     pCol->setModel(xNewColumn);
1837 
1838     Any aHidden = xNewColumn->getPropertyValue(FM_PROP_HIDDEN);
1839     if (::comphelper::getBOOL(aHidden))
1840         pGrid->HideColumn(pCol->GetId());
1841 
1842     FormControlFactory( m_xServiceFactory ).initializeTextFieldLineEnds( xNewColumn );
1843 }
1844 
1845 //------------------------------------------------------------------------------
1846 void FmXGridPeer::elementReplaced(const ContainerEvent& evt) throw( RuntimeException )
1847 {
1848     ::vos::OGuard aGuard( Application::GetSolarMutex() );
1849 
1850     FmGridControl* pGrid = (FmGridControl*) GetWindow();
1851 
1852     // Handle Column beruecksichtigen
1853     if (!pGrid || !m_xColumns.is() || pGrid->IsInColumnMove())
1854         return;
1855 
1856     Reference< XPropertySet >  xNewColumn;
1857     Reference< XPropertySet >  xOldColumn;
1858     ::cppu::extractInterface(xNewColumn, evt.Element);
1859     ::cppu::extractInterface(xOldColumn, evt.ReplacedElement);
1860 
1861     sal_Bool bWasEditing = pGrid->IsEditing();
1862     if (bWasEditing)
1863         pGrid->DeactivateCell();
1864 
1865     pGrid->RemoveColumn(pGrid->GetColumnIdFromModelPos((sal_uInt16)::comphelper::getINT32(evt.Accessor)));
1866 
1867     removeColumnListeners(xOldColumn);
1868     addColumnListeners(xNewColumn);
1869 
1870     String aName = ::comphelper::getString(xNewColumn->getPropertyValue(FM_PROP_LABEL));
1871     Any aWidth = xNewColumn->getPropertyValue(FM_PROP_WIDTH);
1872     sal_Int32 nWidth = 0;
1873     if (aWidth >>= nWidth)
1874         nWidth = pGrid->LogicToPixel(Point(nWidth,0),MAP_10TH_MM).X();
1875     sal_uInt16 nNewId = pGrid->AppendColumn(aName, (sal_uInt16)nWidth, (sal_Int16)::comphelper::getINT32(evt.Accessor));
1876     sal_uInt16 nNewPos = pGrid->GetModelColumnPos(nNewId);
1877 
1878     // set the model of the new column
1879     DbGridColumn* pCol = pGrid->GetColumns().GetObject(nNewPos);
1880 
1881     // for initializong this grid column, we need the fields of the grid's data source
1882     Reference< XColumnsSupplier > xSuppColumns;
1883     CursorWrapper* pGridDataSource = pGrid->getDataSource();
1884     if ( pGridDataSource )
1885         xSuppColumns = xSuppColumns.query( (Reference< XInterface >)( *pGridDataSource ) );
1886     Reference< XNameAccess > xColumnsByName;
1887     if ( xSuppColumns.is() )
1888         xColumnsByName = xSuppColumns->getColumns();
1889     Reference< XIndexAccess > xColumnsByIndex( xColumnsByName, UNO_QUERY );
1890 
1891     if ( xColumnsByIndex.is() )
1892         pGrid->InitColumnByField( pCol, xNewColumn, xColumnsByName, xColumnsByIndex );
1893     else
1894         // the simple version, applies when the grid is not yet connected to a data source
1895         pCol->setModel(xNewColumn);
1896 
1897     if (bWasEditing)
1898         pGrid->ActivateCell();
1899 }
1900 
1901 //------------------------------------------------------------------------------
1902 void FmXGridPeer::elementRemoved(const ContainerEvent& evt) throw( RuntimeException )
1903 {
1904     ::vos::OGuard aGuard( Application::GetSolarMutex() );
1905 
1906     FmGridControl* pGrid    = (FmGridControl*) GetWindow();
1907 
1908     // Handle Column beruecksichtigen
1909     if (!pGrid || !m_xColumns.is() || pGrid->IsInColumnMove() || m_xColumns->getCount() == ((sal_Int32)pGrid->GetModelColCount()))
1910         return;
1911 
1912     pGrid->RemoveColumn(pGrid->GetColumnIdFromModelPos((sal_uInt16)::comphelper::getINT32(evt.Accessor)));
1913 
1914     Reference< XPropertySet >  xOldColumn;
1915     ::cppu::extractInterface(xOldColumn, evt.Element);
1916     removeColumnListeners(xOldColumn);
1917 }
1918 
1919 //------------------------------------------------------------------------------
1920 void FmXGridPeer::setProperty( const ::rtl::OUString& PropertyName, const Any& Value) throw( RuntimeException )
1921 {
1922     ::vos::OGuard aGuard( Application::GetSolarMutex() );
1923 
1924     FmGridControl* pGrid = (FmGridControl*) GetWindow();
1925 
1926     sal_Bool bVoid = !Value.hasValue();
1927 
1928     if ( 0 == PropertyName.compareTo( FM_PROP_TEXTLINECOLOR ) )
1929     {
1930         ::Color aTextLineColor( bVoid ? COL_TRANSPARENT : ::comphelper::getINT32( Value ) );
1931         if (bVoid)
1932         {
1933             pGrid->SetTextLineColor();
1934             pGrid->GetDataWindow().SetTextLineColor();
1935         }
1936         else
1937         {
1938             pGrid->SetTextLineColor(aTextLineColor);
1939             pGrid->GetDataWindow().SetTextLineColor(aTextLineColor);
1940         }
1941 
1942         // need to forward this to the columns
1943         DbGridColumns& rColumns = const_cast<DbGridColumns&>(pGrid->GetColumns());
1944         DbGridColumn* pLoop = rColumns.First();
1945         while (pLoop)
1946         {
1947             FmXGridCell* pXCell = pLoop->GetCell();
1948             if (pXCell)
1949             {
1950                 if (bVoid)
1951                     pXCell->SetTextLineColor();
1952                 else
1953                     pXCell->SetTextLineColor(aTextLineColor);
1954             }
1955 
1956             pLoop = rColumns.Next();
1957         }
1958 
1959         if (isDesignMode())
1960             pGrid->Invalidate();
1961     }
1962     else if ( 0 == PropertyName.compareTo( FM_PROP_FONTEMPHASISMARK ) )
1963     {
1964         Font aGridFont = pGrid->GetControlFont();
1965         sal_Int16 nValue = ::comphelper::getINT16(Value);
1966         aGridFont.SetEmphasisMark( nValue );
1967         pGrid->SetControlFont( aGridFont );
1968     }
1969     else if ( 0 == PropertyName.compareTo( FM_PROP_FONTRELIEF ) )
1970     {
1971         Font aGridFont = pGrid->GetControlFont();
1972         sal_Int16 nValue = ::comphelper::getINT16(Value);
1973         aGridFont.SetRelief( (FontRelief)nValue );
1974         pGrid->SetControlFont( aGridFont );
1975     }
1976     else if ( 0 == PropertyName.compareTo( FM_PROP_HELPURL ) )
1977     {
1978         ::rtl::OUString sHelpURL;
1979         OSL_VERIFY( Value >>= sHelpURL );
1980         INetURLObject aHID( sHelpURL );
1981         if ( aHID.GetProtocol() == INET_PROT_HID )
1982             sHelpURL = aHID.GetURLPath();
1983         pGrid->SetHelpId( rtl::OUStringToOString( sHelpURL, RTL_TEXTENCODING_UTF8 ) );
1984     }
1985     else if ( 0 == PropertyName.compareTo( FM_PROP_DISPLAYSYNCHRON ) )
1986     {
1987         pGrid->setDisplaySynchron(::comphelper::getBOOL(Value));
1988     }
1989     else if ( 0 == PropertyName.compareTo( FM_PROP_CURSORCOLOR ) )
1990     {
1991         if (bVoid)
1992             pGrid->SetCursorColor(COL_TRANSPARENT);
1993         else
1994             pGrid->SetCursorColor( ::Color(::comphelper::getINT32(Value)));
1995         if (isDesignMode())
1996             pGrid->Invalidate();
1997     }
1998     else if ( 0 == PropertyName.compareTo( FM_PROP_ALWAYSSHOWCURSOR ) )
1999     {
2000         pGrid->EnablePermanentCursor(::comphelper::getBOOL(Value));
2001         if (isDesignMode())
2002             pGrid->Invalidate();
2003     }
2004     else if ( 0 == PropertyName.compareTo( FM_PROP_FONT ) )
2005     {
2006         if ( bVoid )
2007             pGrid->SetControlFont( Font() );
2008         else
2009         {
2010             ::com::sun::star::awt::FontDescriptor aFont;
2011             if (Value >>= aFont)
2012             {
2013                 Font aNewVclFont;
2014                 if (::comphelper::operator!=(aFont, ::comphelper::getDefaultFont()))    // ist das der Default
2015                     aNewVclFont = ImplCreateFont( aFont );
2016 
2017                 // need to add relief and emphasis (they're stored in a VCL-Font, but not in a FontDescriptor
2018                 Font aOldVclFont = pGrid->GetControlFont();
2019                 aNewVclFont.SetRelief( aOldVclFont.GetRelief() );
2020                 aNewVclFont.SetEmphasisMark( aOldVclFont.GetEmphasisMark() );
2021 
2022                 // now set it ...
2023                 pGrid->SetControlFont( aNewVclFont );
2024 
2025                 // if our row-height property is void (which means "calculate it font-dependent") we have
2026                 // to adjust the control's row height
2027                 Reference< XPropertySet >  xModelSet(getColumns(), UNO_QUERY);
2028                 if (xModelSet.is() && ::comphelper::hasProperty(FM_PROP_ROWHEIGHT, xModelSet))
2029                 {
2030                     Any aHeight = xModelSet->getPropertyValue(FM_PROP_ROWHEIGHT);
2031                     if (!aHeight.hasValue())
2032                         pGrid->SetDataRowHeight(0);
2033                 }
2034 
2035             }
2036         }
2037     }
2038     else if ( 0 == PropertyName.compareTo( FM_PROP_BACKGROUNDCOLOR ) )
2039     {
2040         if ( bVoid )
2041         {
2042             pGrid->SetControlBackground();
2043         }
2044         else
2045         {
2046             ::Color aColor( ::comphelper::getINT32(Value) );
2047             pGrid->SetBackground( aColor );
2048             pGrid->SetControlBackground( aColor );
2049         }
2050     }
2051     else if ( 0 == PropertyName.compareTo( FM_PROP_TEXTCOLOR ) )
2052     {
2053         if ( bVoid )
2054         {
2055             pGrid->SetControlForeground();
2056         }
2057         else
2058         {
2059             ::Color aColor( ::comphelper::getINT32(Value) );
2060             pGrid->SetTextColor( aColor );
2061             pGrid->SetControlForeground( aColor );
2062         }
2063     }
2064     else if ( 0 == PropertyName.compareTo( FM_PROP_ROWHEIGHT ) )
2065     {
2066         sal_Int32 nLogHeight(0);
2067         if (Value >>= nLogHeight)
2068         {
2069             sal_Int32 nHeight = pGrid->LogicToPixel(Point(0,nLogHeight),MAP_10TH_MM).Y();
2070             // take the zoom factor into account
2071             nHeight = pGrid->CalcZoom(nHeight);
2072             pGrid->SetDataRowHeight(nHeight);
2073         }
2074         else if (bVoid)
2075             pGrid->SetDataRowHeight(0);
2076     }
2077     else if ( 0 == PropertyName.compareTo( FM_PROP_HASNAVIGATION ) )
2078     {
2079         sal_Bool bValue( sal_True );
2080         OSL_VERIFY( Value >>= bValue );
2081         pGrid->EnableNavigationBar( bValue );
2082     }
2083     else if ( 0 == PropertyName.compareTo( FM_PROP_RECORDMARKER ) )
2084     {
2085         sal_Bool bValue( sal_True );
2086         OSL_VERIFY( Value >>= bValue );
2087         pGrid->EnableHandle( bValue );
2088     }
2089     else if ( 0 == PropertyName.compareTo( FM_PROP_ENABLED ) )
2090     {
2091         sal_Bool bValue( sal_True );
2092         OSL_VERIFY( Value >>= bValue );
2093         pGrid->EnableHandle( bValue );
2094 
2095         // Im DesignModus nur das Datenfenster disablen
2096         // Sonst kann das Control nicht mehr konfiguriert werden
2097         if (isDesignMode())
2098             pGrid->GetDataWindow().Enable( bValue );
2099         else
2100             pGrid->Enable( bValue );
2101     }
2102     else
2103         VCLXWindow::setProperty( PropertyName, Value );
2104 }
2105 
2106 //------------------------------------------------------------------------------
2107 Reference< XAccessibleContext > FmXGridPeer::CreateAccessibleContext()
2108 {
2109     Reference< XAccessibleContext > xContext;
2110 
2111     // use the AccessibleContext provided by the VCL window
2112     Window* pGrid = GetWindow();
2113     if ( pGrid )
2114     {
2115         Reference< XAccessible > xAcc( pGrid->GetAccessible( sal_True ) );
2116         if ( xAcc.is() )
2117             xContext = xAcc->getAccessibleContext();
2118         // TODO: this has a slight conceptual problem:
2119         //
2120         // We know that the XAccessible and XAccessibleContext implementation of the browse
2121         // box is the same (the class implements both interfaces), which, speaking strictly,
2122         // is bad here (means when a browse box acts as UnoControl): We (the FmXGridPeer) are
2123         // the XAccessible here, and the browse box should be able to provide us an XAccessibleContext,
2124         // but it should _not_ be the XAccessible itself.
2125         // However, as long as no client implementation uses dirty hacks such as querying an
2126         // XAccessibleContext for XAccessible, this should not be a problem.
2127     }
2128 
2129     if ( !xContext.is() )
2130         xContext = VCLXWindow::CreateAccessibleContext( );
2131 
2132     return xContext;
2133 }
2134 
2135 //------------------------------------------------------------------------------
2136 Any FmXGridPeer::getProperty( const ::rtl::OUString& _rPropertyName ) throw( RuntimeException )
2137 {
2138     Any aProp;
2139     if (GetWindow())
2140     {
2141         FmGridControl* pGrid = (FmGridControl*) GetWindow();
2142         Window* pDataWindow  = &pGrid->GetDataWindow();
2143 
2144         if ( 0 == _rPropertyName.compareTo( FM_PROP_NAME ) )
2145         {
2146             Font aFont = pDataWindow->GetControlFont();
2147             aProp <<= ImplCreateFontDescriptor( aFont );
2148         }
2149         else if ( 0 == _rPropertyName.compareTo( FM_PROP_TEXTCOLOR ) )
2150         {
2151             aProp <<= (sal_Int32)pDataWindow->GetControlForeground().GetColor();
2152         }
2153         else if ( 0 == _rPropertyName.compareTo( FM_PROP_BACKGROUNDCOLOR ) )
2154         {
2155             aProp <<= (sal_Int32)pDataWindow->GetControlBackground().GetColor();
2156         }
2157         else if ( 0 == _rPropertyName.compareTo( FM_PROP_ROWHEIGHT ) )
2158         {
2159             sal_Int32 nPixelHeight = pGrid->GetDataRowHeight();
2160             // take the zoom factor into account
2161             nPixelHeight = pGrid->CalcReverseZoom(nPixelHeight);
2162             aProp <<= (sal_Int32)pGrid->PixelToLogic(Point(0,nPixelHeight),MAP_10TH_MM).Y();
2163         }
2164         else if ( 0 == _rPropertyName.compareTo( FM_PROP_HASNAVIGATION ) )
2165         {
2166             sal_Bool bHasNavBar = pGrid->HasNavigationBar();
2167             aProp <<= (sal_Bool)bHasNavBar;
2168         }
2169         else if ( 0 == _rPropertyName.compareTo( FM_PROP_RECORDMARKER ) )
2170         {
2171             sal_Bool bHasHandle = pGrid->HasHandle();
2172             aProp <<= (sal_Bool)bHasHandle;
2173         }
2174         else if ( 0 == _rPropertyName.compareTo( FM_PROP_ENABLED ) )
2175         {
2176             aProp <<= (sal_Bool)pDataWindow->IsEnabled();
2177         }
2178         else
2179             aProp = VCLXWindow::getProperty( _rPropertyName );
2180     }
2181     return aProp;
2182 }
2183 
2184 //------------------------------------------------------------------------------
2185 void FmXGridPeer::dispose() throw( RuntimeException )
2186 {
2187     EventObject aEvt;
2188     aEvt.Source = static_cast< ::cppu::OWeakObject* >(this);
2189     m_aModifyListeners.disposeAndClear(aEvt);
2190     m_aUpdateListeners.disposeAndClear(aEvt);
2191     m_aContainerListeners.disposeAndClear(aEvt);
2192     VCLXWindow::dispose();
2193 
2194     // release all interceptors
2195     // discovered during #100312# - 2002-10-23 - fs@openoffice.org
2196     Reference< XDispatchProviderInterceptor > xInterceptor( m_xFirstDispatchInterceptor );
2197     m_xFirstDispatchInterceptor.clear();
2198     while ( xInterceptor.is() )
2199     {
2200         // tell the interceptor it has a new (means no) predecessor
2201         xInterceptor->setMasterDispatchProvider( NULL );
2202 
2203         // ask for it's successor
2204         Reference< XDispatchProvider > xSlave = xInterceptor->getSlaveDispatchProvider();
2205         // and give it the new (means no) successoert
2206         xInterceptor->setSlaveDispatchProvider( NULL );
2207 
2208         // start over with the next chain element
2209         xInterceptor = xInterceptor.query( xSlave );
2210     }
2211 
2212     DisConnectFromDispatcher();
2213     setRowSet(Reference< XRowSet > ());
2214 }
2215 
2216 // XContainer
2217 //------------------------------------------------------------------------------
2218 void FmXGridPeer::addContainerListener(const Reference< XContainerListener >& l) throw( RuntimeException )
2219 {
2220     m_aContainerListeners.addInterface( l );
2221 }
2222 //------------------------------------------------------------------------------
2223 void FmXGridPeer::removeContainerListener(const Reference< XContainerListener >& l) throw( RuntimeException )
2224 {
2225     m_aContainerListeners.removeInterface( l );
2226 }
2227 
2228 // ::com::sun::star::data::XDatabaseCursorSupplier
2229 //------------------------------------------------------------------------------
2230 void FmXGridPeer::startCursorListening()
2231 {
2232     if (!m_nCursorListening)
2233     {
2234         Reference< XRowSet >  xRowSet(m_xCursor, UNO_QUERY);
2235         if (xRowSet.is())
2236             xRowSet->addRowSetListener(this);
2237 
2238         Reference< XReset >  xReset(m_xCursor, UNO_QUERY);
2239         if (xReset.is())
2240             xReset->addResetListener(this);
2241 
2242         // alle Listener anmelden
2243         Reference< XPropertySet >  xSet(m_xCursor, UNO_QUERY);
2244         if (xSet.is())
2245         {
2246             xSet->addPropertyChangeListener(FM_PROP_ISMODIFIED, this);
2247             xSet->addPropertyChangeListener(FM_PROP_ROWCOUNT, this);
2248         }
2249     }
2250     m_nCursorListening++;
2251 }
2252 
2253 //------------------------------------------------------------------------------
2254 void FmXGridPeer::stopCursorListening()
2255 {
2256     if (!--m_nCursorListening)
2257     {
2258         Reference< XRowSet >  xRowSet(m_xCursor, UNO_QUERY);
2259         if (xRowSet.is())
2260             xRowSet->removeRowSetListener(this);
2261 
2262         Reference< XReset >  xReset(m_xCursor, UNO_QUERY);
2263         if (xReset.is())
2264             xReset->removeResetListener(this);
2265 
2266         Reference< XPropertySet >  xSet(m_xCursor, UNO_QUERY);
2267         if (xSet.is())
2268         {
2269             xSet->removePropertyChangeListener(FM_PROP_ISMODIFIED, this);
2270             xSet->removePropertyChangeListener(FM_PROP_ROWCOUNT, this);
2271         }
2272     }
2273 }
2274 
2275 //------------------------------------------------------------------------------
2276 void FmXGridPeer::updateGrid(const Reference< XRowSet >& _rxCursor)
2277 {
2278     FmGridControl* pGrid = (FmGridControl*)GetWindow();
2279     if (pGrid)
2280         pGrid->setDataSource(_rxCursor);
2281 }
2282 
2283 //------------------------------------------------------------------------------
2284 Reference< XRowSet >  FmXGridPeer::getRowSet() throw( RuntimeException )
2285 {
2286     return m_xCursor;
2287 }
2288 
2289 //------------------------------------------------------------------------------
2290 void FmXGridPeer::setRowSet(const Reference< XRowSet >& _rDatabaseCursor) throw( RuntimeException )
2291 {
2292     FmGridControl* pGrid = (FmGridControl*) GetWindow();
2293     if (!pGrid || !m_xColumns.is() || !m_xColumns->getCount())
2294         return;
2295     // alle Listener abmelden
2296     if (m_xCursor.is())
2297     {
2298         Reference< XLoadable >  xLoadable(m_xCursor, UNO_QUERY);
2299         // only if the form is loaded we set the rowset
2300         if (xLoadable.is())
2301         {
2302             stopCursorListening();
2303             xLoadable->removeLoadListener(this);
2304         }
2305     }
2306 
2307     m_xCursor = _rDatabaseCursor;
2308 
2309     if (pGrid)
2310     {
2311         Reference< XLoadable >  xLoadable(m_xCursor, UNO_QUERY);
2312         // only if the form is loaded we set the rowset
2313         if (xLoadable.is() && xLoadable->isLoaded())
2314             pGrid->setDataSource(m_xCursor);
2315         else
2316             pGrid->setDataSource(Reference< XRowSet > ());
2317 
2318         if (xLoadable.is())
2319         {
2320             startCursorListening();
2321             xLoadable->addLoadListener(this);
2322         }
2323     }
2324 }
2325 
2326 //------------------------------------------------------------------------------
2327 void SAL_CALL FmXGridPeer::addGridControlListener( const Reference< XGridControlListener >& _listener ) throw( RuntimeException )
2328 {
2329     m_aGridControlListeners.addInterface( _listener );
2330 }
2331 
2332 //------------------------------------------------------------------------------
2333 void SAL_CALL FmXGridPeer::removeGridControlListener( const Reference< XGridControlListener >& _listener ) throw( RuntimeException )
2334 {
2335     m_aGridControlListeners.removeInterface( _listener );
2336 }
2337 
2338 //------------------------------------------------------------------------------
2339 sal_Int16 FmXGridPeer::getCurrentColumnPosition() throw( RuntimeException )
2340 {
2341     FmGridControl* pGrid = (FmGridControl*) GetWindow();
2342     return pGrid ? pGrid->GetViewColumnPos(pGrid->GetCurColumnId()) : -1;
2343 }
2344 
2345 //------------------------------------------------------------------------------
2346 void FmXGridPeer::setCurrentColumnPosition(sal_Int16 nPos) throw( RuntimeException )
2347 {
2348     FmGridControl* pGrid = (FmGridControl*) GetWindow();
2349     if (pGrid)
2350         pGrid->GoToColumnId(pGrid->GetColumnIdFromViewPos(nPos));
2351 }
2352 
2353 //------------------------------------------------------------------------------
2354 void FmXGridPeer::selectionChanged(const EventObject& evt) throw( RuntimeException )
2355 {
2356     ::vos::OGuard aGuard(Application::GetSolarMutex());
2357 
2358     FmGridControl* pGrid = (FmGridControl*) GetWindow();
2359     if (pGrid)
2360     {
2361         Reference< ::com::sun::star::view::XSelectionSupplier >  xSelSupplier(evt.Source, UNO_QUERY);
2362         Any aSelection = xSelSupplier->getSelection();
2363         DBG_ASSERT(aSelection.getValueType().getTypeClass() == TypeClass_INTERFACE, "FmXGridPeer::selectionChanged : invalid selection !");
2364         Reference< XPropertySet >  xSelection;
2365          aSelection >>= xSelection;
2366         if (xSelection.is())
2367         {
2368             Reference< XPropertySet > xCol;
2369             sal_Int32 i = 0;
2370             sal_Int32 nColCount = m_xColumns->getCount();
2371 
2372             for (; i < nColCount; ++i)
2373             {
2374                 m_xColumns->getByIndex(i) >>= xCol;
2375                 if ( xCol == xSelection )
2376                 {
2377                     pGrid->markColumn(pGrid->GetColumnIdFromModelPos((sal_uInt16)i));
2378                     break;
2379                 }
2380             }
2381             // fuer das VCL-Control muessen die Columns 1-basiert sein
2382             // die Selektion an das VCL-Control weiterreichen, wenn noetig
2383             if ( i != pGrid->GetSelectedColumn() )
2384             {   // (wenn das nicht greift, wurde das selectionChanged implizit von dem Control selber ausgeloest
2385                 if ( i < nColCount )
2386                 {
2387                     pGrid->SelectColumnPos(pGrid->GetViewColumnPos(pGrid->GetColumnIdFromModelPos( (sal_uInt16)i )) + 1, sal_True);
2388                     // SelectColumnPos hat wieder zu einem impliziten ActivateCell gefuehrt
2389                     if (pGrid->IsEditing())
2390                         pGrid->DeactivateCell();
2391                 }
2392                 else
2393                     pGrid->SetNoSelection();
2394             }
2395         }
2396         else
2397             pGrid->markColumn(USHRT_MAX);
2398     }
2399 }
2400 
2401 // XElementAccess
2402 //------------------------------------------------------------------------------
2403 sal_Bool FmXGridPeer::hasElements() throw( RuntimeException )
2404 {
2405     return getCount() != 0;
2406 }
2407 
2408 //------------------------------------------------------------------------------
2409 Type SAL_CALL FmXGridPeer::getElementType(  ) throw(RuntimeException)
2410 {
2411     return ::getCppuType((Reference< ::com::sun::star::awt::XControl> *)NULL);
2412 }
2413 
2414 // XEnumerationAccess
2415 //------------------------------------------------------------------------------
2416 Reference< XEnumeration >  FmXGridPeer::createEnumeration() throw( RuntimeException )
2417 {
2418     return new ::comphelper::OEnumerationByIndex(this);
2419 }
2420 
2421 // XIndexAccess
2422 //------------------------------------------------------------------------------
2423 sal_Int32 FmXGridPeer::getCount() throw( RuntimeException )
2424 {
2425     FmGridControl* pGrid = (FmGridControl*) GetWindow();
2426     if (pGrid)
2427         return pGrid->GetViewColCount();
2428     else
2429         return 0;
2430 }
2431 
2432 //------------------------------------------------------------------------------
2433 Any FmXGridPeer::getByIndex(sal_Int32 _nIndex) throw( IndexOutOfBoundsException, WrappedTargetException, RuntimeException )
2434 {
2435     FmGridControl* pGrid = (FmGridControl*) GetWindow();
2436     if (_nIndex < 0 ||
2437         _nIndex >= getCount() || !pGrid)
2438         throw IndexOutOfBoundsException();
2439 
2440     Any aElement;
2441     // get the columnid
2442     sal_uInt16 nId = pGrid->GetColumnIdFromViewPos((sal_uInt16)_nIndex);
2443     // get the list position
2444     sal_uInt16 nPos = pGrid->GetModelColumnPos(nId);
2445 
2446     DbGridColumn* pCol = pGrid->GetColumns().GetObject(nPos);
2447 //  DBG_ASSERT(pCol && pCol->GetCell(), "FmXGridPeer::getByIndex(): Invalid cell");
2448     Reference< ::com::sun::star::awt::XControl >  xControl(pCol->GetCell());
2449     aElement <<= xControl;
2450 
2451     return aElement;
2452 }
2453 
2454 // ::com::sun::star::util::XModeSelector
2455 //------------------------------------------------------------------------------
2456 void FmXGridPeer::setMode(const ::rtl::OUString& Mode) throw( NoSupportException, RuntimeException )
2457 {
2458     if (!supportsMode(Mode))
2459         throw NoSupportException();
2460 
2461     if (Mode == m_aMode)
2462         return;
2463 
2464     m_aMode = Mode;
2465 
2466     FmGridControl* pGrid = (FmGridControl*) GetWindow();
2467     if ( Mode == ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterMode" ) ) )
2468         pGrid->SetFilterMode(sal_True);
2469     else
2470     {
2471         pGrid->SetFilterMode(sal_False);
2472         pGrid->setDataSource(m_xCursor);
2473     }
2474 }
2475 
2476 //------------------------------------------------------------------------------
2477 ::rtl::OUString FmXGridPeer::getMode() throw( RuntimeException )
2478 {
2479     return m_aMode;
2480 }
2481 
2482 //------------------------------------------------------------------------------
2483 ::comphelper::StringSequence FmXGridPeer::getSupportedModes() throw( RuntimeException )
2484 {
2485     static ::comphelper::StringSequence aModes;
2486     if (!aModes.getLength())
2487     {
2488         aModes.realloc(2);
2489         ::rtl::OUString* pModes = aModes.getArray();
2490         pModes[0] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DataMode" ) );
2491         pModes[1] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "FilterMode" ) );
2492     }
2493     return aModes;
2494 }
2495 
2496 //------------------------------------------------------------------------------
2497 sal_Bool FmXGridPeer::supportsMode(const ::rtl::OUString& Mode) throw( RuntimeException )
2498 {
2499     ::comphelper::StringSequence aModes(getSupportedModes());
2500     const ::rtl::OUString* pModes = aModes.getConstArray();
2501     for (sal_Int32 i = aModes.getLength(); i > 0; )
2502     {
2503         if (pModes[--i] == Mode)
2504             return sal_True;
2505     }
2506     return sal_False;
2507 }
2508 
2509 //------------------------------------------------------------------------------
2510 void FmXGridPeer::columnVisible(DbGridColumn* pColumn)
2511 {
2512     FmGridControl* pGrid = (FmGridControl*) GetWindow();
2513 
2514     sal_Int32 _nIndex = pGrid->GetModelColumnPos(pColumn->GetId());
2515     Reference< ::com::sun::star::awt::XControl >  xControl(pColumn->GetCell());
2516     ContainerEvent aEvt;
2517     aEvt.Source   = (XContainer*)this;
2518     aEvt.Accessor <<= _nIndex;
2519     aEvt.Element  <<= xControl;
2520 
2521     m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvt );
2522 }
2523 
2524 //------------------------------------------------------------------------------
2525 void FmXGridPeer::columnHidden(DbGridColumn* pColumn)
2526 {
2527     FmGridControl* pGrid = (FmGridControl*) GetWindow();
2528 
2529     sal_Int32 _nIndex = pGrid->GetModelColumnPos(pColumn->GetId());
2530     Reference< ::com::sun::star::awt::XControl >  xControl(pColumn->GetCell());
2531     ContainerEvent aEvt;
2532     aEvt.Source   = (XContainer*)this;
2533     aEvt.Accessor <<= _nIndex;
2534     aEvt.Element  <<= xControl;
2535 
2536     m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvt );
2537 }
2538 
2539 //------------------------------------------------------------------------------
2540 void FmXGridPeer::draw( sal_Int32 x, sal_Int32 y ) throw( RuntimeException )
2541 {
2542     FmGridControl* pGrid = (FmGridControl*) GetWindow();
2543     sal_Int32 nOldFlags = pGrid->GetBrowserFlags();
2544     pGrid->SetBrowserFlags(nOldFlags | EBBF_NOROWPICTURE);
2545 
2546     VCLXWindow::draw(x, y);
2547 
2548     pGrid->SetBrowserFlags(nOldFlags);
2549 }
2550 
2551 //------------------------------------------------------------------------------
2552 Reference< ::com::sun::star::frame::XDispatch >  FmXGridPeer::queryDispatch(const ::com::sun::star::util::URL& aURL, const ::rtl::OUString& aTargetFrameName, sal_Int32 nSearchFlags) throw( RuntimeException )
2553 {
2554     Reference< ::com::sun::star::frame::XDispatch >  xResult;
2555 
2556     // first ask our interceptor chain
2557     if (m_xFirstDispatchInterceptor.is() && !m_bInterceptingDispatch)
2558     {
2559         m_bInterceptingDispatch = sal_True;
2560             // safety against recursion : as we are master of the first chain element and slave of the last one we would
2561             // have an infinite loop without this if no dispatcher can fullfill the rewuest)
2562         xResult = m_xFirstDispatchInterceptor->queryDispatch(aURL, aTargetFrameName, nSearchFlags);
2563         m_bInterceptingDispatch = sal_False;
2564     }
2565 
2566     // then ask ourself : we don't have any dispatches
2567     return xResult;
2568 }
2569 
2570 //------------------------------------------------------------------------------
2571 Sequence< Reference< ::com::sun::star::frame::XDispatch > > FmXGridPeer::queryDispatches(const Sequence< ::com::sun::star::frame::DispatchDescriptor>& aDescripts) throw( RuntimeException )
2572 {
2573     if (m_xFirstDispatchInterceptor.is())
2574         return m_xFirstDispatchInterceptor->queryDispatches(aDescripts);
2575 
2576     // then ask ourself : we don't have any dispatches
2577     return Sequence< Reference< ::com::sun::star::frame::XDispatch > >();
2578 }
2579 
2580 //------------------------------------------------------------------------------
2581 void FmXGridPeer::registerDispatchProviderInterceptor(const Reference< ::com::sun::star::frame::XDispatchProviderInterceptor >& _xInterceptor) throw( RuntimeException )
2582 {
2583     if (_xInterceptor.is())
2584     {
2585         if (m_xFirstDispatchInterceptor.is())
2586         {
2587             Reference< ::com::sun::star::frame::XDispatchProvider > xFirstProvider(m_xFirstDispatchInterceptor, UNO_QUERY);
2588             // there is already an interceptor; the new one will become its master
2589             _xInterceptor->setSlaveDispatchProvider(xFirstProvider);
2590             m_xFirstDispatchInterceptor->setMasterDispatchProvider(xFirstProvider);
2591         }
2592         else
2593         {
2594             // it is the first interceptor; set ourself as slave
2595             _xInterceptor->setSlaveDispatchProvider((::com::sun::star::frame::XDispatchProvider*)this);
2596         }
2597 
2598         // we are the master of the chain's first interceptor
2599         m_xFirstDispatchInterceptor = _xInterceptor;
2600         m_xFirstDispatchInterceptor->setMasterDispatchProvider((::com::sun::star::frame::XDispatchProvider*)this);
2601 
2602         // we have a new interceptor and we're alive ?
2603         if (!isDesignMode())
2604             // -> check for new dispatchers
2605             UpdateDispatches();
2606     }
2607 }
2608 
2609 //------------------------------------------------------------------------------
2610 void FmXGridPeer::releaseDispatchProviderInterceptor(const Reference< ::com::sun::star::frame::XDispatchProviderInterceptor >& _xInterceptor) throw( RuntimeException )
2611 {
2612     if (!_xInterceptor.is())
2613         return;
2614 
2615     Reference< ::com::sun::star::frame::XDispatchProviderInterceptor >  xChainWalk(m_xFirstDispatchInterceptor);
2616 
2617     if (m_xFirstDispatchInterceptor == _xInterceptor)
2618     {   // our chain will have a new first element
2619         Reference< ::com::sun::star::frame::XDispatchProviderInterceptor >  xSlave(m_xFirstDispatchInterceptor->getSlaveDispatchProvider(), UNO_QUERY);
2620         m_xFirstDispatchInterceptor = xSlave;
2621     }
2622     // do this before removing the interceptor from the chain as we won't know it's slave afterwards)
2623 
2624     while (xChainWalk.is())
2625     {
2626         // walk along the chain of interceptors and look for the interceptor that has to be removed
2627         Reference< ::com::sun::star::frame::XDispatchProviderInterceptor >  xSlave(xChainWalk->getSlaveDispatchProvider(), UNO_QUERY);
2628 
2629         if (xChainWalk == _xInterceptor)
2630         {
2631             // old master may be an interceptor too
2632             Reference< ::com::sun::star::frame::XDispatchProviderInterceptor >  xMaster(xChainWalk->getMasterDispatchProvider(), UNO_QUERY);
2633 
2634             // unchain the interceptor that has to be removed
2635             xChainWalk->setSlaveDispatchProvider(Reference< ::com::sun::star::frame::XDispatchProvider > ());
2636             xChainWalk->setMasterDispatchProvider(Reference< ::com::sun::star::frame::XDispatchProvider > ());
2637 
2638             // reconnect the chain
2639             if (xMaster.is())
2640             {
2641                 if (xSlave.is())
2642                     xMaster->setSlaveDispatchProvider(Reference< ::com::sun::star::frame::XDispatchProvider >::query(xSlave));
2643                 else
2644                     // it's the first interceptor of the chain, set ourself as slave
2645                     xMaster->setSlaveDispatchProvider((::com::sun::star::frame::XDispatchProvider*)this);
2646             }
2647             else
2648             {
2649                 // the chain's first element was removed, set ourself as new master of the second one
2650                 if (xSlave.is())
2651                     xSlave->setMasterDispatchProvider((::com::sun::star::frame::XDispatchProvider*)this);
2652             }
2653         }
2654 
2655         xChainWalk = xSlave;
2656     }
2657     // our interceptor chain has changed and we're alive ?
2658     if (!isDesignMode())
2659         // -> check the dispatchers
2660         UpdateDispatches();
2661 }
2662 
2663 //------------------------------------------------------------------------------
2664 void FmXGridPeer::statusChanged(const ::com::sun::star::frame::FeatureStateEvent& Event) throw( RuntimeException )
2665 {
2666     DBG_ASSERT(m_pStateCache, "FmXGridPeer::statusChanged : invalid call !");
2667     DBG_ASSERT(m_pDispatchers, "FmXGridPeer::statusChanged : invalid call !");
2668 
2669     Sequence< ::com::sun::star::util::URL>& aUrls = getSupportedURLs();
2670     const ::com::sun::star::util::URL* pUrls = aUrls.getConstArray();
2671 
2672     Sequence<sal_uInt16> aSlots = getSupportedGridSlots();
2673     const sal_uInt16* pSlots = aSlots.getConstArray();
2674 
2675     sal_uInt16 i;
2676     for (i=0; i<aUrls.getLength(); ++i, ++pUrls, ++pSlots)
2677     {
2678         if (pUrls->Main == Event.FeatureURL.Main)
2679         {
2680             DBG_ASSERT(m_pDispatchers[i] == Event.Source, "FmXGridPeer::statusChanged : the event source is a little bit suspect !");
2681             m_pStateCache[i] = Event.IsEnabled;
2682             FmGridControl* pGrid = (FmGridControl*) GetWindow();
2683             if (*pSlots != SID_FM_RECORD_UNDO)
2684                 pGrid->GetNavigationBar().InvalidateState(*pSlots);
2685             break;
2686         }
2687     }
2688     DBG_ASSERT(i<aUrls.getLength(), "FmXGridPeer::statusChanged : got a call for an unknown url !");
2689 }
2690 
2691 //------------------------------------------------------------------------------
2692 sal_Bool FmXGridPeer::approveReset(const EventObject& /*rEvent*/) throw( RuntimeException )
2693 {
2694     return sal_True;
2695 }
2696 
2697 //------------------------------------------------------------------------------
2698 sal_Bool SAL_CALL FmXGridPeer::select( const Any& _rSelection ) throw (IllegalArgumentException, RuntimeException)
2699 {
2700     Sequence< Any > aBookmarks;
2701     if ( !( _rSelection >>= aBookmarks ) )
2702         throw IllegalArgumentException();
2703 
2704     FmGridControl* pVclControl = static_cast<FmGridControl*>(GetWindow());
2705     return pVclControl->selectBookmarks(aBookmarks);
2706 
2707     // TODO:
2708     // speaking strictly, we would have to adjust our model, as our ColumnSelection may have changed.
2709     // Our model is a XSelectionSupplier, too, it handles the selection of single columns.
2710     // This is somewhat strange, as selection should be a view (not a model) aspect.
2711     // So for a clean solution, we should handle column selection ourself, and the model shouldn't
2712     // deal with selection at all.
2713 }
2714 
2715 //------------------------------------------------------------------------------
2716 Any SAL_CALL FmXGridPeer::getSelection(  ) throw (RuntimeException)
2717 {
2718     FmGridControl* pVclControl = static_cast<FmGridControl*>(GetWindow());
2719     Sequence< Any > aSelectionBookmarks = pVclControl->getSelectionBookmarks();
2720     return makeAny(aSelectionBookmarks);
2721 }
2722 
2723 //------------------------------------------------------------------------------
2724 void SAL_CALL FmXGridPeer::addSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener ) throw (RuntimeException)
2725 {
2726     m_aSelectionListeners.addInterface( _rxListener );
2727 }
2728 
2729 //------------------------------------------------------------------------------
2730 void SAL_CALL FmXGridPeer::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& _rxListener ) throw (RuntimeException)
2731 {
2732     m_aSelectionListeners.removeInterface( _rxListener );
2733 }
2734 
2735 //------------------------------------------------------------------------------
2736 void FmXGridPeer::resetted(const EventObject& rEvent) throw( RuntimeException )
2737 {
2738     if (m_xColumns == rEvent.Source)
2739     {   // my model was reset -> refresh the grid content
2740         FmGridControl* pGrid = (FmGridControl*)GetWindow();
2741         if (!pGrid)
2742             return;
2743         ::vos::OGuard aGuard( Application::GetSolarMutex() );
2744         pGrid->resetCurrentRow();
2745     }
2746     // if the cursor fired a reset event we seem to be on the insert row
2747     else if (m_xCursor == rEvent.Source)
2748     {
2749         ::vos::OGuard aGuard( Application::GetSolarMutex() );
2750         FmGridControl* pGrid = (FmGridControl*) GetWindow();
2751         if (pGrid && pGrid->IsOpen())
2752             pGrid->positioned(rEvent);
2753     }
2754 }
2755 
2756 //------------------------------------------------------------------------------
2757 Sequence<sal_uInt16>& FmXGridPeer::getSupportedGridSlots()
2758 {
2759     static Sequence<sal_uInt16> aSupported;
2760     if (aSupported.getLength() == 0)
2761     {
2762         sal_uInt16 nSupported[] = {
2763             DbGridControl::NavigationBar::RECORD_FIRST,
2764             DbGridControl::NavigationBar::RECORD_PREV,
2765             DbGridControl::NavigationBar::RECORD_NEXT,
2766             DbGridControl::NavigationBar::RECORD_LAST,
2767             DbGridControl::NavigationBar::RECORD_NEW,
2768             SID_FM_RECORD_UNDO
2769         };
2770         aSupported.realloc(sizeof(nSupported)/sizeof(nSupported[0]));
2771         sal_uInt16* pSupported = aSupported.getArray();
2772         for (sal_uInt16 i=0; i<aSupported.getLength(); ++i, ++pSupported)
2773             *pSupported = nSupported[i];
2774     }
2775     return aSupported;
2776 }
2777 
2778 //------------------------------------------------------------------------------
2779 Sequence< ::com::sun::star::util::URL>& FmXGridPeer::getSupportedURLs()
2780 {
2781     static Sequence< ::com::sun::star::util::URL> aSupported;
2782     if (aSupported.getLength() == 0)
2783     {
2784         static ::rtl::OUString sSupported[] = {
2785             FMURL_RECORD_MOVEFIRST,
2786             FMURL_RECORD_MOVEPREV,
2787             FMURL_RECORD_MOVENEXT,
2788             FMURL_RECORD_MOVELAST,
2789             FMURL_RECORD_MOVETONEW,
2790             FMURL_RECORD_UNDO
2791         };
2792         aSupported.realloc(sizeof(sSupported)/sizeof(sSupported[0]));
2793         ::com::sun::star::util::URL* pSupported = aSupported.getArray();
2794         sal_uInt16 i;
2795 
2796         for ( i = 0; i < aSupported.getLength(); ++i, ++pSupported)
2797             pSupported->Complete = sSupported[i];
2798 
2799         // let an ::com::sun::star::util::URL-transformer normalize the URLs
2800         Reference< ::com::sun::star::util::XURLTransformer >  xTransformer(
2801             ::comphelper::getProcessServiceFactory()->createInstance(
2802                 ::rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer")),
2803             UNO_QUERY);
2804         pSupported = aSupported.getArray();
2805         if (xTransformer.is())
2806         {
2807             for (i=0; i<aSupported.getLength(); ++i)
2808                 xTransformer->parseStrict(pSupported[i]);
2809         }
2810     }
2811 
2812     return aSupported;
2813 }
2814 
2815 //------------------------------------------------------------------------------
2816 void FmXGridPeer::UpdateDispatches()
2817 {
2818     if (!m_pStateCache)
2819     {   // we don't have any dispatchers yet -> do the initial connect
2820         ConnectToDispatcher();
2821         return;
2822     }
2823 
2824     sal_uInt16 nDispatchersGot = 0;
2825     const Sequence< ::com::sun::star::util::URL>& aSupportedURLs = getSupportedURLs();
2826     const ::com::sun::star::util::URL* pSupportedURLs = aSupportedURLs.getConstArray();
2827     Reference< ::com::sun::star::frame::XDispatch >  xNewDispatch;
2828     for (sal_uInt16 i=0; i<aSupportedURLs.getLength(); ++i, ++pSupportedURLs)
2829     {
2830         xNewDispatch = queryDispatch(*pSupportedURLs, rtl::OUString(), 0);
2831         if (xNewDispatch != m_pDispatchers[i])
2832         {
2833             if (m_pDispatchers[i].is())
2834                 m_pDispatchers[i]->removeStatusListener((::com::sun::star::frame::XStatusListener*)this, *pSupportedURLs);
2835             m_pDispatchers[i] = xNewDispatch;
2836             if (m_pDispatchers[i].is())
2837                 m_pDispatchers[i]->addStatusListener((::com::sun::star::frame::XStatusListener*)this, *pSupportedURLs);
2838         }
2839         if (m_pDispatchers[i].is())
2840             ++nDispatchersGot;
2841     }
2842 
2843     if (!nDispatchersGot)
2844     {
2845         delete[] m_pStateCache;
2846         delete[] m_pDispatchers;
2847         m_pStateCache = NULL;
2848         m_pDispatchers = NULL;
2849     }
2850 }
2851 
2852 //------------------------------------------------------------------------------
2853 void FmXGridPeer::ConnectToDispatcher()
2854 {
2855     DBG_ASSERT((m_pStateCache != NULL) == (m_pDispatchers != NULL), "FmXGridPeer::ConnectToDispatcher : inconsistent !");
2856     if (m_pStateCache)
2857     {   // already connected -> just do an update
2858         UpdateDispatches();
2859         return;
2860     }
2861 
2862     const Sequence< ::com::sun::star::util::URL>& aSupportedURLs = getSupportedURLs();
2863 
2864     // _before_ adding the status listeners (as the add should result in a statusChanged-call) !
2865     m_pStateCache = new sal_Bool[aSupportedURLs.getLength()];
2866     m_pDispatchers = new Reference< ::com::sun::star::frame::XDispatch > [aSupportedURLs.getLength()];
2867 
2868     sal_uInt16 nDispatchersGot = 0;
2869     const ::com::sun::star::util::URL* pSupportedURLs = aSupportedURLs.getConstArray();
2870     for (sal_uInt16 i=0; i<aSupportedURLs.getLength(); ++i, ++pSupportedURLs)
2871     {
2872         m_pStateCache[i] = 0;
2873         m_pDispatchers[i] = queryDispatch(*pSupportedURLs, rtl::OUString(), 0);
2874         if (m_pDispatchers[i].is())
2875         {
2876             m_pDispatchers[i]->addStatusListener((::com::sun::star::frame::XStatusListener*)this, *pSupportedURLs);
2877             ++nDispatchersGot;
2878         }
2879     }
2880 
2881     if (!nDispatchersGot)
2882     {
2883         delete[] m_pStateCache;
2884         delete[] m_pDispatchers;
2885         m_pStateCache = NULL;
2886         m_pDispatchers = NULL;
2887     }
2888 }
2889 
2890 //------------------------------------------------------------------------------
2891 void FmXGridPeer::DisConnectFromDispatcher()
2892 {
2893     if (!m_pStateCache || !m_pDispatchers)
2894         return;
2895     // we're not connected
2896 
2897     const Sequence< ::com::sun::star::util::URL>& aSupportedURLs = getSupportedURLs();
2898     const ::com::sun::star::util::URL* pSupportedURLs = aSupportedURLs.getConstArray();
2899     for (sal_uInt16 i=0; i<aSupportedURLs.getLength(); ++i, ++pSupportedURLs)
2900     {
2901         if (m_pDispatchers[i].is())
2902             m_pDispatchers[i]->removeStatusListener((::com::sun::star::frame::XStatusListener*)this, *pSupportedURLs);
2903     }
2904 
2905     delete[] m_pStateCache;
2906     delete[] m_pDispatchers;
2907     m_pStateCache = NULL;
2908     m_pDispatchers = NULL;
2909 }
2910 
2911 //------------------------------------------------------------------------------
2912 IMPL_LINK(FmXGridPeer, OnQueryGridSlotState, void*, pSlot)
2913 {
2914     if (!m_pStateCache)
2915         return -1;  // unspecified
2916 
2917     sal_uInt16 nSlot = (sal_uInt16)(sal_uIntPtr)pSlot;
2918 
2919     // search the given slot with our supported sequence
2920     Sequence<sal_uInt16>& aSupported = getSupportedGridSlots();
2921     const sal_uInt16* pSlots = aSupported.getConstArray();
2922     for (sal_uInt16 i=0; i<aSupported.getLength(); ++i)
2923     {
2924         if (pSlots[i] == nSlot)
2925         {
2926             if (!m_pDispatchers[i].is())
2927                 return -1;  // nothing known about this slot
2928             else
2929                 return m_pStateCache[i];
2930         }
2931     }
2932 
2933     return  -1;
2934 }
2935 
2936 //------------------------------------------------------------------------------
2937 IMPL_LINK(FmXGridPeer, OnExecuteGridSlot, void*, pSlot)
2938 {
2939     if (!m_pDispatchers)
2940         return 0;   // not handled
2941 
2942     Sequence< ::com::sun::star::util::URL>& aUrls = getSupportedURLs();
2943     const ::com::sun::star::util::URL* pUrls = aUrls.getConstArray();
2944 
2945     Sequence<sal_uInt16> aSlots = getSupportedGridSlots();
2946     const sal_uInt16* pSlots = aSlots.getConstArray();
2947 
2948     DBG_ASSERT(aSlots.getLength() == aUrls.getLength(), "FmXGridPeer::OnExecuteGridSlot : inconstent data returned by getSupportedURLs/getSupportedGridSlots !");
2949 
2950     sal_uInt16 nSlot = (sal_uInt16)(sal_uIntPtr)pSlot;
2951     for (sal_uInt16 i=0; i<aSlots.getLength(); ++i, ++pUrls, ++pSlots)
2952     {
2953         if (*pSlots == nSlot)
2954         {
2955             if (m_pDispatchers[i].is())
2956             {
2957                 // commit any changes done so far, if it's not the undoRecord URL
2958                 if ( 0 == pUrls->Complete.compareTo( FMURL_RECORD_UNDO ) || commit() )
2959                     m_pDispatchers[i]->dispatch(*pUrls, Sequence< PropertyValue>());
2960 
2961                 return 1;   // handled
2962             }
2963         }
2964     }
2965 
2966     return 0;   // not handled
2967 }
2968 
2969