Coverage Report

Created: 2026-07-10 11:04

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