Coverage Report

Created: 2025-07-07 10:01

/src/libreoffice/svtools/source/dialogs/addresstemplate.cxx
Line
Count
Source (jump to first uncovered line)
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 <svtools/addresstemplate.hxx>
23
#include <svtools/strings.hrc>
24
#include <svtools/svtresid.hxx>
25
#include <tools/debug.hxx>
26
#include <comphelper/interaction.hxx>
27
#include <comphelper/propertyvalue.hxx>
28
#include <comphelper/string.hxx>
29
#include <unotools/configitem.hxx>
30
#include <utility>
31
#include <vcl/stdtext.hxx>
32
#include <vcl/svapp.hxx>
33
#include <vcl/weld.hxx>
34
#include <sal/log.hxx>
35
#include <comphelper/diagnose_ex.hxx>
36
#include <osl/diagnose.h>
37
#include <com/sun/star/util/AliasProgrammaticPair.hpp>
38
#include <com/sun/star/ui/dialogs/AddressBookSourcePilot.hpp>
39
#include <com/sun/star/beans/PropertyValue.hpp>
40
#include <com/sun/star/beans/XPropertySet.hpp>
41
#include <com/sun/star/sdb/DatabaseContext.hpp>
42
#include <com/sun/star/sdb/XCompletedConnection.hpp>
43
#include <com/sun/star/sdb/SQLContext.hpp>
44
#include <com/sun/star/sdbc/SQLWarning.hpp>
45
#include <com/sun/star/sdbc/XConnection.hpp>
46
#include <com/sun/star/sdbc/XDataSource.hpp>
47
#include <com/sun/star/task/InteractionHandler.hpp>
48
#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
49
#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
50
#include <svl/filenotation.hxx>
51
#include <tools/urlobj.hxx>
52
#include <algorithm>
53
#include <map>
54
#include <set>
55
#include <array>
56
#include <strings.hxx>
57
58
59
namespace svt
60
{
61
    using namespace ::com::sun::star::uno;
62
    using namespace ::com::sun::star::container;
63
    using namespace ::com::sun::star::ui::dialogs;
64
    using namespace ::com::sun::star::util;
65
    using namespace ::com::sun::star::beans;
66
    using namespace ::com::sun::star::sdb;
67
    using namespace ::com::sun::star::sdbc;
68
    using namespace ::com::sun::star::sdbcx;
69
    using namespace ::com::sun::star::task;
70
    using namespace ::comphelper;
71
    using namespace ::utl;
72
73
    typedef std::set<OUString> StringBag;
74
    typedef std::map<OUString, OUString> MapString2String;
75
76
    namespace
77
    {
78
        OUString lcl_getSelectedDataSource( const weld::ComboBox& dataSourceCombo )
79
0
        {
80
0
            OUString selectedDataSource = dataSourceCombo.get_active_text();
81
0
            if (dataSourceCombo.find_text(selectedDataSource) == -1)
82
0
            {
83
                // none of the pre-selected entries -> assume a path to a database document
84
0
                OFileNotation aFileNotation( selectedDataSource, OFileNotation::N_SYSTEM );
85
0
                selectedDataSource = aFileNotation.get( OFileNotation::N_URL );
86
0
            }
87
0
            return selectedDataSource;
88
0
        }
89
90
    // = IAssignmentData
91
92
    class IAssignmentData
93
    {
94
    public:
95
        virtual ~IAssignmentData();
96
97
        /// the data source to use for the address book
98
        virtual OUString getDatasourceName() const = 0;
99
100
        /// the command to use for the address book
101
        virtual OUString getCommand() const = 0;
102
103
        /// checks whether or not there is an assignment for a given logical field
104
        virtual bool        hasFieldAssignment(const OUString& _rLogicalName) = 0;
105
        /// retrieves the assignment for a given logical field
106
        virtual OUString getFieldAssignment(const OUString& _rLogicalName) = 0;
107
108
        /// set the assignment for a given logical field
109
        virtual void            setFieldAssignment(const OUString& _rLogicalName, const OUString& _rAssignment) = 0;
110
111
        virtual void    setDatasourceName(const OUString& _rName) = 0;
112
        virtual void    setCommand(const OUString& _rCommand) = 0;
113
    };
114
115
    }
116
117
    IAssignmentData::~IAssignmentData()
118
0
    {
119
0
    }
120
121
122
    // = AssignmentTransientData
123
124
    namespace {
125
126
    class AssignmentTransientData : public IAssignmentData
127
    {
128
    protected:
129
        OUString             m_sDSName;
130
        OUString             m_sTableName;
131
        MapString2String     m_aAliases;
132
133
    public:
134
        AssignmentTransientData(
135
            OUString _aDataSourceName,
136
            OUString _aTableName,
137
            const Sequence< AliasProgrammaticPair >& _rFields
138
        );
139
140
        // IAssignmentData overridables
141
        virtual OUString getDatasourceName() const override;
142
        virtual OUString getCommand() const override;
143
144
        virtual bool     hasFieldAssignment(const OUString& _rLogicalName) override;
145
        virtual OUString getFieldAssignment(const OUString& _rLogicalName) override;
146
        virtual void     setFieldAssignment(const OUString& _rLogicalName, const OUString& _rAssignment) override;
147
148
        virtual void    setDatasourceName(const OUString& _rName) override;
149
        virtual void    setCommand(const OUString& _rCommand) override;
150
    };
151
152
    }
153
154
    AssignmentTransientData::AssignmentTransientData(
155
            OUString _aDataSourceName, OUString _aTableName,
156
            const Sequence< AliasProgrammaticPair >& _rFields )
157
0
        :m_sDSName(std::move( _aDataSourceName ))
158
0
        ,m_sTableName(std::move( _aTableName ))
159
0
    {
160
        // fill our aliases structure
161
        // first collect all known programmatic names
162
0
        StringBag aKnownNames;
163
164
0
        OUString const sLogicalFieldNames(STR_LOGICAL_FIELD_NAMES);
165
0
        sal_Int32 nIndex = 0;
166
0
        do
167
0
        {
168
0
            OUString aToken = sLogicalFieldNames.getToken(0, ';', nIndex);
169
0
            aKnownNames.insert(aToken);
170
0
        }
171
0
        while ( nIndex >= 0);
172
173
        // loop through the given names
174
0
        for (const AliasProgrammaticPair& rField : _rFields)
175
0
        {
176
0
            if ( aKnownNames.end() != aKnownNames.find( rField.ProgrammaticName ) )
177
0
            {
178
0
                m_aAliases[ rField.ProgrammaticName ] = rField.Alias;
179
0
            }
180
0
            else
181
0
            {
182
0
                SAL_WARN( "svtools", "AssignmentTransientData::AssignmentTransientData: unknown programmatic name: "
183
0
                          << rField.ProgrammaticName );
184
0
            }
185
0
        }
186
0
    }
187
188
189
    OUString AssignmentTransientData::getDatasourceName() const
190
0
    {
191
0
        return m_sDSName;
192
0
    }
193
194
195
    OUString AssignmentTransientData::getCommand() const
196
0
    {
197
0
        return m_sTableName;
198
0
    }
199
200
201
    bool AssignmentTransientData::hasFieldAssignment(const OUString& _rLogicalName)
202
0
    {
203
0
        MapString2String::const_iterator aPos = m_aAliases.find( _rLogicalName );
204
0
        return  ( m_aAliases.end() != aPos )
205
0
            &&  ( !aPos->second.isEmpty() );
206
0
    }
207
208
209
    OUString AssignmentTransientData::getFieldAssignment(const OUString& _rLogicalName)
210
0
    {
211
0
        OUString sReturn;
212
0
        MapString2String::const_iterator aPos = m_aAliases.find( _rLogicalName );
213
0
        if ( m_aAliases.end() != aPos )
214
0
            sReturn = aPos->second;
215
216
0
        return sReturn;
217
0
    }
218
219
220
    void AssignmentTransientData::setFieldAssignment(const OUString& _rLogicalName, const OUString& _rAssignment)
221
0
    {
222
0
        m_aAliases[ _rLogicalName ] = _rAssignment;
223
0
    }
224
225
226
    void AssignmentTransientData::setDatasourceName(const OUString&)
227
0
    {
228
0
        OSL_FAIL( "AssignmentTransientData::setDatasourceName: cannot be implemented for transient data!" );
229
0
    }
230
231
232
    void AssignmentTransientData::setCommand(const OUString&)
233
0
    {
234
0
        OSL_FAIL( "AssignmentTransientData::setCommand: cannot be implemented for transient data!" );
235
0
    }
236
237
238
    // = AssignmentPersistentData
239
240
    namespace {
241
242
    class AssignmentPersistentData
243
            :public ::utl::ConfigItem
244
            ,public IAssignmentData
245
    {
246
    protected:
247
        StringBag       m_aStoredFields;
248
249
    protected:
250
        css::uno::Any   getProperty(const OUString& _rLocalName) const;
251
252
        OUString        getStringProperty(const OUString& _rLocalName) const;
253
254
        void            setStringProperty(const OUString& _pLocalName, const OUString& _rValue);
255
256
    public:
257
        AssignmentPersistentData();
258
259
        // IAssignmentData overridables
260
        virtual OUString getDatasourceName() const override;
261
        virtual OUString getCommand() const override;
262
263
        virtual bool     hasFieldAssignment(const OUString& _rLogicalName) override;
264
        virtual OUString getFieldAssignment(const OUString& _rLogicalName) override;
265
        virtual void     setFieldAssignment(const OUString& _rLogicalName, const OUString& _rAssignment) override;
266
267
        virtual void    setDatasourceName(const OUString& _rName) override;
268
        virtual void    setCommand(const OUString& _rCommand) override;
269
270
        virtual void    Notify( const css::uno::Sequence<OUString>& aPropertyNames) override;
271
272
    private:
273
        virtual void    ImplCommit() override;
274
        void            clearFieldAssignment(const OUString& _rLogicalName);
275
    };
276
277
    }
278
279
void AssignmentPersistentData::Notify( const css::uno::Sequence<OUString>& )
280
0
{
281
0
}
282
283
void AssignmentPersistentData::ImplCommit()
284
0
{
285
0
}
286
287
288
    AssignmentPersistentData::AssignmentPersistentData()
289
0
        :ConfigItem(u"Office.DataAccess/AddressBook"_ustr)
290
0
    {
291
0
        const Sequence< OUString > aStoredNames = GetNodeNames(u"Fields"_ustr);
292
0
        m_aStoredFields.insert(aStoredNames.begin(), aStoredNames.end());
293
0
    }
294
295
    bool AssignmentPersistentData::hasFieldAssignment(const OUString& _rLogicalName)
296
0
    {
297
0
        return (m_aStoredFields.end() != m_aStoredFields.find(_rLogicalName));
298
0
    }
299
300
301
    OUString AssignmentPersistentData::getFieldAssignment(const OUString& _rLogicalName)
302
0
    {
303
0
        OUString sAssignment;
304
0
        if (hasFieldAssignment(_rLogicalName))
305
0
        {
306
0
            OUString sFieldPath = "Fields/" + _rLogicalName + "/AssignedFieldName";
307
0
            sAssignment = getStringProperty(sFieldPath);
308
0
        }
309
0
        return sAssignment;
310
0
    }
311
312
313
    Any AssignmentPersistentData::getProperty(const OUString& _rLocalName) const
314
0
    {
315
0
        Sequence< OUString > aProperties(&_rLocalName, 1);
316
0
        Sequence< Any > aValues = const_cast<AssignmentPersistentData*>(this)->GetProperties(aProperties);
317
0
        DBG_ASSERT(aValues.getLength() == 1, "AssignmentPersistentData::getProperty: invalid sequence length!");
318
0
        return aValues[0];
319
0
    }
320
321
322
    OUString AssignmentPersistentData::getStringProperty(const OUString& _rLocalName) const
323
0
    {
324
0
        OUString sReturn;
325
0
        getProperty( _rLocalName ) >>= sReturn;
326
0
        return sReturn;
327
0
    }
328
329
330
    void AssignmentPersistentData::setStringProperty(const OUString& _pLocalName, const OUString& _rValue)
331
0
    {
332
0
        Sequence< OUString > aNames { _pLocalName };
333
0
        Sequence< Any > aValues{ Any(_rValue) };
334
0
        PutProperties(aNames, aValues);
335
0
    }
336
337
338
    void AssignmentPersistentData::setFieldAssignment(const OUString& _rLogicalName, const OUString& _rAssignment)
339
0
    {
340
0
        if (_rAssignment.isEmpty())
341
0
        {
342
0
            if (hasFieldAssignment(_rLogicalName))
343
0
            {
344
                // the assignment exists but it should be reset
345
0
                clearFieldAssignment(_rLogicalName);
346
0
            }
347
0
            return;
348
0
        }
349
350
        // Fields
351
0
        OUString sDescriptionNodePath(u"Fields"_ustr);
352
353
        // Fields/<field>
354
0
        OUString sFieldElementNodePath = sDescriptionNodePath + "/" + _rLogicalName;
355
356
0
        Sequence< PropertyValue > aNewFieldDescription{
357
            // Fields/<field>/ProgrammaticFieldName
358
0
            comphelper::makePropertyValue(sFieldElementNodePath + "/ProgrammaticFieldName",
359
0
                                          _rLogicalName),
360
            // Fields/<field>/AssignedFieldName
361
0
            comphelper::makePropertyValue(sFieldElementNodePath + "/AssignedFieldName",
362
0
                                          _rAssignment)
363
0
        };
364
365
        // just set the new value
366
0
        bool bSuccess =
367
0
            SetSetProperties(sDescriptionNodePath, aNewFieldDescription);
368
0
        DBG_ASSERT(bSuccess, "AssignmentPersistentData::setFieldAssignment: could not commit the changes a field!");
369
0
    }
370
371
372
    void AssignmentPersistentData::clearFieldAssignment(const OUString& _rLogicalName)
373
0
    {
374
0
        if (!hasFieldAssignment(_rLogicalName))
375
            // nothing to do
376
0
            return;
377
378
0
        Sequence< OUString > aNames(&_rLogicalName, 1);
379
0
        ClearNodeElements(u"Fields"_ustr, aNames);
380
0
    }
381
382
383
    OUString AssignmentPersistentData::getDatasourceName() const
384
0
    {
385
0
        return getStringProperty( u"DataSourceName"_ustr );
386
0
    }
387
388
389
    OUString AssignmentPersistentData::getCommand() const
390
0
    {
391
0
        return getStringProperty( u"Command"_ustr );
392
0
    }
393
394
395
    void AssignmentPersistentData::setDatasourceName(const OUString& _rName)
396
0
    {
397
0
        setStringProperty( u"DataSourceName"_ustr, _rName );
398
0
    }
399
400
401
    void AssignmentPersistentData::setCommand(const OUString& _rCommand)
402
0
    {
403
0
        setStringProperty( u"Command"_ustr, _rCommand );
404
0
    }
405
406
407
    // = AddressBookSourceDialogData
408
409
    struct AddressBookSourceDialogData
410
    {
411
        std::array<std::unique_ptr<weld::Label>, FIELD_PAIRS_VISIBLE*2> pFieldLabels;
412
        std::array<std::unique_ptr<weld::ComboBox>, FIELD_PAIRS_VISIBLE*2> pFields;
413
414
        /// when working transient, we need the data source
415
        Reference< XDataSource >
416
                        m_xTransientDataSource;
417
        /// current scroll pos in the field list
418
        sal_Int32       nFieldScrollPos;
419
        /// indicates that we've an odd field number. This member is for efficiency only, it's redundant.
420
        bool        bOddFieldNumber : 1;
421
        /// indicates that we're working with the real persistent configuration
422
        bool        bWorkingPersistent : 1;
423
424
        /// the strings to use as labels for the field selection listboxes
425
        std::vector<OUString>     aFieldLabels;
426
        // the current field assignment
427
        std::vector<OUString>     aFieldAssignments;
428
        /// the logical field names
429
        std::vector<OUString>     aLogicalFieldNames;
430
431
        std::unique_ptr<IAssignmentData> pConfigData;
432
433
434
        AddressBookSourceDialogData( )
435
0
            :pFieldLabels{{nullptr}}
436
0
            ,pFields{{nullptr}}
437
0
            ,nFieldScrollPos(0)
438
0
            ,bOddFieldNumber(false)
439
0
            ,bWorkingPersistent( true )
440
0
            ,pConfigData( new AssignmentPersistentData )
441
0
        {
442
0
        }
443
444
        AddressBookSourceDialogData( const Reference< XDataSource >& _rxTransientDS, const OUString& _rDataSourceName,
445
            const OUString& _rTableName, const Sequence< AliasProgrammaticPair >& _rFields )
446
0
            :pFieldLabels{{nullptr}}
447
0
            ,pFields{{nullptr}}
448
0
            ,m_xTransientDataSource( _rxTransientDS )
449
0
            ,nFieldScrollPos(0)
450
0
            ,bOddFieldNumber(false)
451
0
            ,bWorkingPersistent( false )
452
0
            ,pConfigData( new AssignmentTransientData( _rDataSourceName, _rTableName, _rFields ) )
453
0
        {
454
0
        }
455
456
        // Copy assignment is forbidden and not implemented.
457
        AddressBookSourceDialogData (const AddressBookSourceDialogData &) = delete;
458
        AddressBookSourceDialogData & operator= (const AddressBookSourceDialogData &) = delete;
459
    };
460
461
    // = AddressBookSourceDialog
462
    AddressBookSourceDialog::AddressBookSourceDialog(weld::Window* pParent,
463
            const Reference< XComponentContext >& _rxORB )
464
0
        : GenericDialogController(pParent, u"svt/ui/addresstemplatedialog.ui"_ustr, u"AddressTemplateDialog"_ustr)
465
0
        , m_sNoFieldSelection(SvtResId(STR_NO_FIELD_SELECTION))
466
0
        , m_xORB(_rxORB)
467
0
        , m_pImpl( new AddressBookSourceDialogData )
468
0
    {
469
0
        implConstruct();
470
0
    }
471
472
    AddressBookSourceDialog::AddressBookSourceDialog(weld::Window* pParent, const Reference< XComponentContext >& _rxORB,
473
        const Reference< XDataSource >& _rxTransientDS, const OUString& _rDataSourceName,
474
        const OUString& _rTable, const Sequence< AliasProgrammaticPair >& _rMapping )
475
0
        : GenericDialogController(pParent, u"svt/ui/addresstemplatedialog.ui"_ustr, u"AddressTemplateDialog"_ustr)
476
0
        , m_sNoFieldSelection(SvtResId(STR_NO_FIELD_SELECTION))
477
0
        , m_xORB(_rxORB)
478
0
        , m_pImpl( new AddressBookSourceDialogData( _rxTransientDS, _rDataSourceName, _rTable, _rMapping ) )
479
0
    {
480
0
        implConstruct();
481
0
    }
482
483
    void AddressBookSourceDialog::implConstruct()
484
0
    {
485
0
        m_xOKButton = m_xBuilder->weld_button(u"ok"_ustr);
486
0
        m_xDatasource = m_xBuilder->weld_combo_box(u"datasource"_ustr);
487
0
        m_xAdministrateDatasources = m_xBuilder->weld_button(u"admin"_ustr);
488
0
        m_xTable = m_xBuilder->weld_combo_box(u"datatable"_ustr);
489
0
        m_xFieldScroller = m_xBuilder->weld_scrolled_window(u"scrollwindow"_ustr, true);
490
0
        m_xGrid = m_xBuilder->weld_widget(u"grid"_ustr);
491
492
0
        for (sal_Int32 row=0; row<FIELD_PAIRS_VISIBLE; ++row)
493
0
        {
494
0
            for (sal_Int32 column=0; column<2; ++column)
495
0
            {
496
                // the label
497
0
                m_pImpl->pFieldLabels[row * 2 + column] = m_xBuilder->weld_label("label" + OUString::number(row * 2 + column));
498
                // the listbox
499
0
                m_pImpl->pFields[row * 2 + column] = m_xBuilder->weld_combo_box("box" + OUString::number(row * 2 + column));
500
0
                m_pImpl->pFields[row * 2 + column]->connect_changed(LINK(this, AddressBookSourceDialog, OnFieldSelect));
501
0
            }
502
0
        }
503
504
0
        initializeDatasources();
505
506
        // for the moment, we have a hard coded list of all known fields.
507
        // A better solution would be to store all known field translations in the configuration, which could be
508
        // extensible by the user in an arbitrary way.
509
        // But for the moment we need a quick solution ...
510
        // (the main thing would be to store the translations to use here in the user interface, besides that, the code
511
        // should be adjustable with a rather small effort.)
512
513
        // initialize the strings for the field labels
514
0
        m_pImpl->aFieldLabels = {
515
0
            SvtResId(STR_FIELD_FIRSTNAME),
516
0
            SvtResId(STR_FIELD_LASTNAME),
517
0
            SvtResId(STR_FIELD_COMPANY),
518
0
            SvtResId(STR_FIELD_DEPARTMENT),
519
0
            SvtResId(STR_FIELD_STREET),
520
0
            SvtResId(STR_FIELD_ZIPCODE),
521
0
            SvtResId(STR_FIELD_CITY),
522
0
            SvtResId(STR_FIELD_STATE),
523
0
            SvtResId(STR_FIELD_COUNTRY),
524
0
            SvtResId(STR_FIELD_HOMETEL),
525
0
            SvtResId(STR_FIELD_WORKTEL),
526
0
            SvtResId(STR_FIELD_OFFICETEL),
527
0
            SvtResId(STR_FIELD_MOBILE),
528
0
            SvtResId(STR_FIELD_TELOTHER),
529
0
            SvtResId(STR_FIELD_PAGER),
530
0
            SvtResId(STR_FIELD_FAX),
531
0
            SvtResId(STR_FIELD_EMAIL),
532
0
            SvtResId(STR_FIELD_URL),
533
0
            SvtResId(STR_FIELD_TITLE ),
534
0
            SvtResId(STR_FIELD_POSITION),
535
0
            SvtResId(STR_FIELD_INITIALS),
536
0
            SvtResId(STR_FIELD_ADDRFORM),
537
0
            SvtResId(STR_FIELD_SALUTATION),
538
0
            SvtResId(STR_FIELD_ID),
539
0
            SvtResId(STR_FIELD_CALENDAR),
540
0
            SvtResId(STR_FIELD_INVITE),
541
0
            SvtResId(STR_FIELD_NOTE),
542
0
            SvtResId(STR_FIELD_USER1),
543
0
            SvtResId(STR_FIELD_USER2),
544
0
            SvtResId(STR_FIELD_USER3),
545
0
            SvtResId(STR_FIELD_USER4)
546
0
        };
547
548
0
        tools::Long nLabelWidth = 0;
549
0
        tools::Long nListBoxWidth = m_pImpl->pFields[0]->get_approximate_digit_width() * 18;
550
0
        for (auto const& fieldLabel : m_pImpl->aFieldLabels)
551
0
        {
552
0
            m_pImpl->pFieldLabels[0]->set_label(fieldLabel);
553
0
            nLabelWidth = std::max(nLabelWidth, m_pImpl->pFieldLabels[0]->get_preferred_size().Width());
554
0
        }
555
0
        for (sal_Int32 row=0; row<FIELD_PAIRS_VISIBLE; ++row)
556
0
        {
557
0
            for (sal_Int32 column=0; column<2; ++column)
558
0
            {
559
0
                m_pImpl->pFieldLabels[row * 2 + column]->set_size_request(nLabelWidth, -1);
560
0
                m_pImpl->pFields[row * 2 + column]->set_size_request(nListBoxWidth, -1);
561
0
            }
562
0
        }
563
564
        // force an even number of known fields
565
0
        m_pImpl->bOddFieldNumber = (m_pImpl->aFieldLabels.size() % 2) != 0;
566
0
        if (m_pImpl->bOddFieldNumber)
567
0
            m_pImpl->aFieldLabels.emplace_back();
568
569
        // limit the scrollbar range accordingly
570
0
        sal_Int32 nOverallFieldPairs = m_pImpl->aFieldLabels.size() / 2;
571
0
        m_xFieldScroller->vadjustment_configure(0, 0, nOverallFieldPairs,
572
0
                                                1, FIELD_PAIRS_VISIBLE - 1, FIELD_PAIRS_VISIBLE);
573
574
        // reset the current field assignments
575
0
        m_pImpl->aFieldAssignments.resize(m_pImpl->aFieldLabels.size());
576
        // (empty strings mean "no assignment")
577
578
        // some knittings
579
0
        m_xFieldScroller->connect_vadjustment_changed(LINK(this, AddressBookSourceDialog, OnFieldScroll));
580
0
        m_xAdministrateDatasources->connect_clicked(LINK(this, AddressBookSourceDialog, OnAdministrateDatasources));
581
0
        m_xDatasource->set_entry_completion(true);
582
0
        m_xTable->set_entry_completion(true);
583
0
        m_xTable->connect_focus_in(LINK(this, AddressBookSourceDialog, OnComboGetFocus));
584
0
        m_xDatasource->connect_focus_in(LINK(this, AddressBookSourceDialog, OnComboGetFocus));
585
0
        m_xTable->connect_focus_out(LINK(this, AddressBookSourceDialog, OnComboLoseFocus));
586
0
        m_xDatasource->connect_focus_out(LINK(this, AddressBookSourceDialog, OnComboLoseFocus));
587
0
        m_xTable->connect_changed(LINK(this, AddressBookSourceDialog, OnComboSelect));
588
0
        m_xDatasource->connect_changed(LINK(this, AddressBookSourceDialog, OnComboSelect));
589
0
        m_xOKButton->connect_clicked(LINK(this, AddressBookSourceDialog, OnOkClicked));
590
591
        // initialize the field controls
592
0
        resetFields();
593
        // tdf#136494 wait until contents are filled before getting preferred height
594
0
        m_xFieldScroller->set_size_request(-1, m_xGrid->get_preferred_size().Height());
595
0
        m_xFieldScroller->vadjustment_set_value(0);
596
0
        m_pImpl->nFieldScrollPos = -1;
597
0
        implScrollFields(0, false, false);
598
599
        // the logical names
600
0
        OUString sLogicalFieldNames(STR_LOGICAL_FIELD_NAMES);
601
0
        sal_Int32 nAdjustedTokenCount = comphelper::string::getTokenCount(sLogicalFieldNames, ';') + (m_pImpl->bOddFieldNumber ? 1 : 0);
602
0
        DBG_ASSERT(nAdjustedTokenCount == static_cast<sal_Int32>(m_pImpl->aFieldLabels.size()),
603
0
            "AddressBookSourceDialog::AddressBookSourceDialog: inconsistence between logical and UI field names!");
604
0
        m_pImpl->aLogicalFieldNames.reserve(nAdjustedTokenCount);
605
0
        sal_Int32 nIdx{ 0 };
606
0
        for (sal_Int32 i = 0; i<nAdjustedTokenCount; ++i)
607
0
            m_pImpl->aLogicalFieldNames.push_back(sLogicalFieldNames.getToken(0, ';', nIdx));
608
609
        // load the initial data from the configuration
610
0
        loadConfiguration();
611
0
        resetTables();
612
            // will reset the tables/fields implicitly
613
614
0
        if ( !m_pImpl->bWorkingPersistent )
615
0
            if ( m_pImpl->pFields[0] )
616
0
                m_pImpl->pFields[0]->grab_focus();
617
618
0
        if (m_pImpl->bWorkingPersistent)
619
0
            return;
620
621
0
        m_xAdministrateDatasources->hide();
622
0
    }
623
624
    void AddressBookSourceDialog::getFieldMapping(Sequence< AliasProgrammaticPair >& _rMapping) const
625
0
    {
626
0
        _rMapping.realloc( m_pImpl->aLogicalFieldNames.size() );
627
0
        AliasProgrammaticPair* pPair = _rMapping.getArray();
628
629
0
        for (auto const& logicalFieldName : m_pImpl->aLogicalFieldNames)
630
0
        {
631
0
            if ( m_pImpl->pConfigData->hasFieldAssignment(logicalFieldName) )
632
0
            {
633
                // the user gave us an assignment for this field
634
0
                pPair->ProgrammaticName = logicalFieldName;
635
0
                pPair->Alias = m_pImpl->pConfigData->getFieldAssignment(logicalFieldName);
636
0
                ++pPair;
637
0
            }
638
0
        }
639
640
0
        _rMapping.realloc( pPair - _rMapping.getArray() );
641
0
    }
642
643
    void AddressBookSourceDialog::loadConfiguration()
644
0
    {
645
0
        OUString sName = m_pImpl->pConfigData->getDatasourceName();
646
0
        INetURLObject aURL( sName );
647
0
        if( aURL.GetProtocol() != INetProtocol::NotValid )
648
0
        {
649
0
            OFileNotation aFileNotation( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
650
0
            sName = aFileNotation.get(OFileNotation::N_SYSTEM);
651
0
        }
652
653
0
        m_xDatasource->set_entry_text(sName);
654
0
        m_xTable->set_entry_text(m_pImpl->pConfigData->getCommand());
655
        // we ignore the CommandType: only tables are supported
656
657
        // the logical names for the fields
658
        // AddressBookSourceDialog::loadConfiguration: inconsistence between field names and field assignments!
659
0
        assert(m_pImpl->aLogicalFieldNames.size() == m_pImpl->aFieldAssignments.size());
660
661
0
        auto aAssignment = m_pImpl->aFieldAssignments.begin();
662
0
        for (auto const& logicalFieldName : m_pImpl->aLogicalFieldNames)
663
0
        {
664
0
            *aAssignment = m_pImpl->pConfigData->getFieldAssignment(logicalFieldName);
665
0
            ++aAssignment;
666
0
        }
667
0
    }
668
669
    AddressBookSourceDialog::~AddressBookSourceDialog()
670
0
    {
671
0
    }
672
673
    void AddressBookSourceDialog::initializeDatasources()
674
0
    {
675
0
        if (!m_xDatabaseContext.is())
676
0
        {
677
0
            DBG_ASSERT(m_xORB.is(), "AddressBookSourceDialog::initializeDatasources: no service factory!");
678
0
            if (!m_xORB.is())
679
0
                return;
680
681
0
            try
682
0
            {
683
0
                m_xDatabaseContext = DatabaseContext::create(m_xORB);
684
0
            }
685
0
            catch(const Exception&) { }
686
0
            if (!m_xDatabaseContext.is())
687
0
            {
688
0
                ShowServiceNotAvailableError(m_xDialog.get(), u"com.sun.star.sdb.DatabaseContext", false);
689
0
                return;
690
0
            }
691
0
        }
692
0
        m_xDatasource->clear();
693
694
        // fill the datasources listbox
695
0
        try
696
0
        {
697
0
            const css::uno::Sequence<OUString> aElementNames = m_xDatabaseContext->getElementNames();
698
0
            for (const OUString& rDatasourceName : aElementNames)
699
0
                m_xDatasource->append_text(rDatasourceName);
700
0
        }
701
0
        catch(Exception&)
702
0
        {
703
0
            TOOLS_WARN_EXCEPTION( "svtools", "AddressBookSourceDialog::initializeDatasources: caught an exception while asking for the data source names!");
704
0
        }
705
0
    }
706
707
    IMPL_LINK(AddressBookSourceDialog, OnFieldScroll, weld::ScrolledWindow&, rScrollBar, void)
708
0
    {
709
0
        implScrollFields(rScrollBar.vadjustment_get_value(), true, true);
710
0
    }
711
712
    void AddressBookSourceDialog::resetTables()
713
0
    {
714
0
        if (!m_xDatabaseContext.is())
715
0
            return;
716
717
0
        weld::WaitObject aWaitCursor(m_xDialog.get());
718
719
        // no matter what we do here, we handled the currently selected data source (no matter if successful or not)
720
0
        m_xDatasource->save_value();
721
722
        // create an interaction handler (may be needed for connecting)
723
0
        Reference< XInteractionHandler > xHandler;
724
0
        try
725
0
        {
726
0
            xHandler.set(
727
0
                InteractionHandler::createWithParent(m_xORB, m_xDialog->GetXWindow()),
728
0
                UNO_QUERY_THROW );
729
0
        }
730
0
        catch(const Exception&) { }
731
0
        if (!xHandler.is())
732
0
        {
733
0
            ShowServiceNotAvailableError(m_xDialog.get(), u"com.sun.star.task.InteractionHandler", true);
734
0
            return;
735
0
        }
736
737
        // the currently selected table
738
0
        OUString sOldTable = m_xTable->get_active_text();
739
740
0
        m_xTable->clear();
741
742
0
        m_xCurrentDatasourceTables= nullptr;
743
744
        // get the tables of the connection
745
0
        Sequence< OUString > aTableNames;
746
0
        Any aException;
747
0
        try
748
0
        {
749
0
            Reference< XCompletedConnection > xDS;
750
0
            if ( m_pImpl->bWorkingPersistent )
751
0
            {
752
0
                OUString sSelectedDS = lcl_getSelectedDataSource(*m_xDatasource);
753
754
                // get the data source the user has chosen and let it build a connection
755
0
                INetURLObject aURL( sSelectedDS );
756
0
                if ( aURL.GetProtocol() != INetProtocol::NotValid || m_xDatabaseContext->hasByName(sSelectedDS) )
757
0
                    m_xDatabaseContext->getByName( sSelectedDS ) >>= xDS;
758
0
            }
759
0
            else
760
0
            {
761
0
                xDS.set(m_pImpl->m_xTransientDataSource, css::uno::UNO_QUERY);
762
0
            }
763
764
            // build the connection
765
0
            Reference< XConnection > xConn;
766
0
            if (xDS.is())
767
0
                xConn = xDS->connectWithCompletion(xHandler);
768
769
            // get the table names
770
0
            Reference< XTablesSupplier > xSupplTables(xConn, UNO_QUERY);
771
0
            if (xSupplTables.is())
772
0
            {
773
0
                m_xCurrentDatasourceTables = xSupplTables->getTables();
774
0
                if (m_xCurrentDatasourceTables.is())
775
0
                    aTableNames = m_xCurrentDatasourceTables->getElementNames();
776
0
            }
777
0
        }
778
0
        catch(const SQLContext& e) { aException <<= e; }
779
0
        catch(const SQLWarning& e) { aException <<= e; }
780
0
        catch(const SQLException& e) { aException <<= e; }
781
0
        catch(Exception&)
782
0
        {
783
0
            OSL_FAIL("AddressBookSourceDialog::resetTables: could not retrieve the table!");
784
0
        }
785
786
0
        if (aException.hasValue())
787
0
        {
788
0
            Reference< XInteractionRequest > xRequest = new OInteractionRequest(aException);
789
0
            try
790
0
            {
791
0
                xHandler->handle(xRequest);
792
0
            }
793
0
            catch(Exception&) { }
794
0
            return;
795
0
        }
796
797
0
        bool bKnowOldTable = false;
798
        // fill the table list
799
0
        for (const OUString& rTableName : aTableNames)
800
0
        {
801
0
            m_xTable->append_text(rTableName);
802
0
            if (rTableName == sOldTable)
803
0
                bKnowOldTable = true;
804
0
        }
805
806
        // set the old table, if the new data source knows a table with this name, too. Else reset the tables edit field.
807
0
        if (!bKnowOldTable)
808
0
            sOldTable.clear();
809
0
        m_xTable->set_entry_text(sOldTable);
810
811
0
        resetFields();
812
0
    }
813
814
    void AddressBookSourceDialog::resetFields()
815
0
    {
816
0
        weld::WaitObject aWaitCursor(m_xDialog.get());
817
818
        // no matter what we do here, we handled the currently selected table (no matter if successful or not)
819
0
        m_xDatasource->save_value();
820
821
0
        OUString sSelectedTable = m_xTable->get_active_text();
822
0
        Sequence< OUString > aColumnNames;
823
0
        try
824
0
        {
825
0
            if (m_xCurrentDatasourceTables.is())
826
0
            {
827
                // get the table and the columns
828
0
                Reference< XColumnsSupplier > xSuppTableCols;
829
0
                if (m_xCurrentDatasourceTables->hasByName(sSelectedTable))
830
0
                    xSuppTableCols.set(
831
0
                        m_xCurrentDatasourceTables->getByName(sSelectedTable),
832
0
                        css::uno::UNO_QUERY);
833
0
                Reference< XNameAccess > xColumns;
834
0
                if (xSuppTableCols.is())
835
0
                    xColumns = xSuppTableCols->getColumns();
836
0
                if (xColumns.is())
837
0
                    aColumnNames = xColumns->getElementNames();
838
0
            }
839
0
        }
840
0
        catch (const Exception&)
841
0
        {
842
0
            OSL_FAIL("AddressBookSourceDialog::resetFields: could not retrieve the table columns!");
843
0
        }
844
845
846
        // for quicker access
847
0
        ::std::set< OUString > aColumnNameSet(std::cbegin(aColumnNames), std::cend(aColumnNames));
848
849
0
        std::vector<OUString>::iterator aInitialSelection = m_pImpl->aFieldAssignments.begin() + m_pImpl->nFieldScrollPos;
850
851
0
        OUString sSaveSelection;
852
0
        for (sal_Int32 i=0; i<FIELD_CONTROLS_VISIBLE; ++i, ++aInitialSelection)
853
0
        {
854
0
            weld::ComboBox* pListbox = m_pImpl->pFields[i].get();
855
0
            sSaveSelection = pListbox->get_active_text();
856
857
0
            pListbox->clear();
858
859
            // the one entry for "no selection"
860
0
            pListbox->append_text(m_sNoFieldSelection);
861
            // as it's entry data, set the index of the list box in our array
862
0
            pListbox->set_id(0, OUString::number(i));
863
864
            // the field names
865
0
            for (const OUString& rColumnName : aColumnNames)
866
0
                pListbox->append_text(rColumnName);
867
868
0
            if (!aInitialSelection->isEmpty() && (aColumnNameSet.end() != aColumnNameSet.find(*aInitialSelection)))
869
                // we can select the entry as specified in our field assignment array
870
0
                pListbox->set_active_text(*aInitialSelection);
871
0
            else
872
                // try to restore the selection
873
0
                if (aColumnNameSet.end() != aColumnNameSet.find(sSaveSelection))
874
                    // the old selection is a valid column name
875
0
                    pListbox->set_active_text(sSaveSelection);
876
0
                else
877
                    // select the <none> entry
878
0
                    pListbox->set_active(0);
879
0
        }
880
881
        // adjust m_pImpl->aFieldAssignments
882
0
        for (auto & fieldAssignment : m_pImpl->aFieldAssignments)
883
0
            if (!fieldAssignment.isEmpty())
884
0
                if (aColumnNameSet.end() == aColumnNameSet.find(fieldAssignment))
885
0
                    fieldAssignment.clear();
886
0
    }
887
888
    IMPL_LINK(AddressBookSourceDialog, OnFieldSelect, weld::ComboBox&, rListbox, void)
889
0
    {
890
        // the index of the affected list box in our array
891
0
        sal_Int32 nListBoxIndex = rListbox.get_id(0).toInt32();
892
0
        DBG_ASSERT(nListBoxIndex >= 0 && nListBoxIndex < FIELD_CONTROLS_VISIBLE,
893
0
            "AddressBookSourceDialog::OnFieldScroll: invalid list box entry!");
894
895
        // update the array where we remember the field selections
896
0
        if (0 == rListbox.get_active())
897
            // it's the "no field selection" entry
898
0
            m_pImpl->aFieldAssignments[m_pImpl->nFieldScrollPos * 2 + nListBoxIndex].clear();
899
0
        else
900
            // it's a regular field entry
901
0
            m_pImpl->aFieldAssignments[m_pImpl->nFieldScrollPos * 2 + nListBoxIndex] = rListbox.get_active_text();
902
0
    }
903
904
905
    void AddressBookSourceDialog::implScrollFields(sal_Int32 _nPos, bool _bAdjustFocus, bool _bAdjustScrollbar)
906
0
    {
907
0
        if (_nPos == m_pImpl->nFieldScrollPos)
908
            // nothing to do
909
0
            return;
910
911
        // loop through our field control rows and do some adjustments
912
        // for the new texts
913
0
        auto pLeftLabelControl = m_pImpl->pFieldLabels.begin();
914
0
        auto pRightLabelControl = pLeftLabelControl+1;
915
0
        auto pLeftColumnLabel = m_pImpl->aFieldLabels.cbegin() + 2 * _nPos;
916
0
        auto pRightColumnLabel = pLeftColumnLabel + 1;
917
918
        // for the focus movement and the selection scroll
919
0
        auto pLeftListControl = m_pImpl->pFields.begin();
920
0
        auto pRightListControl = pLeftListControl + 1;
921
922
        // for the focus movement
923
0
        sal_Int32 nOldFocusRow = -1;
924
0
        sal_Int32 nOldFocusColumn = 0;
925
926
        // for the selection scroll
927
0
        auto pLeftAssignment = m_pImpl->aFieldAssignments.cbegin() + 2 * _nPos;
928
0
        auto pRightAssignment = pLeftAssignment + 1;
929
930
        // loop
931
0
        for (sal_Int32 i=0; i<FIELD_PAIRS_VISIBLE; ++i)
932
0
        {
933
0
            if ((*pLeftListControl)->has_focus())
934
0
            {
935
0
                nOldFocusRow = i;
936
0
                nOldFocusColumn = 0;
937
0
            }
938
0
            else if ((*pRightListControl)->has_focus())
939
0
            {
940
0
                nOldFocusRow = i;
941
0
                nOldFocusColumn = 1;
942
0
            }
943
944
            // the new texts of the label controls
945
0
            (*pLeftLabelControl)->set_label(*pLeftColumnLabel);
946
0
            (*pRightLabelControl)->set_label(*pRightColumnLabel);
947
948
            // we may have to hide the controls in the right column, if we have no label text for it
949
            // (which means we have an odd number of fields, though we forced our internal arrays to
950
            // be even-sized for easier handling)
951
            // (If sometimes we support an arbitrary number of field assignments, we would have to care for
952
            // an invisible left hand side column, too. But right now, the left hand side controls are always
953
            // visible)
954
0
            bool bHideRightColumn = pRightColumnLabel->isEmpty();
955
0
            (*pRightLabelControl)->set_visible(!bHideRightColumn);
956
0
            (*pRightListControl)->set_visible(!bHideRightColumn);
957
            // the new selections of the listboxes
958
0
            implSelectField(pLeftListControl->get(), *pLeftAssignment);
959
0
            implSelectField(pRightListControl->get(), *pRightAssignment);
960
961
            // increment ...
962
0
            if ( i < FIELD_PAIRS_VISIBLE - 1 )
963
0
            {   // (not in the very last round, here the +=2 could result in an invalid
964
                // iterator position, which causes an abort in a non-product version
965
0
                pLeftLabelControl += 2;
966
0
                pRightLabelControl += 2;
967
0
                pLeftColumnLabel += 2;
968
0
                pRightColumnLabel += 2;
969
970
0
                pLeftListControl += 2;
971
0
                pRightListControl += 2;
972
0
                pLeftAssignment += 2;
973
0
                pRightAssignment += 2;
974
0
            }
975
0
        }
976
977
0
        if (_bAdjustFocus && (nOldFocusRow >= 0))
978
0
        {   // we have to adjust the focus and one of the list boxes has the focus
979
0
            sal_Int32 nDelta = m_pImpl->nFieldScrollPos - _nPos;
980
            // the new row for the focus
981
0
            sal_Int32 nNewFocusRow = nOldFocusRow + nDelta;
982
            // normalize
983
0
            nNewFocusRow = std::min(nNewFocusRow, sal_Int32(FIELD_PAIRS_VISIBLE - 1), ::std::less< sal_Int32 >());
984
0
            nNewFocusRow = std::max(nNewFocusRow, sal_Int32(0), ::std::less< sal_Int32 >());
985
            // set the new focus (in the same column)
986
0
            m_pImpl->pFields[nNewFocusRow * 2 + nOldFocusColumn]->grab_focus();
987
0
        }
988
989
0
        m_pImpl->nFieldScrollPos = _nPos;
990
991
0
        if (_bAdjustScrollbar)
992
0
            m_xFieldScroller->vadjustment_set_value(m_pImpl->nFieldScrollPos);
993
0
    }
994
995
    void AddressBookSourceDialog::implSelectField(weld::ComboBox* pBox, const OUString& rText)
996
0
    {
997
0
        if (!rText.isEmpty())
998
            // a valid field name
999
0
            pBox->set_active_text(rText);
1000
0
        else
1001
            // no selection for this item
1002
0
            pBox->set_active(0);
1003
0
    }
1004
1005
    IMPL_LINK(AddressBookSourceDialog, OnComboSelect, weld::ComboBox&, rBox, void)
1006
0
    {
1007
0
        if (&rBox == m_xDatasource.get())
1008
0
            resetTables();
1009
0
        else
1010
0
            resetFields();
1011
0
    }
1012
1013
    IMPL_STATIC_LINK(AddressBookSourceDialog, OnComboGetFocus, weld::Widget&, rBox, void)
1014
0
    {
1015
0
        dynamic_cast<weld::ComboBox&>(rBox).save_value();
1016
0
    }
1017
1018
    IMPL_LINK(AddressBookSourceDialog, OnComboLoseFocus, weld::Widget&, rControl, void)
1019
0
    {
1020
0
        weld::ComboBox& rBox = dynamic_cast<weld::ComboBox&>(rControl);
1021
0
        if (rBox.get_value_changed_from_saved())
1022
0
        {
1023
0
            if (&rBox == m_xDatasource.get())
1024
0
                resetTables();
1025
0
            else
1026
0
                resetFields();
1027
0
        }
1028
0
    }
1029
1030
    IMPL_LINK_NOARG(AddressBookSourceDialog, OnOkClicked, weld::Button&, void)
1031
0
    {
1032
0
        OUString sSelectedDS = lcl_getSelectedDataSource(*m_xDatasource);
1033
0
        if ( m_pImpl->bWorkingPersistent )
1034
0
        {
1035
0
            m_pImpl->pConfigData->setDatasourceName(sSelectedDS);
1036
0
            m_pImpl->pConfigData->setCommand(m_xTable->get_active_text());
1037
0
        }
1038
1039
        // AddressBookSourceDialog::loadConfiguration: inconsistence between field names and field assignments!
1040
0
        assert(m_pImpl->aLogicalFieldNames.size() == m_pImpl->aFieldAssignments.size());
1041
1042
        // set the field assignments
1043
0
        auto aAssignment = m_pImpl->aFieldAssignments.cbegin();
1044
0
        for (auto const& logicalFieldName : m_pImpl->aLogicalFieldNames)
1045
0
        {
1046
0
            m_pImpl->pConfigData->setFieldAssignment(logicalFieldName, *aAssignment);
1047
0
            ++aAssignment;
1048
0
        }
1049
1050
0
        m_xDialog->response(RET_OK);
1051
0
    }
1052
1053
    IMPL_LINK_NOARG(AddressBookSourceDialog, OnAdministrateDatasources, weld::Button&, void)
1054
0
    {
1055
        // create the dialog object
1056
0
        Reference< XExecutableDialog > xAdminDialog;
1057
0
        try
1058
0
        {
1059
0
            xAdminDialog = AddressBookSourcePilot::createWithParent(m_xORB, m_xDialog->GetXWindow());
1060
0
        }
1061
0
        catch(const Exception&) { }
1062
0
        if (!xAdminDialog.is())
1063
0
        {
1064
0
            ShowServiceNotAvailableError(m_xDialog.get(), u"com.sun.star.ui.dialogs.AddressBookSourcePilot", true);
1065
0
            return;
1066
0
        }
1067
1068
        // execute the dialog
1069
0
        try
1070
0
        {
1071
0
            if ( xAdminDialog->execute() == RET_OK )
1072
0
            {
1073
0
                Reference<XPropertySet> xProp(xAdminDialog,UNO_QUERY);
1074
0
                if ( xProp.is() )
1075
0
                {
1076
0
                    OUString sName;
1077
0
                    xProp->getPropertyValue(u"DataSourceName"_ustr) >>= sName;
1078
1079
0
                    INetURLObject aURL( sName );
1080
0
                    if( aURL.GetProtocol() != INetProtocol::NotValid )
1081
0
                    {
1082
0
                        OFileNotation aFileNotation( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1083
0
                        sName = aFileNotation.get(OFileNotation::N_SYSTEM);
1084
0
                    }
1085
0
                    m_xDatasource->append_text(sName);
1086
0
                    m_pImpl->pConfigData.reset( new AssignmentPersistentData );
1087
0
                    loadConfiguration();
1088
0
                    resetTables();
1089
                    // will reset the fields implicitly
1090
0
                }
1091
0
            }
1092
0
        }
1093
0
        catch(const Exception&)
1094
0
        {
1095
0
            OSL_FAIL("AddressBookSourceDialog::OnAdministrateDatasources: an error occurred while executing the administration dialog!");
1096
0
        }
1097
1098
        // re-fill the data source list
1099
        // try to preserve the current selection
1100
1101
//      initializeDatasources();
1102
0
    }
1103
1104
}   // namespace svt
1105
1106
1107
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */