Coverage Report

Created: 2026-04-09 11:41

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