Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/xmlsource/xmlsourcedlg.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
10
#include <xmlsourcedlg.hxx>
11
#include <bitmaps.hlst>
12
#include <document.hxx>
13
#include <orcusfilters.hxx>
14
#include <filter.hxx>
15
#include <reffact.hxx>
16
#include <tabvwsh.hxx>
17
18
#include <tools/urlobj.hxx>
19
#include <sfx2/filedlghelper.hxx>
20
#include <vcl/weld/Dialog.hxx>
21
22
#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
23
#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
24
#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
25
26
using namespace com::sun::star;
27
28
namespace {
29
30
bool isAttribute(const weld::TreeView& rControl, const weld::TreeIter& rEntry)
31
0
{
32
0
    const ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(rControl, rEntry);
33
0
    if (!pUserData)
34
0
        return false;
35
36
0
    return pUserData->meType == ScOrcusXMLTreeParam::Attribute;
37
0
}
38
39
OUString getXPath(
40
    const weld::TreeView& rTree, const weld::TreeIter& rEntry, std::vector<size_t>& rNamespaces)
41
0
{
42
0
    OUStringBuffer aBuf;
43
0
    std::unique_ptr<weld::TreeIter> xEntry(rTree.make_iterator(&rEntry));
44
0
    do
45
0
    {
46
        // Collect used namespace.
47
0
        const ScOrcusXMLTreeParam::EntryData* pData = ScOrcusXMLTreeParam::getUserData(rTree, *xEntry);
48
0
        if (pData)
49
0
            rNamespaces.push_back(pData->mnNamespaceID);
50
51
        // element separator is '/' whereas attribute separator is '/@' in xpath.
52
0
        std::u16string_view sSeparator;
53
0
        if (isAttribute(rTree, *xEntry))
54
0
            sSeparator = u"/@";
55
0
        else
56
0
            sSeparator = u"/";
57
0
        aBuf.insert(0, sSeparator + rTree.get_text(*xEntry, 0));
58
0
    }
59
0
    while (rTree.iter_parent(*xEntry));
60
61
0
    return aBuf.makeStringAndClear();
62
0
}
63
64
}
65
66
ScXMLSourceDlg::ScXMLSourceDlg(
67
    SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, ScDocument& rDoc)
68
0
    : ScAnyRefDlgController(pB, pCW, pParent, u"modules/scalc/ui/xmlsourcedialog.ui"_ustr, u"XMLSourceDialog"_ustr)
69
0
    , mrDoc(rDoc)
70
0
    , mbDlgLostFocus(false)
71
0
    , mxBtnSelectSource(m_xBuilder->weld_button(u"selectsource"_ustr))
72
0
    , mxFtSourceFile(m_xBuilder->weld_label(u"sourcefile"_ustr))
73
0
    , mxMapGrid(m_xBuilder->weld_container(u"mapgrid"_ustr))
74
0
    , mxLbTree(m_xBuilder->weld_tree_view(u"tree"_ustr))
75
0
    , mxRefEdit(new formula::RefEdit(m_xBuilder->weld_entry(u"edit"_ustr)))
76
0
    , mxRefBtn(new formula::RefButton(m_xBuilder->weld_button(u"ref"_ustr)))
77
0
    , mxBtnOk(m_xBuilder->weld_button(u"ok"_ustr))
78
0
    , mxBtnCancel(m_xBuilder->weld_button(u"cancel"_ustr))
79
0
    , maCustomCompare(*mxLbTree)
80
0
    , maCellLinks(maCustomCompare)
81
0
    , maRangeLinks(maCustomCompare)
82
0
{
83
0
    mxLbTree->set_size_request(mxLbTree->get_approximate_digit_width() * 40,
84
0
                               mxLbTree->get_height_rows(15));
85
0
    mxLbTree->set_selection_mode(SelectionMode::Multiple);
86
0
    mxRefEdit->SetReferences(this);
87
0
    mxRefBtn->SetReferences(this, mxRefEdit.get());
88
89
0
    mpActiveEdit = mxRefEdit.get();
90
91
0
    maXMLParam.maImgElementDefault = RID_BMP_ELEMENT_DEFAULT;
92
0
    maXMLParam.maImgElementRepeat = RID_BMP_ELEMENT_REPEAT;
93
0
    maXMLParam.maImgAttribute = RID_BMP_ELEMENT_ATTRIBUTE;
94
95
0
    Link<weld::Button&,void> aBtnHdl = LINK(this, ScXMLSourceDlg, BtnPressedHdl);
96
0
    mxBtnSelectSource->connect_clicked(aBtnHdl);
97
0
    mxBtnOk->connect_clicked(aBtnHdl);
98
0
    mxBtnCancel->connect_clicked(aBtnHdl);
99
100
0
    mxLbTree->connect_selection_changed(LINK(this, ScXMLSourceDlg, TreeItemSelectHdl));
101
102
0
    Link<formula::RefEdit&,void> aLink = LINK(this, ScXMLSourceDlg, RefModifiedHdl);
103
0
    mxRefEdit->SetModifyHdl(aLink);
104
105
0
    mxBtnOk->set_sensitive(false);
106
107
0
    SetNonLinkable();
108
0
    mxBtnSelectSource->grab_focus(); // Initial focus is on the select source button.
109
0
}
110
111
ScXMLSourceDlg::~ScXMLSourceDlg()
112
0
{
113
0
}
114
115
bool ScXMLSourceDlg::IsRefInputMode() const
116
0
{
117
0
    return mpActiveEdit != nullptr && mpActiveEdit->GetWidget()->get_sensitive();
118
0
}
119
120
void ScXMLSourceDlg::SetReference(const ScRange& rRange, ScDocument& rDoc)
121
0
{
122
0
    if (!mpActiveEdit)
123
0
        return;
124
125
0
    if (rRange.aStart != rRange.aEnd)
126
0
        RefInputStart(mpActiveEdit);
127
128
0
    OUString aStr(rRange.aStart.Format(ScRefFlags::ADDR_ABS_3D, &rDoc, rDoc.GetAddressConvention()));
129
0
    mpActiveEdit->SetRefString(aStr);
130
131
0
    RefEditModified();
132
0
}
133
134
void ScXMLSourceDlg::Deactivate()
135
0
{
136
0
    mbDlgLostFocus = true;
137
0
}
138
139
void ScXMLSourceDlg::SetActive()
140
0
{
141
0
    if (mbDlgLostFocus)
142
0
    {
143
0
        mbDlgLostFocus = false;
144
0
        if (mpActiveEdit)
145
0
        {
146
0
            mpActiveEdit->GrabFocus();
147
0
        }
148
0
    }
149
0
    else
150
0
    {
151
0
        m_xDialog->grab_focus();
152
0
    }
153
154
0
    RefInputDone();
155
0
}
156
157
void ScXMLSourceDlg::Close()
158
0
{
159
0
    DoClose(ScXMLSourceDlgWrapper::GetChildWindowId());
160
0
}
161
162
void ScXMLSourceDlg::SelectSourceFile()
163
0
{
164
0
    sfx2::FileDialogHelper aDlgHelper(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
165
0
                                      FileDialogFlags::NONE, m_xDialog.get());
166
0
    aDlgHelper.SetContext(sfx2::FileDialogHelper::CalcXMLSource);
167
168
    // Use the directory of current source file.
169
0
    INetURLObject aURL(maSrcPath);
170
0
    aURL.removeSegment();
171
0
    aURL.removeFinalSlash();
172
0
    OUString aPath = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
173
174
0
    if (!aPath.isEmpty())
175
0
        aDlgHelper.SetDisplayFolder(aPath);
176
0
    if (aDlgHelper.Execute() != ERRCODE_NONE)
177
        // File picker dialog cancelled.
178
0
        return;
179
180
0
    uno::Sequence<OUString> aFiles = aDlgHelper.GetSelectedFiles();
181
0
    if (!aFiles.hasElements())
182
0
        return;
183
184
    // There should only be one file returned from the file picker.
185
0
    maSrcPath = aFiles[0];
186
0
    mxFtSourceFile->set_label(maSrcPath);
187
0
    LoadSourceFileStructure(maSrcPath);
188
0
}
189
190
void ScXMLSourceDlg::LoadSourceFileStructure(const OUString& rPath)
191
0
{
192
0
    ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
193
0
    if (!pOrcus)
194
0
        return;
195
196
0
    mpXMLContext = pOrcus->createXMLContext(mrDoc, rPath);
197
0
    if (!mpXMLContext)
198
0
        return;
199
200
0
    mpXMLContext->loadXMLStructure(*mxLbTree, maXMLParam);
201
0
}
202
203
namespace {
204
205
/**
206
 * The current entry is the reference entry for a cell link.  For a range
207
 * link, the reference entry is the shallowest repeat element entry up from
208
 * the current entry position.  The mapped cell position for a range link is
209
 * stored with the reference entry.
210
 */
211
std::unique_ptr<weld::TreeIter> getReferenceEntry(const weld::TreeView& rTree, const weld::TreeIter& rCurEntry)
212
0
{
213
0
    std::unique_ptr<weld::TreeIter> xParent(rTree.make_iterator(&rCurEntry));
214
0
    bool bParent = rTree.iter_parent(*xParent);
215
0
    std::unique_ptr<weld::TreeIter> xRefEntry;
216
0
    while (bParent)
217
0
    {
218
0
        ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(rTree, *xParent);
219
0
        assert(pUserData);
220
0
        if (pUserData->meType == ScOrcusXMLTreeParam::ElementRepeat)
221
0
        {
222
            // This is a repeat element - a potential reference entry.
223
0
            xRefEntry = rTree.make_iterator(xParent.get());
224
0
        }
225
0
        bParent = rTree.iter_parent(*xParent);
226
0
    }
227
228
0
    if (xRefEntry)
229
0
        return xRefEntry;
230
231
0
    std::unique_ptr<weld::TreeIter> xCurEntry(rTree.make_iterator(&rCurEntry));
232
0
    return xCurEntry;
233
0
}
234
235
}
236
237
void ScXMLSourceDlg::TreeItemSelected()
238
0
{
239
0
    std::unique_ptr<weld::TreeIter> xEntry = mxLbTree->get_cursor();
240
0
    if (!xEntry)
241
0
        return;
242
243
0
    mxLbTree->unselect_all();
244
0
    mxLbTree->select(*xEntry);
245
246
0
    mxCurRefEntry = getReferenceEntry(*mxLbTree, *xEntry);
247
248
0
    ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *mxCurRefEntry);
249
0
    assert(pUserData);
250
251
0
    const ScAddress& rPos = pUserData->maLinkedPos;
252
0
    if (rPos.IsValid())
253
0
    {
254
0
        OUString aStr(rPos.Format(ScRefFlags::ADDR_ABS_3D, &mrDoc, mrDoc.GetAddressConvention()));
255
0
        mxRefEdit->SetRefString(aStr);
256
0
    }
257
0
    else
258
0
        mxRefEdit->SetRefString(OUString());
259
260
0
    switch (pUserData->meType)
261
0
    {
262
0
        case ScOrcusXMLTreeParam::Attribute:
263
0
            AttributeSelected(*mxCurRefEntry);
264
0
        break;
265
0
        case ScOrcusXMLTreeParam::ElementDefault:
266
0
            DefaultElementSelected(*mxCurRefEntry);
267
0
        break;
268
0
        case ScOrcusXMLTreeParam::ElementRepeat:
269
0
            RepeatElementSelected(*mxCurRefEntry);
270
0
        break;
271
0
        default:
272
0
            ;
273
0
    }
274
0
}
275
276
void ScXMLSourceDlg::DefaultElementSelected(const weld::TreeIter& rEntry)
277
0
{
278
0
    if (mxLbTree->iter_has_child(rEntry))
279
0
    {
280
        // Only an element with no child elements (leaf element) can be linked.
281
0
        bool bHasChild = false;
282
0
        std::unique_ptr<weld::TreeIter> xChild(mxLbTree->make_iterator(&rEntry));
283
0
        (void)mxLbTree->iter_children(*xChild);
284
0
        do
285
0
        {
286
0
            ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *xChild);
287
0
            assert(pUserData);
288
0
            if (pUserData->meType != ScOrcusXMLTreeParam::Attribute)
289
0
            {
290
                // This child is not an attribute. Bail out.
291
0
                bHasChild = true;
292
0
                break;
293
0
            }
294
0
        }
295
0
        while (mxLbTree->iter_next_sibling(*xChild));
296
297
0
        if (bHasChild)
298
0
        {
299
0
            SetNonLinkable();
300
0
            return;
301
0
        }
302
0
    }
303
304
    // Check all its parents and make sure non of them are range-linked nor
305
    // repeat elements.
306
0
    if (IsParentDirty(&rEntry))
307
0
    {
308
0
        SetNonLinkable();
309
0
        return;
310
0
    }
311
312
0
    SetSingleLinkable();
313
0
}
314
315
void ScXMLSourceDlg::RepeatElementSelected(const weld::TreeIter& rEntry)
316
0
{
317
    // Check all its parents first.
318
319
0
    if (IsParentDirty(&rEntry))
320
0
    {
321
0
        SetNonLinkable();
322
0
        return;
323
0
    }
324
325
    // Check all its child elements / attributes and make sure non of them are
326
    // linked.
327
328
0
    if (IsChildrenDirty(&rEntry))
329
0
    {
330
0
        SetNonLinkable();
331
0
        return;
332
0
    }
333
334
0
    if (!mxLbTree->is_selected(rEntry))
335
0
    {
336
        // Highlight the entry if not highlighted already.  This can happen
337
        // when the current entry is a child entry of a repeat element entry.
338
0
        mxLbTree->select(rEntry);
339
0
    }
340
341
0
    SelectAllChildEntries(rEntry);
342
0
    SetRangeLinkable();
343
0
}
344
345
void ScXMLSourceDlg::AttributeSelected(const weld::TreeIter& rEntry)
346
0
{
347
    // Check all its parent elements and make sure non of them are linked nor
348
    // repeat elements.  In attribute's case, it's okay to have the immediate
349
    // parent element linked (but not range-linked).
350
0
    std::unique_ptr<weld::TreeIter> xParent(mxLbTree->make_iterator(&rEntry));
351
0
    mxLbTree->iter_parent(*xParent);
352
353
0
    ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *xParent);
354
0
    assert(pUserData);
355
0
    if (pUserData->maLinkedPos.IsValid() && pUserData->mbRangeParent)
356
0
    {
357
        // Parent element is range-linked.  Bail out.
358
0
        SetNonLinkable();
359
0
        return;
360
0
    }
361
362
0
    if (IsParentDirty(&rEntry))
363
0
    {
364
0
        SetNonLinkable();
365
0
        return;
366
0
    }
367
368
0
    SetSingleLinkable();
369
0
}
370
371
void ScXMLSourceDlg::SetNonLinkable()
372
0
{
373
0
    mxMapGrid->set_sensitive(false);
374
0
}
375
376
void ScXMLSourceDlg::SetSingleLinkable()
377
0
{
378
0
    mxMapGrid->set_sensitive(true);
379
0
}
380
381
void ScXMLSourceDlg::SetRangeLinkable()
382
0
{
383
0
    mxMapGrid->set_sensitive(true);
384
0
}
385
386
void ScXMLSourceDlg::SelectAllChildEntries(const weld::TreeIter& rEntry)
387
0
{
388
0
    std::unique_ptr<weld::TreeIter> xChild(mxLbTree->make_iterator(&rEntry));
389
0
    if (!mxLbTree->iter_children(*xChild))
390
0
        return;
391
0
    do
392
0
    {
393
0
        SelectAllChildEntries(*xChild); // select recursively.
394
0
        mxLbTree->select(*xChild);
395
0
    } while (mxLbTree->iter_next_sibling(*xChild));
396
0
}
397
398
bool ScXMLSourceDlg::IsParentDirty(const weld::TreeIter* pEntry) const
399
0
{
400
0
    std::unique_ptr<weld::TreeIter> xParent(mxLbTree->make_iterator(pEntry));
401
0
    if (!mxLbTree->iter_parent(*xParent))
402
0
        return false;
403
0
    do
404
0
    {
405
0
        ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *xParent);
406
0
        assert(pUserData);
407
0
        if (pUserData->maLinkedPos.IsValid())
408
0
        {
409
            // This parent is already linked.
410
0
            return true;
411
0
        }
412
0
    }
413
0
    while (mxLbTree->iter_parent(*xParent));
414
0
    return false;
415
0
}
416
417
bool ScXMLSourceDlg::IsChildrenDirty(const weld::TreeIter* pEntry) const
418
0
{
419
0
    std::unique_ptr<weld::TreeIter> xChild(mxLbTree->make_iterator(pEntry));
420
0
    if (!mxLbTree->iter_children(*xChild))
421
0
        return false;
422
423
0
    do
424
0
    {
425
0
        ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *xChild);
426
0
        assert(pUserData);
427
0
        if (pUserData->maLinkedPos.IsValid())
428
            // Already linked.
429
0
            return true;
430
431
0
        if (pUserData->meType == ScOrcusXMLTreeParam::ElementDefault)
432
0
        {
433
            // Check recursively.
434
0
            if (IsChildrenDirty(xChild.get()))
435
0
                return true;
436
0
        }
437
0
    } while (mxLbTree->iter_next_sibling(*xChild));
438
439
0
    return false;
440
0
}
441
442
namespace {
443
444
/**
445
 * Pick only the leaf elements.
446
 */
447
void getFieldLinks(
448
    ScOrcusImportXMLParam::RangeLink& rRangeLink, std::vector<size_t>& rNamespaces,
449
    const weld::TreeView& rTree, const weld::TreeIter& rEntry)
450
0
{
451
0
    OUString aPath = getXPath(rTree, rEntry, rNamespaces);
452
0
    const ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(rTree, rEntry);
453
454
0
    if (pUserData)
455
0
    {
456
0
        if (pUserData->meType == ScOrcusXMLTreeParam::ElementRepeat)
457
            // nested repeat element automatically becomes a row-group node.
458
0
            rRangeLink.maRowGroups.push_back(
459
0
                OUStringToOString(aPath, RTL_TEXTENCODING_UTF8));
460
461
0
        if (pUserData->mbLeafNode && !aPath.isEmpty())
462
            // XPath should never be empty anyway, but it won't hurt to check...
463
0
            rRangeLink.maFieldPaths.push_back(OUStringToOString(aPath, RTL_TEXTENCODING_UTF8));
464
0
    }
465
466
0
    std::unique_ptr<weld::TreeIter> xChild(rTree.make_iterator(&rEntry));
467
468
0
    if (!rTree.iter_children(*xChild))
469
        // No more children.  We're done.
470
0
        return;
471
472
0
    do
473
0
    {
474
        // Walk recursively.
475
0
        getFieldLinks(rRangeLink, rNamespaces, rTree, *xChild);
476
0
    }
477
0
    while (rTree.iter_next_sibling(*xChild));
478
0
}
479
480
void removeDuplicates(std::vector<size_t>& rArray)
481
0
{
482
0
    std::sort(rArray.begin(), rArray.end());
483
0
    std::vector<size_t>::iterator it = std::unique(rArray.begin(), rArray.end());
484
0
    rArray.erase(it, rArray.end());
485
0
}
486
487
}
488
489
void ScXMLSourceDlg::OkPressed()
490
0
{
491
0
    if (!mpXMLContext)
492
0
        return;
493
494
    // Begin import.
495
496
0
    ScOrcusImportXMLParam aParam;
497
498
    // Convert single cell links.
499
0
    for (const auto& rEntry : maCellLinks)
500
0
    {
501
0
        OUString aPath = getXPath(*mxLbTree, *rEntry, aParam.maNamespaces);
502
0
        const ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *rEntry);
503
504
0
        aParam.maCellLinks.emplace_back(
505
0
                pUserData->maLinkedPos, OUStringToOString(aPath, RTL_TEXTENCODING_UTF8));
506
0
    }
507
508
    // Convert range links. For now, an element with range link takes all its
509
    // child elements as its fields.
510
0
    for (const auto& rEntry: maRangeLinks)
511
0
    {
512
0
        const ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *rEntry);
513
514
0
        ScOrcusImportXMLParam::RangeLink aRangeLink;
515
0
        aRangeLink.maPos = pUserData->maLinkedPos;
516
517
        // Go through all its child elements.
518
0
        getFieldLinks(aRangeLink, aParam.maNamespaces, *mxLbTree, *rEntry);
519
520
        // Add the reference entry as a row-group node, which will be used
521
        // as a row position increment point.
522
0
        OUString aThisEntry = getXPath(*mxLbTree, *rEntry, aParam.maNamespaces);
523
0
        aRangeLink.maRowGroups.push_back(
524
0
            OUStringToOString(aThisEntry, RTL_TEXTENCODING_UTF8));
525
526
0
        aParam.maRangeLinks.push_back(std::move(aRangeLink));
527
0
    }
528
529
    // Remove duplicate namespace IDs.
530
0
    removeDuplicates(aParam.maNamespaces);
531
532
    // Now do the import.
533
0
    mpXMLContext->importXML(aParam);
534
535
    // Don't forget to broadcast the change.
536
0
    ScDocShell* pShell = mrDoc.GetDocumentShell();
537
0
    pShell->Broadcast(SfxHint(SfxHintId::ScDataChanged));
538
539
    // Repaint the grid to force repaint the cell values.
540
0
    ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
541
0
    if (pViewShell)
542
0
        pViewShell->PaintGrid();
543
544
0
    m_xDialog->response(RET_OK);
545
0
}
546
547
void ScXMLSourceDlg::CancelPressed()
548
0
{
549
0
    m_xDialog->response(RET_CANCEL);
550
0
}
551
552
void ScXMLSourceDlg::RefEditModified()
553
0
{
554
0
    OUString aRefStr = mxRefEdit->GetText();
555
556
    // Check if the address is valid.
557
    // Preset current sheet in case only address was entered.
558
0
    ScAddress aLinkedPos;
559
0
    aLinkedPos.SetTab( ScDocShell::GetCurTab());
560
0
    ScRefFlags nRes = aLinkedPos.Parse(aRefStr, mrDoc, mrDoc.GetAddressConvention());
561
0
    bool bValid = ( (nRes & ScRefFlags::VALID) == ScRefFlags::VALID );
562
563
    // TODO: For some unknown reason, setting the ref invalid will hide the text altogether.
564
    // Find out how to make this work.
565
//  mxRefEdit->SetRefValid(bValid);
566
567
0
    if (!bValid)
568
0
        aLinkedPos.SetInvalid();
569
570
    // Set this address to the current reference entry.
571
0
    if (!mxCurRefEntry)
572
        // This should never happen.
573
0
        return;
574
575
0
    ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *mxCurRefEntry);
576
0
    if (!pUserData)
577
        // This should never happen either.
578
0
        return;
579
580
0
    bool bRepeatElem = pUserData->meType == ScOrcusXMLTreeParam::ElementRepeat;
581
0
    pUserData->maLinkedPos = aLinkedPos;
582
0
    pUserData->mbRangeParent = aLinkedPos.IsValid() && bRepeatElem;
583
584
0
    if (bRepeatElem)
585
0
    {
586
0
        if (bValid)
587
0
            maRangeLinks.insert(mxLbTree->make_iterator(mxCurRefEntry.get()));
588
0
        else
589
0
            maRangeLinks.erase(mxCurRefEntry);
590
0
    }
591
0
    else
592
0
    {
593
0
        if (bValid)
594
0
            maCellLinks.insert(mxLbTree->make_iterator(mxCurRefEntry.get()));
595
0
        else
596
0
            maCellLinks.erase(mxCurRefEntry);
597
0
    }
598
599
    // Enable the import button only when at least one link exists.
600
0
    bool bHasLink = !maCellLinks.empty() || !maRangeLinks.empty();
601
0
    mxBtnOk->set_sensitive(bHasLink);
602
0
}
603
604
IMPL_LINK(ScXMLSourceDlg, BtnPressedHdl, weld::Button&, rBtn, void)
605
0
{
606
0
    if (&rBtn == mxBtnSelectSource.get())
607
0
        SelectSourceFile();
608
0
    else if (&rBtn == mxBtnOk.get())
609
0
        OkPressed();
610
0
    else if (&rBtn == mxBtnCancel.get())
611
0
        CancelPressed();
612
0
}
613
614
IMPL_LINK_NOARG(ScXMLSourceDlg, TreeItemSelectHdl, weld::TreeView&, void)
615
0
{
616
0
    TreeItemSelected();
617
0
}
618
619
IMPL_LINK_NOARG(ScXMLSourceDlg, RefModifiedHdl, formula::RefEdit&, void)
620
0
{
621
0
    RefEditModified();
622
0
}
623
624
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */