Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/form/fmvwimp.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
21
#include <memory>
22
#include <fmdocumentclassification.hxx>
23
#include <fmobj.hxx>
24
#include <fmpgeimp.hxx>
25
#include <fmprop.hxx>
26
#include <svx/strings.hrc>
27
#include <fmservs.hxx>
28
#include <fmshimp.hxx>
29
#include <svx/fmtools.hxx>
30
#include <fmvwimp.hxx>
31
#include <formcontrolfactory.hxx>
32
#include <svx/sdrpaintwindow.hxx>
33
#include <svx/svditer.hxx>
34
#include <svx/dataaccessdescriptor.hxx>
35
#include <svx/dialmgr.hxx>
36
#include <svx/svdobjkind.hxx>
37
#include <svx/fmmodel.hxx>
38
#include <svx/fmpage.hxx>
39
#include <svx/fmshell.hxx>
40
#include <svx/fmview.hxx>
41
#include <svx/sdrpagewindow.hxx>
42
#include <svx/svdogrp.hxx>
43
#include <svx/svdpagv.hxx>
44
#include <svx/xmlexchg.hxx>
45
#include <toolkit/helper/vclunohelper.hxx>
46
47
#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
48
#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
49
#include <com/sun/star/sdbc/XRowSet.hpp>
50
#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
51
#include <com/sun/star/util/XNumberFormats.hpp>
52
#include <com/sun/star/sdb/CommandType.hpp>
53
#include <com/sun/star/sdbc/DataType.hpp>
54
#include <com/sun/star/form/FormComponentType.hpp>
55
#include <com/sun/star/form/FormButtonType.hpp>
56
#include <com/sun/star/form/binding/XBindableValue.hpp>
57
#include <com/sun/star/form/binding/XValueBinding.hpp>
58
#include <com/sun/star/form/runtime/FormController.hpp>
59
#include <com/sun/star/form/submission/XSubmissionSupplier.hpp>
60
#include <com/sun/star/awt/XTabControllerModel.hpp>
61
#include <com/sun/star/awt/XControlContainer.hpp>
62
#include <com/sun/star/awt/XTabController.hpp>
63
#include <com/sun/star/container/XIndexAccess.hpp>
64
#include <com/sun/star/awt/XControl.hpp>
65
#include <com/sun/star/sdbc/SQLException.hpp>
66
#include <com/sun/star/container/XContainer.hpp>
67
68
#include <comphelper/namedvaluecollection.hxx>
69
#include <comphelper/property.hxx>
70
#include <comphelper/processfactory.hxx>
71
#include <comphelper/types.hxx>
72
#include <cppuhelper/exc_hlp.hxx>
73
#include <unotools/moduleoptions.hxx>
74
#include <tools/debug.hxx>
75
#include <comphelper/diagnose_ex.hxx>
76
#include <sal/log.hxx>
77
#include <utility>
78
#include <vcl/svapp.hxx>
79
#include <vcl/stdtext.hxx>
80
#include <vcl/window.hxx>
81
#include <connectivity/dbtools.hxx>
82
83
#include <algorithm>
84
85
using namespace ::comphelper;
86
using namespace ::svx;
87
using namespace ::svxform;
88
using namespace ::dbtools;
89
90
    using namespace ::com::sun::star;
91
    using ::com::sun::star::uno::Exception;
92
    using ::com::sun::star::uno::XInterface;
93
    using ::com::sun::star::uno::Sequence;
94
    using ::com::sun::star::uno::UNO_QUERY;
95
    using ::com::sun::star::uno::UNO_QUERY_THROW;
96
    using ::com::sun::star::uno::UNO_SET_THROW;
97
    using ::com::sun::star::uno::Type;
98
    using ::com::sun::star::uno::Reference;
99
    using ::com::sun::star::uno::Any;
100
    using ::com::sun::star::uno::XComponentContext;
101
    using ::com::sun::star::form::FormButtonType_SUBMIT;
102
    using ::com::sun::star::form::binding::XValueBinding;
103
    using ::com::sun::star::form::binding::XBindableValue;
104
    using ::com::sun::star::lang::XComponent;
105
    using ::com::sun::star::container::XIndexAccess;
106
    using ::com::sun::star::form::runtime::FormController;
107
    using ::com::sun::star::form::runtime::XFormController;
108
    using ::com::sun::star::script::XEventAttacherManager;
109
    using ::com::sun::star::awt::XTabControllerModel;
110
    using ::com::sun::star::container::XChild;
111
    using ::com::sun::star::task::XInteractionHandler;
112
    using ::com::sun::star::awt::XTabController;
113
    using ::com::sun::star::awt::XControlContainer;
114
    using ::com::sun::star::awt::XControl;
115
    using ::com::sun::star::form::XFormComponent;
116
    using ::com::sun::star::form::XForm;
117
    using ::com::sun::star::lang::IndexOutOfBoundsException;
118
    using ::com::sun::star::container::XContainer;
119
    using ::com::sun::star::container::ContainerEvent;
120
    using ::com::sun::star::lang::EventObject;
121
    using ::com::sun::star::sdb::SQLErrorEvent;
122
    using ::com::sun::star::sdbc::XRowSet;
123
    using ::com::sun::star::beans::XPropertySet;
124
    using ::com::sun::star::container::XElementAccess;
125
    using ::com::sun::star::awt::XWindow;
126
    using ::com::sun::star::awt::FocusEvent;
127
    using ::com::sun::star::ui::dialogs::XExecutableDialog;
128
    using ::com::sun::star::sdbc::XDataSource;
129
    using ::com::sun::star::container::XIndexContainer;
130
    using ::com::sun::star::sdbc::XConnection;
131
    using ::com::sun::star::container::XNameAccess;
132
    using ::com::sun::star::sdbc::SQLException;
133
    using ::com::sun::star::util::XNumberFormatsSupplier;
134
    using ::com::sun::star::util::XNumberFormats;
135
    using ::com::sun::star::beans::XPropertySetInfo;
136
137
    namespace FormComponentType = ::com::sun::star::form::FormComponentType;
138
    namespace CommandType = ::com::sun::star::sdb::CommandType;
139
    namespace DataType = ::com::sun::star::sdbc::DataType;
140
141
142
class FmXFormView::ObjectRemoveListener : public SfxListener
143
{
144
    FmXFormView* m_pParent;
145
public:
146
    explicit ObjectRemoveListener( FmXFormView* pParent );
147
    virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
148
};
149
150
FormViewPageWindowAdapter::FormViewPageWindowAdapter( css::uno::Reference<css::uno::XComponentContext> _xContext, const SdrPageWindow& _rWindow, FmXFormView* _pViewImpl )
151
30
:   m_xControlContainer( _rWindow.GetControlContainer() ),
152
30
    m_xContext(std::move( _xContext )),
153
30
    m_pViewImpl( _pViewImpl ),
154
30
    m_pWindow( _rWindow.GetPaintWindow().GetOutputDevice().GetOwnerWindow() )
155
30
{
156
157
    // create an XFormController for every form
158
30
    FmFormPage* pFormPage = dynamic_cast< FmFormPage* >( _rWindow.GetPageView().GetPage() );
159
30
    DBG_ASSERT( pFormPage, "FormViewPageWindowAdapter::FormViewPageWindowAdapter: no FmFormPage found!" );
160
30
    if ( !pFormPage )
161
0
        return;
162
163
30
    try
164
30
    {
165
30
        Reference< XIndexAccess > xForms( pFormPage->GetForms(), UNO_QUERY_THROW );
166
30
        sal_uInt32 nLength = xForms->getCount();
167
30
        for (sal_uInt32 i = 0; i < nLength; i++)
168
0
        {
169
0
            Reference< XForm > xForm( xForms->getByIndex(i), UNO_QUERY );
170
0
            if ( xForm.is() )
171
0
                setController( xForm, nullptr );
172
0
        }
173
30
    }
174
30
    catch (const Exception&)
175
30
    {
176
30
        DBG_UNHANDLED_EXCEPTION("svx");
177
30
    }
178
30
}
179
180
FormViewPageWindowAdapter::~FormViewPageWindowAdapter()
181
30
{
182
30
}
183
184
void FormViewPageWindowAdapter::dispose()
185
30
{
186
30
    for (   ::std::vector< Reference< XFormController > >::const_iterator i = m_aControllerList.begin();
187
30
            i != m_aControllerList.end();
188
30
            ++i
189
30
        )
190
0
    {
191
0
        try
192
0
        {
193
0
            Reference< XFormController > xController( *i, UNO_SET_THROW );
194
195
            // detaching the events
196
0
            Reference< XChild > xControllerModel( xController->getModel(), UNO_QUERY );
197
0
            if ( xControllerModel.is() )
198
0
            {
199
0
                Reference< XEventAttacherManager >  xEventManager( xControllerModel->getParent(), UNO_QUERY_THROW );
200
0
                Reference< XInterface > xControllerNormalized( xController, UNO_QUERY_THROW );
201
0
                xEventManager->detach( i - m_aControllerList.begin(), xControllerNormalized );
202
0
            }
203
204
            // dispose the formcontroller
205
0
            xController->dispose();
206
0
        }
207
0
        catch (const Exception&)
208
0
        {
209
0
            DBG_UNHANDLED_EXCEPTION("svx");
210
0
        }
211
0
    }
212
213
30
    m_aControllerList.clear();
214
30
}
215
216
sal_Bool SAL_CALL FormViewPageWindowAdapter::hasElements()
217
0
{
218
0
    return getCount() != 0;
219
0
}
220
221
Type SAL_CALL  FormViewPageWindowAdapter::getElementType()
222
0
{
223
0
    return cppu::UnoType<XFormController>::get();
224
0
}
225
226
// XIndexAccess
227
sal_Int32 SAL_CALL FormViewPageWindowAdapter::getCount()
228
0
{
229
0
    return m_aControllerList.size();
230
0
}
231
232
Any SAL_CALL FormViewPageWindowAdapter::getByIndex(sal_Int32 nIndex)
233
0
{
234
0
    if (nIndex < 0 ||
235
0
        nIndex >= getCount())
236
0
        throw IndexOutOfBoundsException();
237
238
0
    Any aElement;
239
0
    aElement <<= m_aControllerList[nIndex];
240
0
    return aElement;
241
0
}
242
243
void SAL_CALL FormViewPageWindowAdapter::makeVisible( const Reference< XControl >& Control )
244
0
{
245
0
    SolarMutexGuard aSolarGuard;
246
247
0
    Reference< XWindow >  xWindow( Control, UNO_QUERY );
248
0
    if ( xWindow.is() && m_pViewImpl->getView() && m_pWindow )
249
0
    {
250
0
        awt::Rectangle aRect = xWindow->getPosSize();
251
0
        ::tools::Rectangle aNewRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height );
252
0
        aNewRect = m_pWindow->PixelToLogic( aNewRect );
253
0
        m_pViewImpl->getView()->MakeVisible( aNewRect, *m_pWindow );
254
0
    }
255
0
}
256
257
static Reference< XFormController >  getControllerSearchChildren( const Reference< XIndexAccess > & xIndex, const Reference< XTabControllerModel > & xModel)
258
0
{
259
0
    if (xIndex.is() && xIndex->getCount())
260
0
    {
261
0
        Reference< XFormController >  xController;
262
263
0
        for (sal_Int32 n = xIndex->getCount(); n-- && !xController.is(); )
264
0
        {
265
0
            xIndex->getByIndex(n) >>= xController;
266
0
            if (xModel.get() == xController->getModel().get())
267
0
                return xController;
268
0
            else
269
0
            {
270
0
                xController = getControllerSearchChildren(xController, xModel);
271
0
                if ( xController.is() )
272
0
                    return xController;
273
0
            }
274
0
        }
275
0
    }
276
0
    return Reference< XFormController > ();
277
0
}
278
279
// Search the according controller
280
Reference< XFormController >  FormViewPageWindowAdapter::getController( const Reference< XForm > & xForm ) const
281
0
{
282
0
    Reference< XTabControllerModel >  xModel(xForm, UNO_QUERY);
283
0
    for (const auto& rpController : m_aControllerList)
284
0
    {
285
0
        if (rpController->getModel().get() == xModel.get())
286
0
            return rpController;
287
288
        // the current-round controller isn't the right one. perhaps one of its children ?
289
0
        Reference< XFormController >  xChildSearch = getControllerSearchChildren(Reference< XIndexAccess > (rpController, UNO_QUERY), xModel);
290
0
        if (xChildSearch.is())
291
0
            return xChildSearch;
292
0
    }
293
0
    return Reference< XFormController > ();
294
0
}
295
296
297
void FormViewPageWindowAdapter::setController(const Reference< XForm > & xForm, const Reference< XFormController >& _rxParentController )
298
0
{
299
0
    DBG_ASSERT( xForm.is(), "FormViewPageWindowAdapter::setController: there should be a form!" );
300
0
    Reference< XIndexAccess >  xFormCps(xForm, UNO_QUERY);
301
0
    if (!xFormCps.is())
302
0
        return;
303
304
0
    Reference< XTabControllerModel >  xTabOrder(xForm, UNO_QUERY);
305
306
    // create a form controller
307
0
    Reference< XFormController > xController( FormController::create(m_xContext) );
308
309
0
    Reference< XInteractionHandler > xHandler;
310
0
    if ( _rxParentController.is() )
311
0
        xHandler = _rxParentController->getInteractionHandler();
312
0
    else
313
0
    {
314
        // TODO: should we create a default handler? Not really necessary, since the
315
        // FormController itself has a default fallback
316
0
    }
317
0
    if ( xHandler.is() )
318
0
        xController->setInteractionHandler( xHandler );
319
320
0
    xController->setContext( this );
321
322
0
    xController->setModel( xTabOrder );
323
0
    xController->setContainer( m_xControlContainer );
324
0
    xController->activateTabOrder();
325
0
    xController->addActivateListener( m_pViewImpl );
326
327
0
    if ( _rxParentController.is() )
328
0
        _rxParentController->addChildController( xController );
329
0
    else
330
0
    {
331
0
        m_aControllerList.push_back(xController);
332
333
0
        xController->setParent( *this );
334
335
        // attaching the events
336
0
        Reference< XEventAttacherManager > xEventManager( xForm->getParent(), UNO_QUERY );
337
0
        xEventManager->attach(m_aControllerList.size() - 1, Reference<XInterface>( xController, UNO_QUERY ), Any(xController) );
338
0
    }
339
340
    // now go through the subforms
341
0
    sal_uInt32 nLength = xFormCps->getCount();
342
0
    Reference< XForm >  xSubForm;
343
0
    for (sal_uInt32 i = 0; i < nLength; i++)
344
0
    {
345
0
        if ( xFormCps->getByIndex(i) >>= xSubForm )
346
0
            setController( xSubForm, xController );
347
0
    }
348
0
}
349
350
351
void FormViewPageWindowAdapter::updateTabOrder( const Reference< XForm >& _rxForm )
352
0
{
353
0
    OSL_PRECOND( _rxForm.is(), "FormViewPageWindowAdapter::updateTabOrder: illegal argument!" );
354
0
    if ( !_rxForm.is() )
355
0
        return;
356
357
0
    try
358
0
    {
359
0
        Reference< XTabController > xTabCtrl( getController( _rxForm ) );
360
0
        if ( xTabCtrl.is() )
361
0
        {   // if there already is a TabController for this form, then delegate the "updateTabOrder" request
362
0
            xTabCtrl->activateTabOrder();
363
0
        }
364
0
        else
365
0
        {   // otherwise, create a TabController
366
367
            // if it's a sub form, then we must ensure there exist TabControllers
368
            // for all its ancestors, too
369
0
            Reference< XForm > xParentForm( _rxForm->getParent(), UNO_QUERY );
370
            // there is a parent form -> look for the respective controller
371
0
            Reference< XFormController > xParentController;
372
0
            if ( xParentForm.is() )
373
0
                xParentController = getController( xParentForm );
374
375
0
            setController( _rxForm, xParentController );
376
0
        }
377
0
    }
378
0
    catch (const Exception&)
379
0
    {
380
0
        DBG_UNHANDLED_EXCEPTION("svx");
381
0
    }
382
0
}
383
384
385
FmXFormView::FmXFormView(FmFormView* _pView )
386
87.9k
    :m_pMarkedGrid(nullptr)
387
87.9k
    ,m_pView(_pView)
388
87.9k
    ,m_nActivationEvent(nullptr)
389
87.9k
    ,m_nErrorMessageEvent( nullptr )
390
87.9k
    ,m_nAutoFocusEvent( nullptr )
391
87.9k
    ,m_nControlWizardEvent( nullptr )
392
87.9k
    ,m_bFirstActivation( true )
393
87.9k
    ,m_isTabOrderUpdateSuspended( false )
394
87.9k
{
395
87.9k
}
396
397
398
void FmXFormView::cancelEvents()
399
175k
{
400
175k
    if ( m_nActivationEvent )
401
0
    {
402
0
        Application::RemoveUserEvent( m_nActivationEvent );
403
0
        m_nActivationEvent = nullptr;
404
0
    }
405
406
175k
    if ( m_nErrorMessageEvent )
407
0
    {
408
0
        Application::RemoveUserEvent( m_nErrorMessageEvent );
409
0
        m_nErrorMessageEvent = nullptr;
410
0
    }
411
412
175k
    if ( m_nAutoFocusEvent )
413
0
    {
414
0
        Application::RemoveUserEvent( m_nAutoFocusEvent );
415
0
        m_nAutoFocusEvent = nullptr;
416
0
    }
417
418
175k
    if ( m_nControlWizardEvent )
419
0
    {
420
0
        Application::RemoveUserEvent( m_nControlWizardEvent );
421
0
        m_nControlWizardEvent = nullptr;
422
0
    }
423
175k
}
424
425
426
void FmXFormView::notifyViewDying( )
427
87.9k
{
428
87.9k
    DBG_ASSERT( m_pView, "FmXFormView::notifyViewDying: my view already died!" );
429
87.9k
    m_pView = nullptr;
430
87.9k
    cancelEvents();
431
87.9k
}
432
433
434
FmXFormView::~FmXFormView()
435
87.9k
{
436
87.9k
    DBG_ASSERT( m_aPageWindowAdapters.empty(), "FmXFormView::~FmXFormView: Window list not empty!" );
437
87.9k
    for (const auto& rpAdapter : m_aPageWindowAdapters)
438
0
    {
439
0
        rpAdapter->dispose();
440
0
    }
441
442
87.9k
    cancelEvents();
443
87.9k
}
444
445
//      EventListener
446
447
void SAL_CALL FmXFormView::disposing(const EventObject& Source)
448
0
{
449
0
    if ( m_xWindow.is() && Source.Source == m_xWindow )
450
0
    {
451
0
        m_xWindow->removeFocusListener(this);
452
0
        if ( m_pView )
453
0
        {
454
0
            m_pView->SetMoveOutside( false, FmFormView::ImplAccess() );
455
0
        }
456
0
        m_xWindow = nullptr;
457
0
    }
458
0
}
459
460
// XFormControllerListener
461
462
void SAL_CALL FmXFormView::formActivated(const EventObject& rEvent)
463
0
{
464
0
    if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() )
465
0
        m_pView->GetFormShell()->GetImpl()->formActivated( rEvent );
466
0
}
467
468
469
void SAL_CALL FmXFormView::formDeactivated(const EventObject& rEvent)
470
0
{
471
0
    if ( m_pView && m_pView->GetFormShell() && m_pView->GetFormShell()->GetImpl() )
472
0
        m_pView->GetFormShell()->GetImpl()->formDeactivated( rEvent );
473
0
}
474
475
// XContainerListener
476
477
void SAL_CALL FmXFormView::elementInserted(const ContainerEvent& evt)
478
0
{
479
0
    try
480
0
    {
481
0
        Reference< XControlContainer > xControlContainer( evt.Source, UNO_QUERY_THROW );
482
0
        Reference< XControl > xControl( evt.Element, UNO_QUERY_THROW );
483
0
        Reference< XFormComponent > xControlModel( xControl->getModel(), UNO_QUERY_THROW );
484
0
        Reference< XForm > xForm( xControlModel->getParent(), UNO_QUERY_THROW );
485
486
0
        if ( m_isTabOrderUpdateSuspended )
487
0
        {
488
            // remember the container and the control, so we can update the tab order on resumeTabOrderUpdate
489
0
            m_aNeedTabOrderUpdate[ xControlContainer ].insert( xForm );
490
0
        }
491
0
        else
492
0
        {
493
0
            rtl::Reference< FormViewPageWindowAdapter > pAdapter = findWindow( xControlContainer );
494
0
            if ( pAdapter.is() )
495
0
                pAdapter->updateTabOrder( xForm );
496
0
        }
497
0
    }
498
0
    catch (const Exception&)
499
0
    {
500
0
        DBG_UNHANDLED_EXCEPTION("svx");
501
0
    }
502
0
}
503
504
505
void SAL_CALL FmXFormView::elementReplaced(const ContainerEvent& evt)
506
0
{
507
0
    elementInserted(evt);
508
0
}
509
510
511
void SAL_CALL FmXFormView::elementRemoved(const ContainerEvent& /*evt*/)
512
0
{
513
0
}
514
515
516
rtl::Reference< FormViewPageWindowAdapter > FmXFormView::findWindow( const Reference< XControlContainer >& _rxCC )  const
517
60
{
518
60
    auto i = std::find_if(m_aPageWindowAdapters.begin(), m_aPageWindowAdapters.end(),
519
60
        [&_rxCC](const rtl::Reference< FormViewPageWindowAdapter >& rpAdapter) { return _rxCC == rpAdapter->getControlContainer(); });
520
60
    if (i != m_aPageWindowAdapters.end())
521
30
        return *i;
522
30
    return nullptr;
523
60
}
524
525
526
void FmXFormView::addWindow(const SdrPageWindow& rWindow)
527
60
{
528
60
    FmFormPage* pFormPage = dynamic_cast<FmFormPage*>( rWindow.GetPageView().GetPage()  );
529
60
    if ( !pFormPage )
530
0
        return;
531
532
60
    const rtl::Reference< UnoControlContainer > & xCC = rWindow.GetControlContainer();
533
60
    if  (   xCC.is()
534
60
        &&  ( !findWindow( xCC ).is() )
535
60
        )
536
30
    {
537
30
        rtl::Reference< FormViewPageWindowAdapter > pAdapter = new FormViewPageWindowAdapter( comphelper::getProcessComponentContext(), rWindow, this );
538
30
        m_aPageWindowAdapters.push_back( pAdapter );
539
540
        // listen at the ControlContainer to notice changes
541
30
        xCC->addContainerListener( this );
542
30
    }
543
60
}
544
545
546
void FmXFormView::removeWindow( const Reference< XControlContainer >& _rxCC )
547
60
{
548
    // Is called if
549
    // - the design mode is being switched to
550
    // - a window is deleted while in the design mode
551
    // - the control container for a window is removed while the active mode is on
552
553
60
    auto i = std::find_if(m_aPageWindowAdapters.begin(), m_aPageWindowAdapters.end(),
554
60
        [&_rxCC](const rtl::Reference< FormViewPageWindowAdapter >& rpAdapter) { return _rxCC == rpAdapter->getControlContainer(); });
555
60
    if (i != m_aPageWindowAdapters.end())
556
30
    {
557
30
        Reference< XContainer >  xContainer( _rxCC, UNO_QUERY );
558
30
        if ( xContainer.is() )
559
30
            xContainer->removeContainerListener( this );
560
561
30
        (*i)->dispose();
562
30
        m_aPageWindowAdapters.erase( i );
563
30
    }
564
60
}
565
566
void FmXFormView::displayAsyncErrorMessage( const SQLErrorEvent& _rEvent )
567
0
{
568
0
    DBG_ASSERT( nullptr == m_nErrorMessageEvent, "FmXFormView::displayAsyncErrorMessage: not too fast, please!" );
569
        // This should not happen - usually, the PostUserEvent is faster than any possible user
570
        // interaction which could trigger a new error. If it happens, we need a queue for the events.
571
0
    m_aAsyncError = _rEvent;
572
0
    m_nErrorMessageEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnDelayedErrorMessage ) );
573
0
}
574
575
IMPL_LINK_NOARG(FmXFormView, OnDelayedErrorMessage, void*, void)
576
0
{
577
0
    m_nErrorMessageEvent = nullptr;
578
0
    displayException(m_aAsyncError, GetParentWindow());
579
0
}
580
581
void FmXFormView::onFirstViewActivation( const FmFormModel* _pDocModel )
582
13
{
583
13
    if ( _pDocModel && _pDocModel->GetAutoControlFocus() )
584
0
        m_nAutoFocusEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnAutoFocus ) );
585
13
}
586
587
void FmXFormView::suspendTabOrderUpdate()
588
83.4k
{
589
83.4k
    OSL_ENSURE( !m_isTabOrderUpdateSuspended, "FmXFormView::suspendTabOrderUpdate: nesting not allowed!" );
590
83.4k
    m_isTabOrderUpdateSuspended = true;
591
83.4k
}
592
593
void FmXFormView::resumeTabOrderUpdate()
594
83.4k
{
595
83.4k
    OSL_ENSURE( m_isTabOrderUpdateSuspended, "FmXFormView::resumeTabOrderUpdate: not suspended!" );
596
83.4k
    m_isTabOrderUpdateSuspended = false;
597
598
    // update the tab orders for all components which were collected since the suspendTabOrderUpdate call.
599
83.4k
    for (const auto& rContainer : m_aNeedTabOrderUpdate)
600
0
    {
601
0
        rtl::Reference< FormViewPageWindowAdapter > pAdapter = findWindow( rContainer.first );
602
0
        if ( !pAdapter.is() )
603
0
            continue;
604
605
0
        for (const auto& rForm : rContainer.second)
606
0
        {
607
0
            pAdapter->updateTabOrder( rForm );
608
0
        }
609
0
    }
610
83.4k
    m_aNeedTabOrderUpdate.clear();
611
83.4k
}
612
613
namespace
614
{
615
    bool isActivableDatabaseForm(const Reference< XFormController > &xController)
616
0
    {
617
        // only database forms are to be activated
618
0
        Reference< XRowSet >  xForm(xController->getModel(), UNO_QUERY);
619
0
        if ( !xForm.is() || !getConnection( xForm ).is() )
620
0
            return false;
621
622
0
        Reference< XPropertySet > xFormSet( xForm, UNO_QUERY );
623
0
        if ( !xFormSet.is() )
624
0
        {
625
0
            SAL_WARN( "svx.form", "FmXFormView::OnActivate: a form which does not have properties?" );
626
0
            return false;
627
0
        }
628
629
0
        const OUString aSource = ::comphelper::getString( xFormSet->getPropertyValue( FM_PROP_COMMAND ) );
630
631
0
        return !aSource.isEmpty();
632
0
    }
633
634
    class find_active_databaseform
635
    {
636
        const Reference< XFormController > xActiveController;
637
638
    public:
639
640
        explicit find_active_databaseform( const Reference< XFormController >& _xActiveController )
641
0
            : xActiveController(_xActiveController )
642
0
        {}
643
644
        Reference < XFormController > operator() (const Reference< XFormController > &xController)
645
0
        {
646
0
            if(xController == xActiveController && isActivableDatabaseForm(xController))
647
0
                return xController;
648
649
0
            if ( !xController.is() )
650
0
            {
651
0
                SAL_WARN( "svx.form", "FmXFormView::OnActivate: a form controller which does not have children?" );
652
0
                return nullptr;
653
0
            }
654
655
0
            for(sal_Int32 i = 0; i < xController->getCount(); ++i)
656
0
            {
657
0
                const Any a(xController->getByIndex(i));
658
0
                Reference < XFormController > xI;
659
0
                if ((a >>= xI) && xI.is())
660
0
                {
661
0
                    Reference < XFormController > xRes(operator()(xI));
662
0
                    if (xRes.is())
663
0
                        return xRes;
664
0
                }
665
0
            }
666
667
0
            return nullptr;
668
0
        }
669
    };
670
}
671
672
673
IMPL_LINK_NOARG(FmXFormView, OnActivate, void*, void)
674
0
{
675
0
    m_nActivationEvent = nullptr;
676
677
0
    if ( !m_pView )
678
0
    {
679
0
        OSL_FAIL( "FmXFormView::OnActivate: well... seems we have a timing problem (the view already died)!" );
680
0
        return;
681
0
    }
682
683
    // setting the controller to activate
684
0
    if (!(m_pView->GetFormShell() && m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW))
685
0
        return;
686
687
0
    FmXFormShell* const pShImpl =  m_pView->GetFormShell()->GetImpl();
688
689
0
    if(!pShImpl)
690
0
        return;
691
692
0
    find_active_databaseform fad(pShImpl->getActiveController_Lock());
693
694
0
    vcl::Window* pWindow = m_pView->GetActualOutDev()->GetOwnerWindow();
695
0
    rtl::Reference< FormViewPageWindowAdapter > pAdapter = m_aPageWindowAdapters.empty() ? nullptr : m_aPageWindowAdapters[0];
696
0
    for (const auto& rpPageWindowAdapter : m_aPageWindowAdapters)
697
0
    {
698
0
        if ( pWindow == rpPageWindowAdapter->getWindow() )
699
0
            pAdapter = rpPageWindowAdapter;
700
0
    }
701
702
0
    if ( !pAdapter.is() )
703
0
        return;
704
705
0
    Reference< XFormController > xControllerToActivate;
706
0
    for (const Reference< XFormController > & xController : pAdapter->GetList())
707
0
    {
708
0
        if ( !xController.is() )
709
0
            continue;
710
711
0
        {
712
0
            Reference< XFormController > xActiveController(fad(xController));
713
0
            if (xActiveController.is())
714
0
            {
715
0
                xControllerToActivate = std::move(xActiveController);
716
0
                break;
717
0
            }
718
0
        }
719
720
0
        if(xControllerToActivate.is() || !isActivableDatabaseForm(xController))
721
0
            continue;
722
723
0
        xControllerToActivate = xController;
724
0
    }
725
0
    pShImpl->setActiveController_Lock(xControllerToActivate);
726
0
}
727
728
729
void FmXFormView::Activate(bool bSync)
730
88.0k
{
731
88.0k
    if (m_nActivationEvent)
732
13
    {
733
13
        Application::RemoveUserEvent(m_nActivationEvent);
734
13
        m_nActivationEvent = nullptr;
735
13
    }
736
737
88.0k
    if (bSync)
738
0
    {
739
0
        LINK(this,FmXFormView,OnActivate).Call(nullptr);
740
0
    }
741
88.0k
    else
742
88.0k
        m_nActivationEvent = Application::PostUserEvent(LINK(this,FmXFormView,OnActivate));
743
88.0k
}
744
745
746
void FmXFormView::Deactivate(bool bDeactivateController)
747
88.0k
{
748
88.0k
    if (m_nActivationEvent)
749
87.9k
    {
750
87.9k
        Application::RemoveUserEvent(m_nActivationEvent);
751
87.9k
        m_nActivationEvent = nullptr;
752
87.9k
    }
753
754
88.0k
    FmXFormShell* pShImpl =  m_pView->GetFormShell() ? m_pView->GetFormShell()->GetImpl() : nullptr;
755
88.0k
    if (pShImpl && bDeactivateController)
756
0
        pShImpl->setActiveController_Lock(nullptr);
757
88.0k
}
758
759
760
FmFormShell* FmXFormView::GetFormShell() const
761
9.15k
{
762
9.15k
    return m_pView ? m_pView->GetFormShell() : nullptr;
763
9.15k
}
764
765
void FmXFormView::AutoFocus()
766
0
{
767
0
    if (m_nAutoFocusEvent)
768
0
        Application::RemoveUserEvent(m_nAutoFocusEvent);
769
770
0
    m_nAutoFocusEvent = Application::PostUserEvent(LINK(this, FmXFormView, OnAutoFocus));
771
0
}
772
773
774
bool FmXFormView::isFocusable( const Reference< XControl >& i_rControl )
775
0
{
776
0
    if ( !i_rControl.is() )
777
0
        return false;
778
779
0
    try
780
0
    {
781
0
        Reference< XPropertySet > xModelProps( i_rControl->getModel(), UNO_QUERY_THROW );
782
783
        // only enabled controls are allowed to participate
784
0
        bool bEnabled = false;
785
0
        OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_ENABLED ) >>= bEnabled );
786
0
        if ( !bEnabled )
787
0
            return false;
788
789
        // check the class id of the control model
790
0
        sal_Int16 nClassId = FormComponentType::CONTROL;
791
0
        OSL_VERIFY( xModelProps->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
792
793
        // controls which are not focussable
794
0
        if  (   ( FormComponentType::CONTROL != nClassId )
795
0
            &&  ( FormComponentType::IMAGEBUTTON != nClassId )
796
0
            &&  ( FormComponentType::GROUPBOX != nClassId )
797
0
            &&  ( FormComponentType::FIXEDTEXT != nClassId )
798
0
            &&  ( FormComponentType::HIDDENCONTROL != nClassId )
799
0
            &&  ( FormComponentType::IMAGECONTROL != nClassId )
800
0
            &&  ( FormComponentType::SCROLLBAR != nClassId )
801
0
            &&  ( FormComponentType::SPINBUTTON!= nClassId )
802
0
            )
803
0
        {
804
0
            return true;
805
0
        }
806
0
    }
807
0
    catch (const Exception&)
808
0
    {
809
0
        DBG_UNHANDLED_EXCEPTION("svx");
810
0
    }
811
0
    return false;
812
0
}
813
814
815
static Reference< XControl > lcl_firstFocussableControl( const Sequence< Reference< XControl > >& _rControls )
816
0
{
817
0
    Reference< XControl > xReturn;
818
819
    // loop through all the controls
820
0
    for ( auto const & control : _rControls )
821
0
    {
822
0
        if ( !control.is() )
823
0
            continue;
824
825
0
        if ( FmXFormView::isFocusable( control ) )
826
0
        {
827
0
            xReturn = control;
828
0
            break;
829
0
        }
830
0
    }
831
832
0
    if ( !xReturn.is() && _rControls.hasElements() )
833
0
        xReturn = _rControls[0];
834
835
0
    return xReturn;
836
0
}
837
838
839
namespace
840
{
841
842
    void lcl_ensureControlsOfFormExist_nothrow( const SdrPage& _rPage, const SdrView& _rView, const vcl::Window& _rWindow, const Reference< XForm >& _rxForm )
843
0
    {
844
0
        try
845
0
        {
846
0
            Reference< XInterface > xNormalizedForm( _rxForm, UNO_QUERY_THROW );
847
848
0
            SdrObjListIter aSdrObjectLoop( &_rPage, SdrIterMode::DeepNoGroups );
849
0
            while ( aSdrObjectLoop.IsMore() )
850
0
            {
851
0
                FmFormObj* pFormObject = FmFormObj::GetFormObject( aSdrObjectLoop.Next() );
852
0
                if ( !pFormObject )
853
0
                    continue;
854
855
0
                Reference< XChild > xModel( pFormObject->GetUnoControlModel(), UNO_QUERY_THROW );
856
0
                Reference< XInterface > xModelParent( xModel->getParent(), UNO_QUERY );
857
858
0
                if ( xNormalizedForm.get() != xModelParent.get() )
859
0
                    continue;
860
861
0
                pFormObject->GetUnoControl( _rView, *_rWindow.GetOutDev() );
862
0
            }
863
0
        }
864
0
        catch (const Exception&)
865
0
        {
866
0
            DBG_UNHANDLED_EXCEPTION("svx");
867
0
        }
868
0
    }
869
}
870
871
872
Reference< XFormController > FmXFormView::getFormController( const Reference< XForm >& _rxForm, const OutputDevice& _rDevice ) const
873
0
{
874
0
    Reference< XFormController > xController;
875
876
0
    for (const rtl::Reference< FormViewPageWindowAdapter >& pAdapter : m_aPageWindowAdapters)
877
0
    {
878
0
        if ( !pAdapter )
879
0
        {
880
0
            SAL_WARN( "svx.form", "FmXFormView::getFormController: invalid page window adapter!" );
881
0
            continue;
882
0
        }
883
884
0
        if ( pAdapter->getWindow() != _rDevice.GetOwnerWindow() )
885
            // wrong device
886
0
            continue;
887
888
0
        xController = pAdapter->getController( _rxForm );
889
0
        if ( xController.is() )
890
0
            break;
891
0
    }
892
0
    return xController;
893
0
}
894
895
896
IMPL_LINK_NOARG(FmXFormView, OnAutoFocus, void*, void)
897
0
{
898
0
    m_nAutoFocusEvent = nullptr;
899
900
    // go to the first form of our page, examine it's TabController, go to its first (in terms of the tab order)
901
    // control, give it the focus
902
903
0
    SdrPageView *pPageView = m_pView ? m_pView->GetSdrPageView() : nullptr;
904
0
    SdrPage *pSdrPage = pPageView ? pPageView->GetPage() : nullptr;
905
    // get the forms collection of the page we belong to
906
0
    FmFormPage* pPage = dynamic_cast<FmFormPage*>( pSdrPage  );
907
0
    Reference< XIndexAccess > xForms( pPage ? Reference< XIndexAccess >( pPage->GetForms() ) : Reference< XIndexAccess >() );
908
909
0
    const rtl::Reference< FormViewPageWindowAdapter > pAdapter = m_aPageWindowAdapters.empty() ? nullptr : m_aPageWindowAdapters[0];
910
0
    const vcl::Window* pWindow = pAdapter ? pAdapter->getWindow() : nullptr;
911
912
0
    ENSURE_OR_RETURN_VOID( xForms.is() && pWindow, "FmXFormView::OnAutoFocus: could not collect all essentials!" );
913
914
0
    try
915
0
    {
916
        // go for the tab controller of the first form
917
0
        if ( !xForms->getCount() )
918
0
            return;
919
0
        Reference< XForm > xForm( xForms->getByIndex( 0 ), UNO_QUERY_THROW );
920
0
        Reference< XTabController > xTabController( pAdapter->getController( xForm ), UNO_QUERY_THROW );
921
922
        // go for the first control of the controller
923
0
        Sequence< Reference< XControl > > aControls( xTabController->getControls() );
924
0
        if ( !aControls.hasElements() )
925
0
        {
926
0
            Reference< XElementAccess > xFormElementAccess( xForm, UNO_QUERY_THROW );
927
0
            if (xFormElementAccess->hasElements() && pPage && m_pView)
928
0
            {
929
                // there are control models in the form, but no controls, yet.
930
                // Well, since some time controls are created on demand only. In particular,
931
                // they're normally created when they're first painted.
932
                // Unfortunately, the FormController does not have any way to
933
                // trigger the creation itself, so we must hack this ...
934
0
                lcl_ensureControlsOfFormExist_nothrow( *pPage, *m_pView, *pWindow, xForm );
935
0
                aControls = xTabController->getControls();
936
0
                OSL_ENSURE( aControls.hasElements(), "FmXFormView::OnAutoFocus: no controls at all!" );
937
0
            }
938
0
        }
939
940
        // set the focus to this first control
941
0
        Reference< XWindow > xControlWindow( lcl_firstFocussableControl( aControls ), UNO_QUERY );
942
0
        if ( !xControlWindow.is() )
943
0
            return;
944
945
0
        xControlWindow->setFocus();
946
947
        // ensure that the control is visible
948
        // 80210 - 12/07/00 - FS
949
0
        const OutputDevice* pOut = m_pView ? m_pView->GetActualOutDev() : nullptr;
950
0
        const vcl::Window* pCurrentWindow = pOut ? pOut->GetOwnerWindow() : nullptr;
951
0
        if ( pCurrentWindow )
952
0
        {
953
0
            awt::Rectangle aRect = xControlWindow->getPosSize();
954
0
            ::tools::Rectangle aNonUnoRect( aRect.X, aRect.Y, aRect.X + aRect.Width, aRect.Y + aRect.Height );
955
0
            m_pView->MakeVisible( pCurrentWindow->PixelToLogic( aNonUnoRect ), *const_cast< vcl::Window* >( pCurrentWindow ) );
956
0
        }
957
0
    }
958
0
    catch (const Exception&)
959
0
    {
960
0
        DBG_UNHANDLED_EXCEPTION("svx");
961
0
    }
962
0
}
963
964
965
void FmXFormView::onCreatedFormObject( FmFormObj const & _rFormObject )
966
0
{
967
0
    FmFormShell* pShell = m_pView ? m_pView->GetFormShell() : nullptr;
968
0
    FmXFormShell* pShellImpl = pShell ? pShell->GetImpl() : nullptr;
969
0
    OSL_ENSURE( pShellImpl, "FmXFormView::onCreatedFormObject: no form shell!" );
970
0
    if ( !pShellImpl )
971
0
        return;
972
973
    // it is valid that the form shell's forms collection is not initialized, yet
974
0
    pShellImpl->UpdateForms_Lock(true);
975
976
0
    m_xLastCreatedControlModel.set( _rFormObject.GetUnoControlModel(), UNO_QUERY );
977
0
    if ( !m_xLastCreatedControlModel.is() )
978
0
        return;
979
980
    // some initial property defaults
981
0
    FormControlFactory aControlFactory;
982
0
    aControlFactory.initializeControlModel(pShellImpl->getDocumentType_Lock(), _rFormObject);
983
984
0
    if (!pShellImpl->GetWizardUsing_Lock())
985
0
        return;
986
987
    // #i31958# don't call wizards in XForms mode
988
0
    if (pShellImpl->isEnhancedForm_Lock())
989
0
        return;
990
991
    // #i46898# no wizards if there is no Base installed - currently, all wizards are
992
    // database related
993
0
    if (!SvtModuleOptions().IsDataBaseInstalled())
994
0
        return;
995
996
0
    if ( m_nControlWizardEvent )
997
0
        Application::RemoveUserEvent( m_nControlWizardEvent );
998
0
    m_nControlWizardEvent = Application::PostUserEvent( LINK( this, FmXFormView, OnStartControlWizard ) );
999
0
}
1000
1001
void FmXFormView::breakCreateFormObject()
1002
0
{
1003
0
    if (m_nControlWizardEvent != nullptr)
1004
0
    {
1005
0
        Application::RemoveUserEvent(m_nControlWizardEvent);
1006
0
        m_nControlWizardEvent = nullptr;
1007
0
    }
1008
0
    m_xLastCreatedControlModel.clear();
1009
0
}
1010
1011
Reference<XWindow> FmXFormView::GetParentWindow() const
1012
0
{
1013
0
    const OutputDevice* pOut = m_pView ? m_pView->GetActualOutDev() : nullptr;
1014
0
    const vcl::Window* pCurrentWindow = pOut ? pOut->GetOwnerWindow() : nullptr;
1015
0
    return VCLUnoHelper::GetInterface(const_cast<vcl::Window*>(pCurrentWindow));
1016
0
}
1017
1018
IMPL_LINK_NOARG( FmXFormView, OnStartControlWizard, void*, void )
1019
0
{
1020
0
    m_nControlWizardEvent = nullptr;
1021
0
    OSL_PRECOND( m_xLastCreatedControlModel.is(), "FmXFormView::OnStartControlWizard: illegal call!" );
1022
0
    if ( !m_xLastCreatedControlModel.is() )
1023
0
        return;
1024
1025
0
    sal_Int16 nClassId = FormComponentType::CONTROL;
1026
0
    try
1027
0
    {
1028
0
        OSL_VERIFY( m_xLastCreatedControlModel->getPropertyValue( FM_PROP_CLASSID ) >>= nClassId );
1029
0
    }
1030
0
    catch (const Exception&)
1031
0
    {
1032
0
        DBG_UNHANDLED_EXCEPTION("svx");
1033
0
    }
1034
1035
0
    const char* pWizardAsciiName = nullptr;
1036
0
    switch ( nClassId )
1037
0
    {
1038
0
        case FormComponentType::GRIDCONTROL:
1039
0
            pWizardAsciiName = "com.sun.star.sdb.GridControlAutoPilot";
1040
0
            break;
1041
0
        case FormComponentType::LISTBOX:
1042
0
        case FormComponentType::COMBOBOX:
1043
0
            pWizardAsciiName = "com.sun.star.sdb.ListComboBoxAutoPilot";
1044
0
            break;
1045
0
        case FormComponentType::GROUPBOX:
1046
0
            pWizardAsciiName = "com.sun.star.sdb.GroupBoxAutoPilot";
1047
0
            break;
1048
0
    }
1049
1050
0
    if ( pWizardAsciiName )
1051
0
    {
1052
        // build the argument list
1053
0
        ::comphelper::NamedValueCollection aWizardArgs;
1054
0
        aWizardArgs.put(u"ObjectModel"_ustr, m_xLastCreatedControlModel);
1055
0
        aWizardArgs.put(u"ParentWindow"_ustr, GetParentWindow());
1056
1057
        // create the wizard object
1058
0
        Reference< XExecutableDialog > xWizard;
1059
0
        try
1060
0
        {
1061
0
            const Reference<XComponentContext>& xContext = comphelper::getProcessComponentContext();
1062
0
            xWizard.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext( OUString::createFromAscii(pWizardAsciiName), aWizardArgs.getWrappedPropertyValues(), xContext ), UNO_QUERY);
1063
0
        }
1064
0
        catch (const Exception&)
1065
0
        {
1066
0
            DBG_UNHANDLED_EXCEPTION("svx");
1067
0
        }
1068
1069
0
        if ( !xWizard.is() )
1070
0
        {
1071
0
            ShowServiceNotAvailableError( nullptr, OUString::createFromAscii(pWizardAsciiName), true );
1072
0
        }
1073
0
        else
1074
0
        {
1075
            // execute the wizard
1076
0
            try
1077
0
            {
1078
0
                xWizard->execute();
1079
0
            }
1080
0
            catch (const Exception&)
1081
0
            {
1082
0
                DBG_UNHANDLED_EXCEPTION("svx");
1083
0
            }
1084
0
        }
1085
0
    }
1086
1087
0
    m_xLastCreatedControlModel.clear();
1088
0
}
1089
1090
1091
namespace
1092
{
1093
    void lcl_insertIntoFormComponentHierarchy_throw( const FmFormView& _rView, const SdrUnoObj& _rSdrObj,
1094
        const Reference< XDataSource >& _rxDataSource, const OUString& _rDataSourceName,
1095
        const OUString& _rCommand, const sal_Int32 _nCommandType )
1096
0
    {
1097
0
        FmFormPage& rPage = static_cast< FmFormPage& >( *_rView.GetSdrPageView()->GetPage() );
1098
1099
0
        Reference< XFormComponent > xFormComponent( _rSdrObj.GetUnoControlModel(), UNO_QUERY_THROW );
1100
0
        Reference< XForm > xTargetForm(
1101
0
            rPage.GetImpl().findPlaceInFormComponentHierarchy( xFormComponent, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType ),
1102
0
            UNO_SET_THROW );
1103
1104
0
        FmFormPageImpl::setUniqueName( xFormComponent, xTargetForm );
1105
1106
0
        Reference< XIndexContainer > xFormAsContainer( xTargetForm, UNO_QUERY_THROW );
1107
0
        xFormAsContainer->insertByIndex( xFormAsContainer->getCount(), Any( xFormComponent ) );
1108
0
    }
1109
}
1110
1111
1112
rtl::Reference<SdrObject> FmXFormView::implCreateFieldControl( const svx::ODataAccessDescriptor& _rColumnDescriptor )
1113
0
{
1114
    // not if we're in design mode
1115
0
    if ( !m_pView->IsDesignMode() )
1116
0
        return nullptr;
1117
1118
0
    OUString sCommand, sFieldName;
1119
0
    sal_Int32 nCommandType = CommandType::COMMAND;
1120
0
    SharedConnection xConnection;
1121
1122
0
    OUString sDataSource = _rColumnDescriptor.getDataSource();
1123
0
    _rColumnDescriptor[ DataAccessDescriptorProperty::Command ]     >>= sCommand;
1124
0
    _rColumnDescriptor[ DataAccessDescriptorProperty::ColumnName ]  >>= sFieldName;
1125
0
    _rColumnDescriptor[ DataAccessDescriptorProperty::CommandType ] >>= nCommandType;
1126
0
    {
1127
0
        Reference< XConnection > xExternalConnection;
1128
0
        _rColumnDescriptor[ DataAccessDescriptorProperty::Connection ]  >>= xExternalConnection;
1129
0
        xConnection.reset( xExternalConnection, SharedConnection::NoTakeOwnership );
1130
0
    }
1131
1132
0
    if  (   sCommand.isEmpty()
1133
0
        ||  sFieldName.isEmpty()
1134
0
        ||  (   sDataSource.isEmpty()
1135
0
            &&  !xConnection.is()
1136
0
            )
1137
0
        )
1138
0
    {
1139
0
        OSL_FAIL( "FmXFormView::implCreateFieldControl: nonsense!" );
1140
0
    }
1141
1142
0
    Reference< XDataSource > xDataSource;
1143
0
    SQLErrorEvent aError;
1144
0
    try
1145
0
    {
1146
0
        if ( xConnection.is() && !xDataSource.is() && sDataSource.isEmpty() )
1147
0
        {
1148
0
            Reference< XChild > xChild( xConnection, UNO_QUERY );
1149
0
            if ( xChild.is() )
1150
0
                xDataSource.set(xChild->getParent(), css::uno::UNO_QUERY);
1151
0
        }
1152
1153
        // obtain the data source
1154
0
        if ( !xDataSource.is() )
1155
0
            xDataSource = getDataSource( sDataSource, comphelper::getProcessComponentContext() );
1156
1157
        // and the connection, if necessary
1158
0
        if ( !xConnection.is() )
1159
0
            xConnection.reset( getConnection_withFeedback(
1160
0
                sDataSource,
1161
0
                OUString(),
1162
0
                OUString(),
1163
0
                comphelper::getProcessComponentContext(),
1164
0
                nullptr
1165
0
            ) );
1166
0
    }
1167
0
    catch (const SQLException&)
1168
0
    {
1169
0
        aError.Reason = ::cppu::getCaughtException();
1170
0
    }
1171
0
    catch (const Exception& )
1172
0
    {
1173
        /* will be asserted below */
1174
0
    }
1175
0
    if (aError.Reason.hasValue())
1176
0
    {
1177
0
        displayAsyncErrorMessage( aError );
1178
0
        return nullptr;
1179
0
    }
1180
1181
    // need a data source and a connection here
1182
0
    if (!xDataSource.is() || !xConnection.is())
1183
0
    {
1184
0
        OSL_FAIL("FmXFormView::implCreateFieldControl : could not retrieve the data source or the connection!");
1185
0
        return nullptr;
1186
0
    }
1187
1188
0
    Reference< XComponent > xKeepFieldsAlive;
1189
    // go
1190
0
    try
1191
0
    {
1192
        // determine the table/query field which we should create a control for
1193
0
        Reference< XPropertySet >   xField;
1194
1195
0
        Reference< XNameAccess >    xFields = getFieldsByCommandDescriptor(
1196
0
            xConnection, nCommandType, sCommand, xKeepFieldsAlive );
1197
1198
0
        if (xFields.is() && xFields->hasByName(sFieldName))
1199
0
            xFields->getByName(sFieldName) >>= xField;
1200
0
        if ( !xField.is() )
1201
0
            return nullptr;
1202
1203
0
        Reference< XNumberFormatsSupplier > xSupplier( getNumberFormats( xConnection ), UNO_SET_THROW );
1204
0
        Reference< XNumberFormats >  xNumberFormats( xSupplier->getNumberFormats(), UNO_SET_THROW );
1205
1206
0
        OUString sLabelPostfix;
1207
1208
1209
        // only for text size
1210
0
        OutputDevice* pOutDev = nullptr;
1211
0
        if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
1212
0
            pOutDev = const_cast<OutputDevice*>(m_pView->GetActualOutDev());
1213
0
        else
1214
0
        {// find OutDev
1215
0
            if (SdrPageView* pPageView = m_pView->GetSdrPageView())
1216
0
            {
1217
                // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
1218
                // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();
1219
1220
0
                for( sal_uInt32 i = 0; i < pPageView->PageWindowCount(); i++ )
1221
0
                {
1222
0
                    const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);
1223
1224
0
                    if( rPageWindow.GetPaintWindow().OutputToWindow())
1225
0
                    {
1226
0
                        pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice();
1227
0
                        break;
1228
0
                    }
1229
0
                }
1230
0
            }
1231
0
        }
1232
1233
0
        if ( !pOutDev )
1234
0
            return nullptr;
1235
1236
0
        sal_Int32 nDataType = ::comphelper::getINT32(xField->getPropertyValue(FM_PROP_FIELDTYPE));
1237
0
        if ((DataType::BINARY == nDataType) || (DataType::VARBINARY == nDataType))
1238
0
            return nullptr;
1239
1240
1241
        // determine the control type by examining the data type of the bound column
1242
0
        SdrObjKind nOBJID = SdrObjKind::NONE;
1243
0
        bool bDateNTimeField = false;
1244
1245
0
        bool bIsCurrency = false;
1246
0
        if (::comphelper::hasProperty(FM_PROP_ISCURRENCY, xField))
1247
0
            bIsCurrency = ::comphelper::getBOOL(xField->getPropertyValue(FM_PROP_ISCURRENCY));
1248
1249
0
        if (bIsCurrency)
1250
0
            nOBJID = SdrObjKind::FormCurrencyField;
1251
0
        else
1252
0
            switch (nDataType)
1253
0
            {
1254
0
                case DataType::BLOB:
1255
0
                case DataType::LONGVARBINARY:
1256
0
                    nOBJID = SdrObjKind::FormImageControl;
1257
0
                    break;
1258
0
                case DataType::LONGVARCHAR:
1259
0
                case DataType::CLOB:
1260
0
                    nOBJID = SdrObjKind::FormEdit;
1261
0
                    break;
1262
0
                case DataType::BINARY:
1263
0
                case DataType::VARBINARY:
1264
0
                    return nullptr;
1265
0
                case DataType::BIT:
1266
0
                case DataType::BOOLEAN:
1267
0
                    nOBJID = SdrObjKind::FormCheckbox;
1268
0
                    break;
1269
0
                case DataType::TINYINT:
1270
0
                case DataType::SMALLINT:
1271
0
                case DataType::INTEGER:
1272
0
                    nOBJID = SdrObjKind::FormNumericField;
1273
0
                    break;
1274
0
                case DataType::REAL:
1275
0
                case DataType::DOUBLE:
1276
0
                case DataType::NUMERIC:
1277
0
                case DataType::DECIMAL:
1278
0
                    nOBJID = SdrObjKind::FormFormattedField;
1279
0
                    break;
1280
0
                case DataType::TIMESTAMP:
1281
0
                    bDateNTimeField = true;
1282
0
                    sLabelPostfix = SvxResId(RID_STR_POSTFIX_DATE);
1283
0
                    [[fallthrough]];
1284
0
                case DataType::DATE:
1285
0
                    nOBJID = SdrObjKind::FormDateField;
1286
0
                    break;
1287
0
                case DataType::TIME:
1288
0
                    nOBJID = SdrObjKind::FormTimeField;
1289
0
                    break;
1290
0
                case DataType::CHAR:
1291
0
                case DataType::VARCHAR:
1292
0
                default:
1293
0
                    nOBJID = SdrObjKind::FormEdit;
1294
0
                    break;
1295
0
            }
1296
0
        if (nOBJID == SdrObjKind::NONE)
1297
0
            return nullptr;
1298
1299
0
        rtl::Reference<SdrUnoObj> pLabel;
1300
0
        rtl::Reference<SdrUnoObj> pControl;
1301
0
        if  (   !createControlLabelPair( *pOutDev, 0, 0, xField, xNumberFormats, nOBJID, sLabelPostfix,
1302
0
                    pLabel, pControl, xDataSource, sDataSource, sCommand, nCommandType )
1303
0
            )
1304
0
        {
1305
0
            return nullptr;
1306
0
        }
1307
1308
1309
        // group objects
1310
0
        bool bCheckbox = ( SdrObjKind::FormCheckbox == nOBJID );
1311
0
        OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateFieldControl: why was there a label created for a check box?" );
1312
0
        if ( bCheckbox )
1313
0
            return pControl;
1314
1315
0
        rtl::Reference<SdrObjGroup> pGroup  = new SdrObjGroup(getView()->getSdrModelFromSdrView());
1316
0
        SdrObjList* pObjList = pGroup->GetSubList();
1317
0
        pObjList->InsertObject( pLabel.get() );
1318
0
        pObjList->InsertObject( pControl.get() );
1319
1320
0
        if ( bDateNTimeField )
1321
0
        {   // so far we created a date field only, but we also need a time field
1322
0
            if  (   createControlLabelPair( *pOutDev, 0, 1000, xField, xNumberFormats, SdrObjKind::FormTimeField,
1323
0
                        SvxResId(RID_STR_POSTFIX_TIME), pLabel, pControl,
1324
0
                        xDataSource, sDataSource, sCommand, nCommandType )
1325
0
                )
1326
0
            {
1327
0
                pObjList->InsertObject( pLabel.get() );
1328
0
                pObjList->InsertObject( pControl.get() );
1329
0
            }
1330
0
        }
1331
1332
0
        return pGroup; // and done
1333
0
    }
1334
0
    catch (const Exception&)
1335
0
    {
1336
0
        DBG_UNHANDLED_EXCEPTION("svx");
1337
0
    }
1338
1339
1340
0
    return nullptr;
1341
0
}
1342
1343
1344
rtl::Reference<SdrObject> FmXFormView::implCreateXFormsControl( const svx::OXFormsDescriptor &_rDesc )
1345
0
{
1346
    // not if we're in design mode
1347
0
    if ( !m_pView->IsDesignMode() )
1348
0
        return nullptr;
1349
1350
    // go
1351
0
    try
1352
0
    {
1353
        // determine the table/query field which we should create a control for
1354
0
        Reference< XNumberFormats > xNumberFormats;
1355
0
        OUString sLabelPostfix = _rDesc.szName;
1356
1357
1358
        // only for text size
1359
0
        OutputDevice* pOutDev = nullptr;
1360
0
        if (m_pView->GetActualOutDev() && m_pView->GetActualOutDev()->GetOutDevType() == OUTDEV_WINDOW)
1361
0
            pOutDev = const_cast<OutputDevice*>(m_pView->GetActualOutDev());
1362
0
        else
1363
0
        {// find OutDev
1364
0
            if (SdrPageView* pPageView = m_pView->GetSdrPageView())
1365
0
            {
1366
                // const SdrPageViewWinList& rWinList = pPageView->GetWinList();
1367
                // const SdrPageViewWindows& rPageViewWindows = pPageView->GetPageViewWindows();
1368
1369
0
                for( sal_uInt32 i = 0; i < pPageView->PageWindowCount(); i++ )
1370
0
                {
1371
0
                    const SdrPageWindow& rPageWindow = *pPageView->GetPageWindow(i);
1372
1373
0
                    if( rPageWindow.GetPaintWindow().GetOutputDevice().GetOutDevType() == OUTDEV_WINDOW)
1374
0
                    {
1375
0
                        pOutDev = &rPageWindow.GetPaintWindow().GetOutputDevice();
1376
0
                        break;
1377
0
                    }
1378
0
                }
1379
0
            }
1380
0
        }
1381
1382
0
        if ( !pOutDev )
1383
0
            return nullptr;
1384
1385
1386
        // The service name decides which control should be created
1387
0
        SdrObjKind nOBJID = SdrObjKind::FormEdit;
1388
0
        if(_rDesc.szServiceName == FM_SUN_COMPONENT_NUMERICFIELD)
1389
0
            nOBJID = SdrObjKind::FormNumericField;
1390
0
        if(_rDesc.szServiceName == FM_SUN_COMPONENT_CHECKBOX)
1391
0
            nOBJID = SdrObjKind::FormCheckbox;
1392
0
        if(_rDesc.szServiceName == FM_COMPONENT_COMMANDBUTTON)
1393
0
            nOBJID = SdrObjKind::FormButton;
1394
1395
0
        Reference< css::form::submission::XSubmission > xSubmission(_rDesc.xPropSet, UNO_QUERY);
1396
1397
        // xform control or submission button?
1398
0
        if ( !xSubmission.is() )
1399
0
        {
1400
0
            rtl::Reference<SdrUnoObj> pLabel;
1401
0
            rtl::Reference<SdrUnoObj> pControl;
1402
0
            if  (   !createControlLabelPair( *pOutDev, 0, 0, nullptr, xNumberFormats, nOBJID, sLabelPostfix,
1403
0
                        pLabel, pControl, nullptr, u""_ustr, u""_ustr, -1 )
1404
0
                )
1405
0
            {
1406
0
                return nullptr;
1407
0
            }
1408
1409
1410
            // Now build the connection between the control and the data item.
1411
0
            Reference< XValueBinding > xValueBinding(_rDesc.xPropSet,UNO_QUERY);
1412
0
            Reference< XBindableValue > xBindableValue(pControl->GetUnoControlModel(),UNO_QUERY);
1413
1414
0
            DBG_ASSERT( xBindableValue.is(), "FmXFormView::implCreateXFormsControl: control's not bindable!" );
1415
0
            if ( xBindableValue.is() )
1416
0
                xBindableValue->setValueBinding(xValueBinding);
1417
1418
0
            bool bCheckbox = ( SdrObjKind::FormCheckbox == nOBJID );
1419
0
            OSL_ENSURE( !bCheckbox || !pLabel, "FmXFormView::implCreateXFormsControl: why was there a label created for a check box?" );
1420
0
            if ( bCheckbox )
1421
0
                return pControl;
1422
1423
1424
            // group objects
1425
0
            rtl::Reference<SdrObjGroup> pGroup  = new SdrObjGroup(getView()->getSdrModelFromSdrView());
1426
0
            SdrObjList* pObjList = pGroup->GetSubList();
1427
0
            pObjList->InsertObject(pLabel.get());
1428
0
            pObjList->InsertObject(pControl.get());
1429
1430
0
            return pGroup;
1431
0
        }
1432
0
        else {
1433
1434
            // create a button control
1435
0
            const MapMode& eTargetMode( pOutDev->GetMapMode() );
1436
0
            const MapMode eSourceMode(MapUnit::Map100thMM);
1437
0
            const SdrObjKind nObjID = SdrObjKind::FormButton;
1438
0
            ::Size controlSize(4000, 500);
1439
0
            rtl::Reference<FmFormObj> pControl = static_cast<FmFormObj*>(
1440
0
                SdrObjFactory::MakeNewObject(
1441
0
                    getView()->getSdrModelFromSdrView(),
1442
0
                    SdrInventor::FmForm,
1443
0
                    nObjID).get());
1444
0
            controlSize.setWidth( tools::Long(controlSize.Width() * eTargetMode.GetScaleX()) );
1445
0
            controlSize.setHeight( tools::Long(controlSize.Height() * eTargetMode.GetScaleY()) );
1446
0
            ::Point controlPos( OutputDevice::LogicToLogic( ::Point( controlSize.Width(), 0 ), eSourceMode, eTargetMode ) );
1447
0
            ::tools::Rectangle controlRect( controlPos, OutputDevice::LogicToLogic( controlSize, eSourceMode, eTargetMode ) );
1448
0
            pControl->SetLogicRect(controlRect);
1449
1450
            // set the button label
1451
0
            Reference< XPropertySet > xControlSet(pControl->GetUnoControlModel(), UNO_QUERY);
1452
0
            xControlSet->setPropertyValue(FM_PROP_LABEL, Any(_rDesc.szName));
1453
1454
            // connect the submission with the submission supplier (aka the button)
1455
0
            xControlSet->setPropertyValue( FM_PROP_BUTTON_TYPE,
1456
0
                                           Any( FormButtonType_SUBMIT ) );
1457
0
            Reference< css::form::submission::XSubmissionSupplier > xSubmissionSupplier(pControl->GetUnoControlModel(), UNO_QUERY);
1458
0
            xSubmissionSupplier->setSubmission(xSubmission);
1459
1460
0
            return rtl::Reference<SdrObject>(pControl);
1461
0
        }
1462
0
    }
1463
0
    catch (const Exception&)
1464
0
    {
1465
0
        TOOLS_WARN_EXCEPTION("svx.form", "caught an exception while creating the control !");
1466
0
    }
1467
1468
1469
0
    return nullptr;
1470
0
}
1471
1472
bool FmXFormView::createControlLabelPair( OutputDevice const & _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM,
1473
        const Reference< XPropertySet >& _rxField, const Reference< XNumberFormats >& _rxNumberFormats,
1474
        SdrObjKind _nControlObjectID, std::u16string_view _rFieldPostfix,
1475
        rtl::Reference<SdrUnoObj>& _rpLabel,
1476
        rtl::Reference<SdrUnoObj>& _rpControl,
1477
        const Reference< XDataSource >& _rxDataSource, const OUString& _rDataSourceName,
1478
        const OUString& _rCommand, const sal_Int32 _nCommandType )
1479
0
{
1480
0
    if(!createControlLabelPair(
1481
0
        _rOutDev,
1482
0
        _nXOffsetMM,
1483
0
        _nYOffsetMM,
1484
0
        _rxField,
1485
0
        _rxNumberFormats,
1486
0
        _nControlObjectID,
1487
0
        _rFieldPostfix,
1488
0
        SdrInventor::FmForm,
1489
0
        SdrObjKind::FormFixedText,
1490
1491
        // tdf#118963 Hand over a SdrModel to SdrObject-creation. It uses the local m_pView
1492
        // and already returning false when nullptr == getView() could be done, but m_pView
1493
        // is already dereferenced here in many places (see below), so just use it for now.
1494
0
        getView()->getSdrModelFromSdrView(),
1495
1496
0
        _rpLabel,
1497
0
        _rpControl))
1498
0
    {
1499
0
        return false;
1500
0
    }
1501
1502
    // insert the control model(s) into the form component hierarchy
1503
0
    if ( _rpLabel )
1504
0
        lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpLabel, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType );
1505
0
    lcl_insertIntoFormComponentHierarchy_throw( *m_pView, *_rpControl, _rxDataSource, _rDataSourceName, _rCommand, _nCommandType );
1506
1507
    // some context-dependent initializations
1508
0
    FormControlFactory aControlFactory;
1509
0
    if ( _rpLabel )
1510
0
        aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpLabel );
1511
0
    aControlFactory.initializeControlModel( impl_getDocumentType(), *_rpControl );
1512
1513
0
    return true;
1514
0
}
1515
1516
1517
bool FmXFormView::createControlLabelPair( OutputDevice const & _rOutDev, sal_Int32 _nXOffsetMM, sal_Int32 _nYOffsetMM,
1518
    const Reference< XPropertySet >& _rxField,
1519
    const Reference< XNumberFormats >& _rxNumberFormats, SdrObjKind _nControlObjectID,
1520
    std::u16string_view _rFieldPostfix, SdrInventor _nInventor, SdrObjKind _nLabelObjectID,
1521
    SdrModel& _rModel,
1522
    rtl::Reference<SdrUnoObj>& _rpLabel, rtl::Reference<SdrUnoObj>& _rpControl)
1523
0
{
1524
0
    sal_Int32 nDataType = 0;
1525
0
    OUString sFieldName;
1526
0
    Any aFieldName;
1527
0
    if ( _rxField.is() )
1528
0
    {
1529
0
        nDataType = ::comphelper::getINT32(_rxField->getPropertyValue(FM_PROP_FIELDTYPE));
1530
0
        aFieldName = _rxField->getPropertyValue(FM_PROP_NAME);
1531
0
        aFieldName >>= sFieldName;
1532
0
    }
1533
1534
    // calculate the positions, respecting the settings of the target device
1535
0
    ::Size aTextSize( _rOutDev.GetTextWidth(sFieldName + _rFieldPostfix), _rOutDev.GetTextHeight() );
1536
1537
0
    const MapMode & eTargetMode( _rOutDev.GetMapMode() );
1538
0
    MapMode eSourceMode( MapUnit::Map100thMM );
1539
1540
    // text width is at least 4 centimeters
1541
    // text height is always half a centimeter
1542
0
    ::Size aDefTxtSize(4000, 500);
1543
0
    ::Size aDefSize(4000, 500);
1544
0
    ::Size aDefImageSize(4000, 4000);
1545
1546
0
    ::Size aRealSize = OutputDevice::LogicToLogic(aTextSize, eTargetMode, eSourceMode);
1547
0
    aRealSize.setWidth( std::max(aRealSize.Width(), aDefTxtSize.Width()) );
1548
0
    aRealSize.setHeight( aDefSize.Height() );
1549
1550
    // adjust to scaling of the target device (#53523#)
1551
0
    aRealSize.setWidth( tools::Long(Fraction(aRealSize.Width(), 1) * eTargetMode.GetScaleX()) );
1552
0
    aRealSize.setHeight( tools::Long(Fraction(aRealSize.Height(), 1) * eTargetMode.GetScaleY()) );
1553
1554
    // for boolean fields, we do not create a label, but just a checkbox
1555
0
    bool bNeedLabel = ( _nControlObjectID != SdrObjKind::FormCheckbox );
1556
1557
    // the label
1558
0
    rtl::Reference< SdrUnoObj > pLabel;
1559
0
    Reference< XPropertySet > xLabelModel;
1560
1561
0
    if ( bNeedLabel )
1562
0
    {
1563
0
        pLabel = dynamic_cast< SdrUnoObj* >(
1564
0
            SdrObjFactory::MakeNewObject(
1565
0
                _rModel,
1566
0
                _nInventor,
1567
0
                _nLabelObjectID).get() );
1568
1569
0
        OSL_ENSURE(pLabel, "FmXFormView::createControlLabelPair: could not create the label!");
1570
1571
0
        if (!pLabel)
1572
0
            return false;
1573
1574
0
        xLabelModel.set( pLabel->GetUnoControlModel(), UNO_QUERY );
1575
0
        if ( xLabelModel.is() )
1576
0
        {
1577
0
            OUString sLabel;
1578
0
            if ( _rxField.is() && _rxField->getPropertySetInfo()->hasPropertyByName(FM_PROP_LABEL) )
1579
0
                _rxField->getPropertyValue(FM_PROP_LABEL) >>= sLabel;
1580
0
            if ( sLabel.isEmpty() )
1581
0
                sLabel = sFieldName;
1582
1583
0
            xLabelModel->setPropertyValue( FM_PROP_LABEL, Any( sLabel + _rFieldPostfix ) );
1584
0
            OUString sObjectLabel(SvxResId(RID_STR_OBJECT_LABEL).replaceAll("#object#", sFieldName));
1585
0
            xLabelModel->setPropertyValue(FM_PROP_NAME, Any(sObjectLabel));
1586
0
        }
1587
1588
0
        pLabel->SetLogicRect( ::tools::Rectangle(
1589
0
            OutputDevice::LogicToLogic( ::Point( _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ),
1590
0
            OutputDevice::LogicToLogic( aRealSize, eSourceMode, eTargetMode )
1591
0
        ) );
1592
0
    }
1593
1594
    // the control
1595
0
    rtl::Reference< SdrUnoObj > pControl( dynamic_cast< SdrUnoObj* >(
1596
0
        SdrObjFactory::MakeNewObject(
1597
0
            _rModel,
1598
0
             _nInventor,
1599
0
             _nControlObjectID).get() ));
1600
1601
0
    OSL_ENSURE(pControl, "FmXFormView::createControlLabelPair: could not create the control!");
1602
1603
0
    if (!pControl)
1604
0
        return false;
1605
1606
0
    Reference< XPropertySet > xControlSet( pControl->GetUnoControlModel(), UNO_QUERY );
1607
0
    if ( !xControlSet.is() )
1608
0
        return false;
1609
1610
    // size of the control
1611
0
    ::Size aControlSize( aDefSize );
1612
0
    switch ( nDataType )
1613
0
    {
1614
0
    case DataType::BIT:
1615
0
    case DataType::BOOLEAN:
1616
0
        aControlSize = aDefSize;
1617
0
        break;
1618
0
    case DataType::LONGVARCHAR:
1619
0
    case DataType::CLOB:
1620
0
    case DataType::LONGVARBINARY:
1621
0
    case DataType::BLOB:
1622
0
        aControlSize = aDefImageSize;
1623
0
        break;
1624
0
    }
1625
1626
0
    if ( SdrObjKind::FormImageControl == _nControlObjectID )
1627
0
        aControlSize = aDefImageSize;
1628
1629
0
    aControlSize.setWidth( tools::Long(Fraction(aControlSize.Width(), 1) * eTargetMode.GetScaleX()) );
1630
0
    aControlSize.setHeight( tools::Long(Fraction(aControlSize.Height(), 1) * eTargetMode.GetScaleY()) );
1631
1632
0
    pControl->SetLogicRect( ::tools::Rectangle(
1633
0
        OutputDevice::LogicToLogic( ::Point( aRealSize.Width() + _nXOffsetMM, _nYOffsetMM ), eSourceMode, eTargetMode ),
1634
0
        OutputDevice::LogicToLogic( aControlSize, eSourceMode, eTargetMode )
1635
0
    ) );
1636
1637
    // some initializations
1638
0
    Reference< XPropertySetInfo > xControlPropInfo = xControlSet->getPropertySetInfo();
1639
1640
0
    if ( aFieldName.hasValue() )
1641
0
    {
1642
0
        xControlSet->setPropertyValue( FM_PROP_CONTROLSOURCE, aFieldName );
1643
0
        xControlSet->setPropertyValue( FM_PROP_NAME, aFieldName );
1644
0
        if ( !bNeedLabel )
1645
0
        {
1646
            // no dedicated label control => use the label property
1647
0
            if ( xControlPropInfo->hasPropertyByName( FM_PROP_LABEL ) )
1648
0
                xControlSet->setPropertyValue( FM_PROP_LABEL, Any( sFieldName + _rFieldPostfix ) );
1649
0
            else
1650
0
                OSL_FAIL( "FmXFormView::createControlLabelPair: can't set a label for the control!" );
1651
0
        }
1652
0
    }
1653
1654
0
    if ( (nDataType == DataType::LONGVARCHAR || nDataType == DataType::CLOB) && xControlPropInfo->hasPropertyByName( FM_PROP_MULTILINE ) )
1655
0
    {
1656
0
        xControlSet->setPropertyValue( FM_PROP_MULTILINE, Any( true ) );
1657
0
    }
1658
1659
    // announce the label to the control
1660
0
    if ( xControlPropInfo->hasPropertyByName( FM_PROP_CONTROLLABEL ) && xLabelModel.is() )
1661
0
    {
1662
0
        try
1663
0
        {
1664
0
            xControlSet->setPropertyValue( FM_PROP_CONTROLLABEL, Any( xLabelModel ) );
1665
0
        }
1666
0
        catch (const Exception&)
1667
0
        {
1668
0
            DBG_UNHANDLED_EXCEPTION("svx");
1669
0
        }
1670
0
    }
1671
1672
0
    if ( _rxField.is() )
1673
0
    {
1674
0
        FormControlFactory::initializeFieldDependentProperties( _rxField, xControlSet, _rxNumberFormats );
1675
0
    }
1676
1677
0
    _rpLabel = std::move(pLabel);
1678
0
    _rpControl = std::move(pControl);
1679
0
    return true;
1680
0
}
1681
1682
1683
FmXFormView::ObjectRemoveListener::ObjectRemoveListener( FmXFormView* pParent )
1684
13
    :m_pParent( pParent )
1685
13
{
1686
13
}
1687
1688
1689
void FmXFormView::ObjectRemoveListener::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint )
1690
0
{
1691
0
    if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
1692
0
        return;
1693
0
    const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
1694
0
    if (pSdrHint->GetKind() == SdrHintKind::ObjectRemoved)
1695
0
        m_pParent->ObjectRemovedInAliveMode(pSdrHint->GetObject());
1696
0
}
1697
1698
1699
void FmXFormView::ObjectRemovedInAliveMode( const SdrObject* pObject )
1700
0
{
1701
    // if the remote object in my MarkList, which I have memorized when switching to the
1702
    // Alive mode, I have to take it out now, because I otherwise try to set the mark
1703
    // again when switching back (interestingly, this fails only with grouped objects
1704
    // (when accessing their ObjList GPF), not with individual ones)
1705
1706
0
    const size_t nCount = m_aMark.GetMarkCount();
1707
0
    for (size_t i = 0; i < nCount; ++i)
1708
0
    {
1709
0
        SdrMark* pMark = m_aMark.GetMark(i);
1710
0
        SdrObject* pCurrent = pMark->GetMarkedSdrObj();
1711
0
        if (pObject == pCurrent)
1712
0
        {
1713
0
            m_aMark.DeleteMark(i);
1714
0
            return;
1715
0
        }
1716
        // I do not need to descend into GroupObjects: if an object is deleted there,
1717
        // then the pointer, which I have, to the GroupObject still remains valid ...
1718
0
    }
1719
0
}
1720
1721
1722
void FmXFormView::stopMarkListWatching()
1723
4.56k
{
1724
4.56k
    if ( m_pWatchStoredList )
1725
0
    {
1726
0
        m_pWatchStoredList->EndListeningAll();
1727
0
        m_pWatchStoredList.reset();
1728
0
    }
1729
4.56k
}
1730
1731
1732
void FmXFormView::startMarkListWatching()
1733
13
{
1734
13
    if ( !m_pWatchStoredList )
1735
13
    {
1736
13
        FmFormModel* pModel = GetFormShell() ? GetFormShell()->GetFormModel() : nullptr;
1737
13
        DBG_ASSERT( pModel != nullptr, "FmXFormView::startMarkListWatching: shell has no model!" );
1738
13
        if (pModel)
1739
13
        {
1740
13
            m_pWatchStoredList.reset(new ObjectRemoveListener( this ));
1741
13
            m_pWatchStoredList->StartListening( *static_cast< SfxBroadcaster* >( pModel ) );
1742
13
        }
1743
13
    }
1744
0
    else
1745
0
    {
1746
0
        OSL_FAIL( "FmXFormView::startMarkListWatching: already listening!" );
1747
0
    }
1748
13
}
1749
1750
void FmXFormView::saveMarkList()
1751
13
{
1752
13
    if ( m_pView )
1753
13
    {
1754
13
        m_aMark = m_pView->GetMarkedObjectList();
1755
13
        const size_t nCount = m_aMark.GetMarkCount( );
1756
13
        for ( size_t i = 0; i < nCount; ++i )
1757
0
        {
1758
0
            SdrMark*   pMark = m_aMark.GetMark(i);
1759
0
            SdrObject* pObj  = pMark->GetMarkedSdrObj();
1760
1761
0
            if ( m_pView->IsObjMarked( pObj ) )
1762
0
            {
1763
0
                if ( pObj->IsGroupObject() )
1764
0
                {
1765
0
                    SdrObjListIter aIter( pObj->GetSubList() );
1766
0
                    bool bMixed = false;
1767
0
                    while ( aIter.IsMore() && !bMixed )
1768
0
                        bMixed = ( aIter.Next()->GetObjInventor() != SdrInventor::FmForm );
1769
1770
0
                    if ( !bMixed )
1771
0
                    {
1772
                        // all objects in the group are form objects
1773
0
                        m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), true /* unmark! */ );
1774
0
                    }
1775
0
                }
1776
0
                else
1777
0
                {
1778
0
                    if ( pObj->GetObjInventor() == SdrInventor::FmForm )
1779
0
                    {   // this is a form layer object
1780
0
                        m_pView->MarkObj( pMark->GetMarkedSdrObj(), pMark->GetPageView(), true /* unmark! */ );
1781
0
                    }
1782
0
                }
1783
0
            }
1784
0
        }
1785
13
    }
1786
0
    else
1787
0
    {
1788
0
        OSL_FAIL( "FmXFormView::saveMarkList: invalid view!" );
1789
0
        m_aMark.Clear();
1790
0
    }
1791
13
}
1792
1793
static bool lcl_hasObject( SdrObjListIter& rIter, SdrObject const * pObj )
1794
0
{
1795
0
    bool bFound = false;
1796
0
    while (rIter.IsMore() && !bFound)
1797
0
        bFound = pObj == rIter.Next();
1798
1799
0
    rIter.Reset();
1800
0
    return bFound;
1801
0
}
1802
1803
1804
void FmXFormView::restoreMarkList( SdrMarkList& _rRestoredMarkList )
1805
4.56k
{
1806
4.56k
    if ( !m_pView )
1807
0
        return;
1808
1809
4.56k
    _rRestoredMarkList.Clear();
1810
1811
4.56k
    const SdrMarkList& rCurrentList = m_pView->GetMarkedObjectList();
1812
4.56k
    FmFormPage* pPage = GetFormShell() ? GetFormShell()->GetCurPage() : nullptr;
1813
4.56k
    if (!pPage)
1814
0
        return;
1815
1816
4.56k
    if (rCurrentList.GetMarkCount())
1817
0
    {   // there is a current mark ... hmm. Is it a subset of the mark we remembered in saveMarkList?
1818
0
        bool bMisMatch = false;
1819
1820
        // loop through all current marks
1821
0
        const size_t nCurrentCount = rCurrentList.GetMarkCount();
1822
0
        for ( size_t i=0; i<nCurrentCount && !bMisMatch; ++i )
1823
0
        {
1824
0
            const SdrObject* pCurrentMarked = rCurrentList.GetMark( i )->GetMarkedSdrObj();
1825
1826
            // loop through all saved marks, check for equality
1827
0
            bool bFound = false;
1828
0
            const size_t nSavedCount = m_aMark.GetMarkCount();
1829
0
            for ( size_t j=0; j<nSavedCount && !bFound; ++j )
1830
0
            {
1831
0
                if ( m_aMark.GetMark( j )->GetMarkedSdrObj() == pCurrentMarked )
1832
0
                    bFound = true;
1833
0
            }
1834
1835
            // did not find a current mark in the saved marks
1836
0
            if ( !bFound )
1837
0
                bMisMatch = true;
1838
0
        }
1839
1840
0
        if ( bMisMatch )
1841
0
        {
1842
0
            m_aMark.Clear();
1843
0
            _rRestoredMarkList = rCurrentList;
1844
0
            return;
1845
0
        }
1846
0
    }
1847
    // it is important that the objects of the mark list are not accessed,
1848
    // because they can be already destroyed
1849
4.56k
    SdrPageView* pCurPageView = m_pView->GetSdrPageView();
1850
4.56k
    SdrObjListIter aPageIter( pPage );
1851
4.56k
    bool bFound = true;
1852
1853
    // do all objects still exist
1854
4.56k
    const size_t nCount = m_aMark.GetMarkCount();
1855
4.56k
    for (size_t i = 0; i < nCount && bFound; ++i)
1856
0
    {
1857
0
        SdrMark*   pMark = m_aMark.GetMark(i);
1858
0
        SdrObject* pObj  = pMark->GetMarkedSdrObj();
1859
0
        if (pObj->IsGroupObject())
1860
0
        {
1861
0
            SdrObjListIter aIter(pObj->GetSubList());
1862
0
            while (aIter.IsMore() && bFound)
1863
0
                bFound = lcl_hasObject(aPageIter, aIter.Next());
1864
0
        }
1865
0
        else
1866
0
            bFound = lcl_hasObject(aPageIter, pObj);
1867
1868
0
        bFound = bFound && pCurPageView == pMark->GetPageView();
1869
0
    }
1870
1871
4.56k
    if (bFound)
1872
4.56k
    {
1873
        // evaluate the LastObject
1874
4.56k
        if (nCount) // now mark the objects
1875
0
        {
1876
0
            for (size_t i = 0; i < nCount; ++i)
1877
0
            {
1878
0
                SdrMark* pMark = m_aMark.GetMark(i);
1879
0
                SdrObject* pObj = pMark->GetMarkedSdrObj();
1880
0
                if ( pObj->GetObjInventor() == SdrInventor::FmForm )
1881
0
                    if ( !m_pView->IsObjMarked( pObj ) )
1882
0
                        m_pView->MarkObj( pObj, pMark->GetPageView() );
1883
0
            }
1884
1885
0
            _rRestoredMarkList = m_aMark;
1886
0
        }
1887
4.56k
    }
1888
4.56k
    m_aMark.Clear();
1889
4.56k
}
1890
1891
void SAL_CALL FmXFormView::focusGained( const FocusEvent& /*e*/ )
1892
0
{
1893
0
    if ( m_xWindow.is() && m_pView )
1894
0
    {
1895
0
        m_pView->SetMoveOutside( true, FmFormView::ImplAccess() );
1896
0
    }
1897
0
}
1898
1899
void SAL_CALL FmXFormView::focusLost( const FocusEvent& /*e*/ )
1900
0
{
1901
    // when switch the focus outside the office the mark didn't change
1902
    // so we can not remove us as focus listener
1903
0
    if ( m_xWindow.is() && m_pView )
1904
0
    {
1905
0
        m_pView->SetMoveOutside( false, FmFormView::ImplAccess() );
1906
0
    }
1907
0
}
1908
1909
DocumentType FmXFormView::impl_getDocumentType() const
1910
0
{
1911
0
    if ( GetFormShell() && GetFormShell()->GetImpl() )
1912
0
        return GetFormShell()->GetImpl()->getDocumentType_Lock();
1913
0
    return eUnknownDocumentType;
1914
0
}
1915
1916
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */