Coverage Report

Created: 2025-11-16 09:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/dialog/tabdlg.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 <stdlib.h>
22
#include <algorithm>
23
#include <string_view>
24
25
#include <sfx2/tabdlg.hxx>
26
#include <sfx2/app.hxx>
27
#include <sfx2/sfxresid.hxx>
28
#include <sfx2/sfxdlg.hxx>
29
#include <sfx2/viewsh.hxx>
30
#include <unotools/viewoptions.hxx>
31
#include <utility>
32
#include <vcl/virdev.hxx>
33
#include <sal/log.hxx>
34
#include <tools/debug.hxx>
35
#include <comphelper/lok.hxx>
36
37
#include <sfx2/strings.hrc>
38
#include <helpids.h>
39
40
using namespace ::com::sun::star::uno;
41
42
constexpr OUString USERITEM_NAME = u"UserItem"_ustr;
43
44
45
struct TabPageImpl
46
{
47
    bool                        mbStandard;
48
    SfxOkDialogController*      mpSfxDialogController;
49
    css::uno::Reference< css::frame::XFrame > mxFrame;
50
51
0
    TabPageImpl() : mbStandard(false), mpSfxDialogController(nullptr) {}
52
};
53
54
namespace {
55
56
struct Data_Impl
57
{
58
    OUString sId;                 // The ID
59
    CreateTabPage fnCreatePage;   // Pointer to Factory
60
    GetTabPageRanges fnGetRanges; // Pointer to Ranges-Function
61
    std::unique_ptr<SfxTabPage> xTabPage;         // The TabPage itself
62
    bool bRefresh;                // Flag: Page must be re-initialized
63
64
    // Constructor
65
    Data_Impl( const OUString& rId, CreateTabPage fnPage,
66
               GetTabPageRanges fnRanges ) :
67
68
0
        sId         ( rId ),
69
0
        fnCreatePage( fnPage ),
70
0
        fnGetRanges ( fnRanges ),
71
0
        bRefresh    ( false )
72
0
    {
73
0
    }
74
};
75
76
}
77
78
SfxTabDialogItem::SfxTabDialogItem( const SfxTabDialogItem& rAttr, SfxItemPool* pItemPool )
79
0
    : SfxSetItem( rAttr, pItemPool )
80
0
{
81
0
}
82
83
SfxTabDialogItem::SfxTabDialogItem( sal_uInt16 nId, const SfxItemSet& rItemSet )
84
0
    : SfxSetItem( nId, rItemSet )
85
0
{
86
0
}
87
88
SfxTabDialogItem* SfxTabDialogItem::Clone(SfxItemPool* pToPool) const
89
0
{
90
0
    return new SfxTabDialogItem( *this, pToPool );
91
0
}
92
93
typedef std::vector<Data_Impl*> SfxTabDlgData_Impl;
94
95
struct TabDlg_Impl
96
{
97
    bool                bHideResetBtn : 1;
98
    bool                bStarted : 1;
99
    SfxTabDlgData_Impl  aData;
100
101
    explicit TabDlg_Impl(sal_uInt8 nCnt)
102
0
        : bHideResetBtn(false)
103
0
        , bStarted(false)
104
0
    {
105
0
        aData.reserve( nCnt );
106
0
    }
107
};
108
109
static auto Find(const SfxTabDlgData_Impl& rArr, std::u16string_view rId)
110
0
{
111
0
    return std::find_if(rArr.begin(), rArr.end(),
112
0
                        [rId](const auto& item) { return item->sId == rId; });
113
0
}
114
115
void SfxTabPage::SetFrame(const css::uno::Reference< css::frame::XFrame >& xFrame)
116
0
{
117
0
    if (mpImpl)
118
0
        mpImpl->mxFrame = xFrame;
119
0
}
120
121
css::uno::Reference< css::frame::XFrame > SfxTabPage::GetFrame() const
122
0
{
123
0
    if (mpImpl)
124
0
        return mpImpl->mxFrame;
125
0
    return css::uno::Reference< css::frame::XFrame >();
126
0
}
127
128
static bool isLOKMobilePhone()
129
0
{
130
0
    if (!comphelper::LibreOfficeKit::isActive())
131
0
        return false;
132
0
    const SfxViewShell* pCurrentShell = SfxViewShell::Current();
133
0
    return pCurrentShell && pCurrentShell->isLOKMobilePhone();
134
0
}
135
136
SfxTabPage::SfxTabPage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, const OUString& rID, const SfxItemSet *rAttrSet)
137
0
    : BuilderPage(pPage, pController, rUIXMLDescription, rID, isLOKMobilePhone())
138
0
    , mpSet(rAttrSet)
139
0
    , mbHasExchangeSupport(false)
140
0
    , mbCancel(false)
141
0
    , mpImpl(new TabPageImpl)
142
0
{
143
0
    mpImpl->mpSfxDialogController = dynamic_cast<SfxOkDialogController*>(m_pDialogController);
144
0
}
145
146
SfxTabPage::~SfxTabPage()
147
0
{
148
0
    if (m_xContainer)
149
0
    {
150
0
        std::unique_ptr<weld::Container> xParent(m_xContainer->weld_parent());
151
0
        if (xParent)
152
0
            xParent->move(m_xContainer.get(), nullptr);
153
0
    }
154
0
    m_xContainer.reset();
155
0
    mpImpl.reset();
156
0
    m_xBuilder.reset();
157
0
}
158
159
bool SfxTabPage::FillItemSet( SfxItemSet* )
160
0
{
161
0
    return false;
162
0
}
163
164
/*
165
Returns the visible strings of a dialog.
166
167
Supported items:
168
- label
169
- check button
170
- radio button
171
- toggle button
172
- link button
173
- button
174
*/
175
0
OUString SfxTabPage::GetAllStrings() { return OUString(); }
176
177
void SfxTabPage::Reset( const SfxItemSet* )
178
0
{
179
0
}
180
181
0
bool SfxTabPage::DeferResetToFirstActivation() { return false; }
182
183
void SfxTabPage::ActivatePage( const SfxItemSet& )
184
/*  [Description]
185
186
    Default implementation of the virtual ActivatePage method. This method is
187
    called when a page of dialogue supports the exchange of data between pages.
188
    <SfxTabPage::DeactivatePage(SfxItemSet *)>
189
*/
190
0
{
191
0
}
192
193
DeactivateRC SfxTabPage::DeactivatePage( SfxItemSet* )
194
195
/*  [Description]
196
197
    Default implementation of the virtual DeactivatePage method. This method is
198
    called by Sfx when leaving a page; the application can, through the return
199
    value, control whether to leave the page. If the page is displayed through
200
    bHasExchangeSupport which supports data exchange between pages, then a
201
    pointer to the exchange set is passed as parameter. This takes on data for
202
    the exchange, then the set is available as a parameter in
203
    <SfxTabPage::ActivatePage(const SfxItemSet &)>.
204
205
    [Return value]
206
207
    DeactivateRC::LeavePage; Allow leaving the page
208
*/
209
210
0
{
211
0
    return DeactivateRC::LeavePage;
212
0
}
213
214
215
void SfxTabPage::FillUserData()
216
217
/*  [Description]
218
219
    Virtual method is called by the base class in the destructor to save
220
    specific information of the TabPage in the ini-file. When overriding a
221
    string must be compiled, which is then flushed with the <SetUserData()>.
222
*/
223
224
0
{
225
0
}
226
227
228
bool SfxTabPage::IsReadOnly() const
229
0
{
230
0
    return false;
231
0
}
232
233
234
const SfxPoolItem* SfxTabPage::GetItem( const SfxItemSet& rSet, sal_uInt16 nSlot, bool bDeep )
235
236
/*  [Description]
237
238
    static Method: hereby are the implementations of the TabPage code
239
    being simplified.
240
*/
241
242
0
{
243
0
    const SfxItemPool* pPool = rSet.GetPool();
244
0
    sal_uInt16 nWh = pPool->GetWhichIDFromSlotID( nSlot, bDeep );
245
0
    const SfxPoolItem* pItem = nullptr;
246
0
    rSet.GetItemState( nWh, true, &pItem );
247
248
0
    if ( !pItem && nWh != nSlot )
249
0
        pItem = &pPool->GetUserOrPoolDefaultItem( nWh );
250
0
    return pItem;
251
0
}
252
253
254
const SfxPoolItem* SfxTabPage::GetOldItem( const SfxItemSet& rSet,
255
                                           sal_uInt16 nSlot, bool bDeep )
256
257
/*  [Description]
258
259
    This method returns an attribute for comparison of the old value.
260
*/
261
262
0
{
263
0
    const SfxItemSet& rOldSet = GetItemSet();
264
0
    sal_uInt16 nWh = GetWhich( nSlot, bDeep );
265
0
    const SfxPoolItem* pItem = nullptr;
266
267
0
    if (mpImpl->mbStandard && rOldSet.GetParent())
268
0
        pItem = GetItem( *rOldSet.GetParent(), nSlot );
269
0
    else if ( rSet.GetParent() &&
270
0
              SfxItemState::INVALID == rSet.GetItemState( nWh ) )
271
0
        pItem = GetItem( *rSet.GetParent(), nSlot );
272
0
    else
273
0
        pItem = GetItem( rOldSet, nSlot );
274
0
    return pItem;
275
0
}
276
277
void SfxTabPage::PageCreated( const SfxAllItemSet& /*aSet*/ )
278
0
{
279
0
    SAL_WARN( "sfx.dialog", "SfxTabPage::PageCreated should not be called");
280
0
}
281
282
void SfxTabPage::ChangesApplied()
283
0
{
284
0
}
285
286
void SfxTabPage::SetDialogController(SfxOkDialogController* pDialog)
287
0
{
288
0
    mpImpl->mpSfxDialogController = pDialog;
289
0
    m_pDialogController = mpImpl->mpSfxDialogController;
290
0
}
291
292
SfxOkDialogController* SfxTabPage::GetDialogController() const
293
0
{
294
0
    return mpImpl->mpSfxDialogController;
295
0
}
296
297
OUString SfxTabPage::GetHelpId() const
298
0
{
299
0
    if (m_xContainer)
300
0
        return m_xContainer->get_help_id();
301
0
    return {};
302
0
}
303
304
weld::Window* SfxTabPage::GetFrameWeld() const
305
0
{
306
0
    if (m_pDialogController)
307
0
        return m_pDialogController->getDialog();
308
0
    return nullptr;
309
0
}
310
311
const SfxItemSet* SfxTabPage::GetDialogExampleSet() const
312
0
{
313
0
    if (mpImpl->mpSfxDialogController)
314
0
        return mpImpl->mpSfxDialogController->GetExampleSet();
315
0
    return nullptr;
316
0
}
317
318
SfxTabDialogController::SfxTabDialogController
319
(
320
    weld::Widget* pParent,              // Parent Window
321
    const OUString& rUIXMLDescription, const OUString& rID, // Dialog .ui path, Dialog Name
322
    const SfxItemSet* pItemSet,   // Itemset with the data;
323
                                  // can be NULL, when Pages are onDemand
324
    bool bEditFmt                 // when yes -> additional Button for standard
325
)
326
0
    : SfxOkDialogController(pParent, rUIXMLDescription, rID)
327
0
    , m_xTabCtrl(m_xBuilder->weld_notebook(u"tabcontrol"_ustr))
328
0
    , m_xOKBtn(m_xBuilder->weld_button(u"ok"_ustr))
329
0
    , m_xApplyBtn(m_xBuilder->weld_button(u"apply"_ustr))
330
0
    , m_xUserBtn(m_xBuilder->weld_button(u"user"_ustr))
331
0
    , m_xCancelBtn(m_xBuilder->weld_button(u"cancel"_ustr))
332
0
    , m_xResetBtn(m_xBuilder->weld_button(u"reset"_ustr))
333
0
    , m_xBaseFmtBtn(m_xBuilder->weld_button(u"standard"_ustr))
334
0
    , m_pSet(pItemSet ? new SfxItemSet(*pItemSet) : nullptr)
335
0
    , m_bStandardPushed(false)
336
0
{
337
0
    m_pImpl.reset(new TabDlg_Impl(m_xTabCtrl->get_n_pages()));
338
0
    m_pImpl->bHideResetBtn = !m_xResetBtn->get_visible();
339
0
    m_xOKBtn->connect_clicked(LINK(this, SfxTabDialogController, OkHdl));
340
0
    m_xCancelBtn->connect_clicked(LINK(this, SfxTabDialogController, CancelHdl));
341
0
    m_xResetBtn->connect_clicked(LINK(this, SfxTabDialogController, ResetHdl));
342
0
    m_xResetBtn->set_label(SfxResId(STR_RESET));
343
0
    m_xTabCtrl->connect_enter_page(LINK(this, SfxTabDialogController, ActivatePageHdl));
344
0
    m_xTabCtrl->connect_leave_page(LINK(this, SfxTabDialogController, DeactivatePageHdl));
345
0
    m_xResetBtn->set_help_id(HID_TABDLG_RESET_BTN);
346
347
0
    if (bEditFmt)
348
0
    {
349
0
        m_xBaseFmtBtn->set_label(SfxResId(STR_STANDARD_SHORTCUT));
350
0
        m_xBaseFmtBtn->connect_clicked(LINK(this, SfxTabDialogController, BaseFmtHdl));
351
0
        m_xBaseFmtBtn->set_help_id(HID_TABDLG_STANDARD_BTN);
352
0
        m_xBaseFmtBtn->show();
353
0
    }
354
355
0
    if (m_xUserBtn)
356
0
        m_xUserBtn->connect_clicked(LINK(this, SfxTabDialogController, UserHdl));
357
358
0
    if (m_pSet)
359
0
    {
360
0
        m_xExampleSet.reset(new SfxItemSet(*m_pSet));
361
0
        m_pOutSet.reset(new SfxItemSet(*m_pSet->GetPool(), m_pSet->GetRanges()));
362
0
    }
363
364
    // The reset functionality seems to be confusing to many; disable in LOK.
365
0
    if (comphelper::LibreOfficeKit::isActive())
366
0
        RemoveResetButton();
367
0
}
368
369
IMPL_LINK_NOARG(SfxTabDialogController, OkHdl, weld::Button&, void)
370
371
/*  [Description]
372
373
    Handler of the Ok-Buttons
374
    This calls the current page <SfxTabPage::DeactivatePage(SfxItemSet *)>.
375
    Returns <DeactivateRC::LeavePage>, <SfxTabDialog::Ok()> is called
376
    and the Dialog is ended.
377
*/
378
379
0
{
380
0
    if (PrepareLeaveCurrentPage())
381
0
        m_xDialog->response(Ok());
382
0
}
383
384
IMPL_LINK_NOARG(SfxTabDialogController, UserHdl, weld::Button&, void)
385
386
/*  [Description]
387
388
    Handler of the User-Buttons
389
    This calls the current page <SfxTabPage::DeactivatePage(SfxItemSet *)>.
390
    returns this <DeactivateRC::LeavePage> and  <SfxTabDialog::Ok()> is called.
391
    Then the Dialog is ended with the Return value <SfxTabDialog::Ok()>
392
*/
393
394
0
{
395
0
    if (PrepareLeaveCurrentPage())
396
0
    {
397
0
        short nRet = Ok();
398
0
        if (RET_OK == nRet)
399
0
            nRet = RET_USER;
400
0
        else
401
0
            nRet = RET_CANCEL;
402
0
        m_xDialog->response(nRet);
403
0
    }
404
0
}
405
406
IMPL_LINK_NOARG(SfxTabDialogController, CancelHdl, weld::Button&, void)
407
0
{
408
0
    m_xDialog->response(RET_CANCEL);
409
0
}
410
411
IMPL_LINK_NOARG(SfxTabDialogController, ResetHdl, weld::Button&, void)
412
413
/*  [Description]
414
415
    Handler behind the reset button.
416
    The Current Page is new initialized with their initial data, all the
417
    settings that the user has made on this page are repealed.
418
*/
419
420
0
{
421
0
    auto it = Find(m_pImpl->aData, m_xTabCtrl->get_current_page_ident());
422
0
    assert(it != m_pImpl->aData.end() && "Id not known");
423
424
0
    (*it)->xTabPage->Reset(m_pSet.get());
425
    // Also reset relevant items of ExampleSet and OutSet to initial state
426
0
    if (!(*it)->fnGetRanges)
427
0
        return;
428
429
0
    if (!m_xExampleSet)
430
0
        m_xExampleSet.reset(new SfxItemSet(*m_pSet));
431
432
0
    const SfxItemPool* pPool = m_pSet->GetPool();
433
0
    const WhichRangesContainer aTmpRanges = ((*it)->fnGetRanges)();
434
435
0
    for (const auto & rPair : aTmpRanges)
436
0
    {
437
        // Correct Range with multiple values
438
0
        sal_uInt16 nTmp = rPair.first, nTmpEnd = rPair.second;
439
0
        DBG_ASSERT(nTmp <= nTmpEnd, "Range is sorted the wrong way");
440
441
0
        if (nTmp > nTmpEnd)
442
0
        {
443
            // If really sorted wrongly, then set new
444
0
            std::swap(nTmp, nTmpEnd);
445
0
        }
446
447
0
        while (nTmp && nTmp <= nTmpEnd)
448
0
        {
449
            // Iterate over the Range and set the Items
450
0
            sal_uInt16 nWh = pPool->GetWhichIDFromSlotID(nTmp);
451
0
            const SfxPoolItem* pItem;
452
0
            if (SfxItemState::SET == m_pSet->GetItemState(nWh, false, &pItem))
453
0
            {
454
0
                m_xExampleSet->Put(*pItem);
455
0
            }
456
0
            else
457
0
            {
458
0
                m_xExampleSet->ClearItem(nWh);
459
0
            }
460
0
            m_pOutSet->ClearItem(nWh);
461
0
            nTmp++;
462
0
        }
463
0
    }
464
0
}
465
466
/*  [Description]
467
468
    Handler behind the Standard-Button.
469
    This button is available when editing style sheets. All the set attributes
470
    in the edited stylesheet are deleted.
471
*/
472
IMPL_LINK_NOARG(SfxTabDialogController, BaseFmtHdl, weld::Button&, void)
473
0
{
474
0
    m_bStandardPushed = true;
475
476
0
    auto it = Find(m_pImpl->aData, m_xTabCtrl->get_current_page_ident());
477
0
    assert(it != m_pImpl->aData.end() && "Id not known");
478
479
0
    if (!(*it)->fnGetRanges)
480
0
        return;
481
482
0
    if (!m_xExampleSet)
483
0
        m_xExampleSet.reset(new SfxItemSet(*m_pSet));
484
485
0
    const SfxItemPool* pPool = m_pSet->GetPool();
486
0
    const WhichRangesContainer aTmpRanges = ((*it)->fnGetRanges)();
487
0
    SfxItemSet aTmpSet(*m_xExampleSet);
488
489
0
    for (const auto& rPair : aTmpRanges)
490
0
    {
491
        // Correct Range with multiple values
492
0
        sal_uInt16 nTmp = rPair.first, nTmpEnd = rPair.second;
493
0
        DBG_ASSERT( nTmp <= nTmpEnd, "Range is sorted the wrong way" );
494
495
0
        if ( nTmp > nTmpEnd )
496
0
        {
497
            // If really sorted wrongly, then set new
498
0
            std::swap(nTmp, nTmpEnd);
499
0
        }
500
501
0
        while ( nTmp && nTmp <= nTmpEnd ) // guard against overflow
502
0
        {
503
            // Iterate over the Range and set the Items
504
0
            sal_uInt16 nWh = pPool->GetWhichIDFromSlotID(nTmp);
505
0
            m_xExampleSet->ClearItem(nWh);
506
0
            aTmpSet.ClearItem(nWh);
507
            // At the Outset of InvalidateItem,
508
            // so that the change takes effect
509
0
            m_pOutSet->InvalidateItem(nWh);
510
0
            nTmp++;
511
0
        }
512
0
    }
513
    // Set all Items as new  -> the call the current Page Reset()
514
0
    assert((*it)->xTabPage && "the Page is gone");
515
0
    (*it)->xTabPage->Reset(&aTmpSet);
516
0
    (*it)->xTabPage->mpImpl->mbStandard = true;
517
0
}
518
519
IMPL_LINK(SfxTabDialogController, ActivatePageHdl, const OUString&, rPage, void)
520
0
{
521
0
    ActivatePage(rPage);
522
0
}
523
524
void SfxTabDialogController::ActivatePage(const OUString& rPage)
525
/*  [Description]
526
527
    Handler that is called by StarView for switching to a different page.
528
    If possible the <SfxTabPage::Reset(const SfxItemSet &)> or
529
    <SfxTabPage::ActivatePage(const SfxItemSet &)> is called on the new page
530
*/
531
532
0
{
533
0
    assert(!m_pImpl->aData.empty() && "no Pages registered");
534
0
    auto it = Find(m_pImpl->aData, rPage);
535
0
    if (it == m_pImpl->aData.end())
536
0
    {
537
0
        SAL_WARN("sfx.dialog", "Tab Page ID '" << rPage << "' not known, this is pretty serious and needs investigation");
538
0
        return;
539
0
    }
540
541
0
    SfxTabPage* pTabPage = (*it)->xTabPage.get();
542
0
    if (!pTabPage)
543
0
        return;
544
545
0
    if ((*it)->bRefresh)
546
0
        pTabPage->Reset(m_pSet.get());
547
0
    (*it)->bRefresh = false;
548
549
0
    if (m_xExampleSet)
550
0
        pTabPage->ActivatePage(*m_xExampleSet);
551
552
0
    if (pTabPage->IsReadOnly() || m_pImpl->bHideResetBtn)
553
0
        m_xResetBtn->hide();
554
0
    else
555
0
        m_xResetBtn->show();
556
0
}
557
558
IMPL_LINK(SfxTabDialogController, DeactivatePageHdl, const OUString&, rPage, bool)
559
0
{
560
0
    return DeactivatePage(rPage);
561
0
}
562
563
bool SfxTabDialogController::DeactivatePage(std::u16string_view aPage)
564
/*  [Description]
565
566
    Handler that is called by StarView before leaving a page.
567
568
    [Cross-reference]
569
570
    <SfxTabPage::DeactivatePage(SfxItemSet *)>
571
*/
572
573
0
{
574
0
    assert(!m_pImpl->aData.empty() && "no Pages registered");
575
0
    auto it = Find(m_pImpl->aData, aPage);
576
0
    if (it == m_pImpl->aData.end())
577
0
    {
578
0
        SAL_WARN("sfx.dialog", "Tab Page ID not known, this is pretty serious and needs investigation");
579
0
        return false;
580
0
    }
581
582
0
    SfxTabPage* pPage = (*it)->xTabPage.get();
583
0
    if (!pPage)
584
0
        return true;
585
586
0
    DeactivateRC nRet = DeactivateRC::LeavePage;
587
588
0
    if (!m_xExampleSet && pPage->HasExchangeSupport() && m_pSet)
589
0
        m_xExampleSet.reset(new SfxItemSet(*m_pSet->GetPool(), m_pSet->GetRanges()));
590
591
0
    if (m_pSet)
592
0
    {
593
0
        SfxItemSet aTmp( *m_pSet->GetPool(), m_pSet->GetRanges() );
594
595
0
        if (pPage->HasExchangeSupport())
596
0
            nRet = pPage->DeactivatePage(&aTmp);
597
0
        else
598
0
            nRet = pPage->DeactivatePage(nullptr);
599
0
        if ( ( DeactivateRC::LeavePage & nRet ) == DeactivateRC::LeavePage &&
600
0
             aTmp.Count() && m_xExampleSet)
601
0
        {
602
0
            m_xExampleSet->Put( aTmp );
603
0
            m_pOutSet->Put( aTmp );
604
0
        }
605
0
    }
606
0
    else
607
0
    {
608
0
        if ( pPage->HasExchangeSupport() ) //!!!
609
0
        {
610
0
            if (!m_xExampleSet)
611
0
            {
612
0
                SfxItemPool* pPool = pPage->GetItemSet().GetPool();
613
0
                m_xExampleSet.reset(new SfxItemSet(*pPool, GetInputRanges(*pPool)));
614
0
            }
615
0
            nRet = pPage->DeactivatePage(m_xExampleSet.get());
616
0
        }
617
0
        else
618
0
            nRet = pPage->DeactivatePage( nullptr );
619
0
    }
620
621
0
    if ( nRet & DeactivateRC::RefreshSet )
622
0
    {
623
0
        RefreshInputSet();
624
        // Flag all Pages as to be initialized as new
625
626
0
        for (auto const& elem : m_pImpl->aData)
627
0
        {
628
0
            elem->bRefresh = ( elem->xTabPage.get() != pPage ); // Do not refresh own Page anymore
629
0
        }
630
0
    }
631
0
    return static_cast<bool>(nRet & DeactivateRC::LeavePage);
632
0
}
633
634
bool SfxTabDialogController::PrepareLeaveCurrentPage()
635
0
{
636
0
    const OUString sId = m_xTabCtrl->get_current_page_ident();
637
0
    auto it = Find(m_pImpl->aData, sId);
638
0
    DBG_ASSERT(it != m_pImpl->aData.end(), "Id not known");
639
0
    SfxTabPage* pPage = it != m_pImpl->aData.end() ? (*it)->xTabPage.get() : nullptr;
640
641
0
    bool bEnd = !pPage;
642
643
0
    if ( pPage )
644
0
    {
645
0
        DeactivateRC nRet = DeactivateRC::LeavePage;
646
0
        if ( m_pSet )
647
0
        {
648
0
            SfxItemSet aTmp( *m_pSet->GetPool(), m_pSet->GetRanges() );
649
650
0
            if ( pPage->HasExchangeSupport() )
651
0
                nRet = pPage->DeactivatePage( &aTmp );
652
0
            else
653
0
                nRet = pPage->DeactivatePage( nullptr );
654
655
0
            if ( ( DeactivateRC::LeavePage & nRet ) == DeactivateRC::LeavePage
656
0
                 && aTmp.Count() )
657
0
            {
658
0
                m_xExampleSet->Put( aTmp );
659
0
                m_pOutSet->Put( aTmp );
660
0
            }
661
0
        }
662
0
        else
663
0
            nRet = pPage->DeactivatePage( nullptr );
664
0
        bEnd = nRet != DeactivateRC::KeepPage;
665
0
    }
666
667
0
    return bEnd;
668
0
}
669
670
void SfxTabDialogController::PrepareCancel()
671
0
{
672
0
    for (auto pDataObject : m_pImpl->aData)
673
0
    {
674
0
        if (!pDataObject->xTabPage)
675
0
            continue;
676
677
0
        SfxTabPage* pPage = pDataObject->xTabPage.get();
678
0
        pPage->SetCancelMode(true);
679
0
        pPage->DeactivatePage(nullptr);
680
0
    }
681
0
}
682
683
const WhichRangesContainer & SfxTabDialogController::GetInputRanges(const SfxItemPool& rPool)
684
685
/*  [Description]
686
687
    Makes the set over the range of all pages of the dialogue. Pages have the
688
    static method for querying their range in AddTabPage, ie deliver their
689
    sets onDemand.
690
691
    [Return value]
692
693
    Pointer to a null-terminated array of sal_uInt16. This array belongs to the
694
    dialog and is deleted when the dialogue is destroy.
695
696
    [Cross-reference]
697
698
    <SfxTabDialog::AddTabPage(sal_uInt16, CreateTabPage, GetTabPageRanges, bool)>
699
    <SfxTabDialog::AddTabPage(sal_uInt16, const String &, CreateTabPage, GetTabPageRanges, bool, sal_uInt16)>
700
    <SfxTabDialog::AddTabPage(sal_uInt16, const Bitmap &, CreateTabPage, GetTabPageRanges, bool, sal_uInt16)>
701
*/
702
703
0
{
704
0
    if ( m_pSet )
705
0
    {
706
0
        SAL_WARN( "sfx.dialog", "Set already exists!" );
707
0
        return m_pSet->GetRanges();
708
0
    }
709
710
0
    if ( !m_pRanges.empty() )
711
0
        return m_pRanges;
712
0
    SfxItemSet aUS(const_cast<SfxItemPool&>(rPool));
713
714
0
    for (auto const& elem : m_pImpl->aData)
715
0
    {
716
717
0
        if ( elem->fnGetRanges )
718
0
        {
719
0
            const WhichRangesContainer aTmpRanges = (elem->fnGetRanges)();
720
721
0
            for (const auto & rPair : aTmpRanges)
722
0
            {
723
0
                sal_uInt16 nWidFrom = rPool.GetWhichIDFromSlotID(rPair.first);
724
0
                sal_uInt16 nWidTo = rPool.GetWhichIDFromSlotID(rPair.second);
725
0
                aUS.MergeRange(nWidFrom, nWidTo); // Keep it valid
726
0
            }
727
0
        }
728
0
    }
729
730
0
    m_pRanges = aUS.GetRanges();
731
0
    return m_pRanges;
732
0
}
733
734
SfxTabDialogController::~SfxTabDialogController()
735
0
{
736
0
    SavePosAndId();
737
738
0
    for (auto & elem : m_pImpl->aData)
739
0
    {
740
0
        if ( elem->xTabPage )
741
0
        {
742
            // save settings of all pages (user data)
743
0
            elem->xTabPage->FillUserData();
744
0
            OUString aPageData( elem->xTabPage->GetUserData() );
745
0
            if ( !aPageData.isEmpty() )
746
0
            {
747
                // save settings of all pages (user data)
748
0
                SvtViewOptions aPageOpt(EViewType::TabPage, elem->xTabPage->GetConfigId());
749
0
                aPageOpt.SetUserItem( USERITEM_NAME, Any( aPageData ) );
750
0
            }
751
752
0
            elem->xTabPage.reset();
753
0
        }
754
0
        delete elem;
755
0
        elem = nullptr;
756
0
    }
757
0
}
758
759
short SfxTabDialogController::Ok()
760
761
/*  [Description]
762
763
    Ok handler for the Dialogue.
764
765
    Dialog's current location and current page are saved for the next time
766
    the dialog is shown.
767
768
    The OutputSet is created and for each page this or the special OutputSet
769
    is set by calling the method <SfxTabPage::FillItemSet(SfxItemSet &)>, to
770
    insert the entered data by the user into the set.
771
772
    [Return value]
773
774
    RET_OK:       if at least one page has returned from FillItemSet,
775
                  otherwise RET_CANCEL.
776
*/
777
0
{
778
0
    SavePosAndId(); //See fdo#38828 "Apply" resetting window position
779
780
0
    if ( !m_pOutSet )
781
0
    {
782
0
        if ( m_xExampleSet )
783
0
            m_pOutSet.reset(new SfxItemSet( *m_xExampleSet ));
784
0
        else if ( m_pSet )
785
0
            m_pOutSet = m_pSet->Clone( false );  // without Items
786
0
    }
787
0
    bool bModified = false;
788
789
0
    for (auto const& elem : m_pImpl->aData)
790
0
    {
791
0
        SfxTabPage* pTabPage = elem->xTabPage.get();
792
793
0
        if ( pTabPage )
794
0
        {
795
0
            if ( m_pSet && !pTabPage->HasExchangeSupport() )
796
0
            {
797
0
                SfxItemSet aTmp( *m_pSet->GetPool(), m_pSet->GetRanges() );
798
799
0
                if ( pTabPage->FillItemSet( &aTmp ) )
800
0
                {
801
0
                    bModified = true;
802
0
                    if (m_xExampleSet)
803
0
                        m_xExampleSet->Put( aTmp );
804
0
                    m_pOutSet->Put( aTmp );
805
0
                }
806
0
            }
807
0
        }
808
0
    }
809
810
0
    if (m_pOutSet && m_pOutSet->Count() > 0)
811
0
        bModified = true;
812
813
0
    if (m_bStandardPushed)
814
0
        bModified = true;
815
816
0
    return bModified ? RET_OK : RET_CANCEL;
817
0
}
818
819
void SfxTabDialogController::RefreshInputSet()
820
821
/*  [Description]
822
823
    Default implementation of the virtual Method.
824
    This is called, when <SfxTabPage::DeactivatePage(SfxItemSet *)>
825
    returns <DeactivateRC::RefreshSet>.
826
*/
827
828
0
{
829
0
    SAL_INFO ( "sfx.dialog", "RefreshInputSet not implemented" );
830
0
}
831
832
void SfxTabDialogController::PageCreated
833
834
/*  [Description]
835
836
    Default implementation of the virtual method. This is called immediately
837
    after creating a page. Here the dialogue can call the TabPage Method
838
    directly.
839
*/
840
841
(
842
    const OUString&, // Id of the created page
843
    SfxTabPage&     // Reference to the created page
844
)
845
0
{
846
0
}
847
848
void SfxTabDialogController::SavePosAndId()
849
0
{
850
    // save settings (screen position and current page)
851
0
    SvtViewOptions aDlgOpt(EViewType::TabDialog, m_xDialog->get_help_id());
852
0
    aDlgOpt.SetPageID(m_xTabCtrl->get_current_page_ident());
853
0
}
854
855
/*
856
    Adds a page to the dialog. The Name must correspond to an entry in the
857
    TabControl in the dialog .ui
858
*/
859
void SfxTabDialogController::AddTabPage(const OUString &rName /* Page ID */,
860
                                        CreateTabPage pCreateFunc  /* Pointer to the Factory Method */,
861
                                        GetTabPageRanges pRangesFunc /* Pointer to the Method for querying Ranges onDemand */)
862
0
{
863
0
    m_pImpl->aData.push_back(new Data_Impl(rName, pCreateFunc, pRangesFunc));
864
0
}
865
866
void SfxTabDialogController::AddTabPage(const OUString &rName /* Page ID */,
867
                                        sal_uInt16 nPageCreateId /* Identifier of the Factory Method to create the page */)
868
0
{
869
0
    SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
870
0
    CreateTabPage pCreateFunc = pFact->GetTabPageCreatorFunc(nPageCreateId);
871
0
    GetTabPageRanges pRangesFunc = pFact->GetTabPageRangesFunc(nPageCreateId);
872
0
    AddTabPage(rName, pCreateFunc, pRangesFunc);
873
0
}
874
875
/*  [Description]
876
877
    Add a page to the dialog. The Rider text is passed on, the page has no
878
    counterpart in the TabControl in the resource of the dialogue.
879
*/
880
881
void SfxTabDialogController::AddTabPage(const OUString &rName, /* Page ID */
882
                                        const OUString& rRiderText,
883
                                        CreateTabPage pCreateFunc, /* Pointer to the Factory Method */
884
                                        const OUString* pIconName)
885
0
{
886
0
    assert(!m_xTabCtrl->get_page(rName) && "Double Page-Ids in the Tabpage");
887
0
    AddTabPage(rName, pCreateFunc, nullptr);
888
0
    m_xTabCtrl->append_page(rName, rRiderText, pIconName);
889
0
}
890
891
void SfxTabDialogController::AddTabPage(const OUString &rName, /* Page ID */
892
                                        const OUString& rRiderText,
893
                                        CreateTabPage pCreateFunc, /* Pointer to the Factory Method */
894
                                        GetTabPageRanges pRangesFunc,
895
                                        const OUString& rIconName)
896
0
{
897
0
    assert(!m_xTabCtrl->get_page(rName) && "Double Page-Ids in the Tabpage");
898
0
    AddTabPage(rName, pCreateFunc, pRangesFunc);
899
0
    m_xTabCtrl->append_page(rName, rRiderText, &rIconName);
900
0
}
901
902
void SfxTabDialogController::AddTabPage(const OUString &rName,
903
                                        const OUString& rRiderText,
904
                                        CreateTabPage pCreateFunc,
905
                                        const OUString& rIconName)
906
0
{
907
0
    AddTabPage(rName, rRiderText, pCreateFunc, &rIconName);
908
0
}
909
910
void SfxTabDialogController::AddTabPage(const OUString &rName, const OUString& rRiderText,
911
                                        sal_uInt16 nPageCreateId, /* Identifier of the Factory Method to create the page */
912
                                        const OUString* pIconName)
913
0
{
914
0
    assert(!m_xTabCtrl->get_page(rName) && "Double Page-Ids in the Tabpage");
915
0
    AddTabPage(rName, nPageCreateId);
916
0
    m_xTabCtrl->append_page(rName, rRiderText, pIconName);
917
0
}
918
919
void SfxTabDialogController::AddTabPage(const OUString &rName, const OUString& rRiderText,
920
                                        sal_uInt16 nPageCreateId,
921
                                        const OUString& rIconName)
922
0
{
923
0
    AddTabPage(rName, rRiderText, nPageCreateId, &rIconName);
924
0
}
925
926
/*  [Description]
927
928
    Default implementation of the virtual Method.
929
    This is called when pages create their sets onDemand.
930
*/
931
SfxItemSet* SfxTabDialogController::CreateInputItemSet(const OUString&)
932
0
{
933
0
    SAL_WARN( "sfx.dialog", "CreateInputItemSet not implemented" );
934
0
    m_xItemSet = std::make_unique<SfxAllItemSet>(SfxGetpApp()->GetPool());
935
0
    return m_xItemSet.get();
936
0
}
937
938
void SfxTabDialogController::CreatePages()
939
0
{
940
0
    for (auto pDataObject : m_pImpl->aData)
941
0
    {
942
0
        if (pDataObject->xTabPage)
943
0
           continue;
944
0
        weld::Container* pPage = m_xTabCtrl->get_page(pDataObject->sId);
945
0
        if (m_pSet)
946
0
            pDataObject->xTabPage = (pDataObject->fnCreatePage)(pPage, this, m_pSet.get());
947
0
        else
948
0
            pDataObject->xTabPage = (pDataObject->fnCreatePage)(pPage, this, CreateInputItemSet(pDataObject->sId));
949
0
        pDataObject->xTabPage->SetDialogController(this);
950
0
        SvtViewOptions aPageOpt(EViewType::TabPage, pDataObject->xTabPage->GetConfigId());
951
0
        OUString sUserData;
952
0
        Any aUserItem = aPageOpt.GetUserItem(USERITEM_NAME);
953
0
        OUString aTemp;
954
0
        if ( aUserItem >>= aTemp )
955
0
            sUserData = aTemp;
956
0
        pDataObject->xTabPage->SetUserData(sUserData);
957
958
0
        PageCreated(pDataObject->sId, *pDataObject->xTabPage);
959
0
        if (pDataObject->xTabPage->DeferResetToFirstActivation())
960
0
            pDataObject->bRefresh = true; // Reset will be called in ActivatePageHdl
961
0
        else
962
0
            pDataObject->xTabPage->Reset(m_pSet.get());
963
0
    }
964
0
}
965
966
void SfxTabDialogController::setPreviewsToSamePlace()
967
0
{
968
    //where tab pages have the same basic layout with a preview on the right,
969
    //get both of their non-preview areas to request the same size so that the
970
    //preview appears in the same place in each one so flipping between tabs
971
    //isn't distracting as it jumps around
972
0
    std::vector<std::unique_ptr<weld::Widget>> aGrids;
973
0
    for (auto pDataObject : m_pImpl->aData)
974
0
    {
975
0
        if (!pDataObject->xTabPage)
976
0
            continue;
977
0
        if (!pDataObject->xTabPage->m_xBuilder)
978
0
            continue;
979
0
        std::unique_ptr<weld::Widget> pGrid = pDataObject->xTabPage->m_xBuilder->weld_widget(u"maingrid"_ustr);
980
0
        if (!pGrid)
981
0
            continue;
982
0
        aGrids.emplace_back(std::move(pGrid));
983
0
    }
984
985
0
    m_xSizeGroup.reset();
986
987
0
    if (aGrids.size() <= 1)
988
0
        return;
989
990
0
    m_xSizeGroup = m_xBuilder->create_size_group();
991
0
    m_xSizeGroup->set_mode(VclSizeGroupMode::Both);
992
0
    for (auto& rGrid : aGrids)
993
0
        m_xSizeGroup->add_widget(rGrid.get());
994
0
}
995
996
void SfxTabDialogController::RemoveTabPage(const OUString& rId)
997
998
/*  [Description]
999
1000
    Delete the TabPage with ID nId
1001
*/
1002
1003
0
{
1004
0
    m_xTabCtrl->remove_page(rId);
1005
0
    auto it = Find(m_pImpl->aData, rId);
1006
1007
0
    if (it != m_pImpl->aData.end())
1008
0
    {
1009
0
        if ((*it)->xTabPage)
1010
0
        {
1011
0
            (*it)->xTabPage->FillUserData();
1012
0
            OUString aPageData((*it)->xTabPage->GetUserData());
1013
0
            if ( !aPageData.isEmpty() )
1014
0
            {
1015
                // save settings of this page (user data)
1016
0
                SvtViewOptions aPageOpt(EViewType::TabPage, (*it)->xTabPage->GetConfigId());
1017
0
                aPageOpt.SetUserItem( USERITEM_NAME, Any( aPageData ) );
1018
0
            }
1019
1020
0
            (*it)->xTabPage.reset();
1021
0
        }
1022
1023
0
        delete *it;
1024
0
        m_pImpl->aData.erase(it);
1025
0
    }
1026
0
    else
1027
0
    {
1028
0
        SAL_INFO( "sfx.dialog", "TabPage-Id not known" );
1029
0
    }
1030
0
}
1031
1032
void SfxTabDialogController::Start_Impl()
1033
0
{
1034
0
    CreatePages();
1035
1036
0
    setPreviewsToSamePlace();
1037
1038
0
    assert(m_pImpl->aData.size() == static_cast<size_t>(m_xTabCtrl->get_n_pages())
1039
0
            && "not all pages registered");
1040
1041
    // load old settings, when exists, setting SetCurPageId will override the settings,
1042
    // something that the sort dialog in calc depends on
1043
0
    if (m_sAppPageId.isEmpty())
1044
0
    {
1045
0
        int nInitialPage = 0;
1046
0
        SvtViewOptions aDlgOpt(EViewType::TabDialog, m_xDialog->get_help_id());
1047
0
        if (aDlgOpt.Exists())
1048
0
        {
1049
0
            const int nIndex = m_xTabCtrl->get_page_index(aDlgOpt.GetPageID());
1050
0
            if (nIndex >= 0)
1051
0
                nInitialPage = nIndex;
1052
0
        }
1053
0
        m_xTabCtrl->set_current_page(nInitialPage);
1054
0
    }
1055
1056
0
    ActivatePage(m_xTabCtrl->get_current_page_ident());
1057
1058
0
    m_pImpl->bStarted = true;
1059
0
}
1060
1061
void SfxTabDialogController::SetCurPageId(const OUString& rIdent)
1062
0
{
1063
0
    m_sAppPageId = rIdent;
1064
0
    m_xTabCtrl->set_current_page(m_sAppPageId);
1065
0
}
1066
1067
/*  [Description]
1068
1069
    The TabPage is activated with the specified Id.
1070
*/
1071
void SfxTabDialogController::ShowPage(const OUString& rIdent)
1072
0
{
1073
0
    SetCurPageId(rIdent);
1074
0
    ActivatePage(rIdent);
1075
0
}
1076
1077
OUString SfxTabDialogController::GetCurPageId() const
1078
0
{
1079
0
    return m_xTabCtrl->get_current_page_ident();
1080
0
}
1081
1082
short SfxTabDialogController::run()
1083
0
{
1084
0
    Start_Impl();
1085
0
    return SfxDialogController::run();
1086
0
}
1087
1088
bool SfxTabDialogController::runAsync(const std::shared_ptr<SfxTabDialogController>& rController,
1089
                                      const std::function<void(sal_Int32)>& rFunc)
1090
0
{
1091
0
    rController->Start_Impl();
1092
0
    return weld::DialogController::runAsync(rController, rFunc);
1093
0
}
1094
1095
void SfxTabDialogController::SetInputSet( const SfxItemSet* pInSet )
1096
1097
/*  [Description]
1098
1099
    With this method the Input-Set can subsequently be set initially or re-set.
1100
*/
1101
1102
0
{
1103
0
    bool bSet = ( m_pSet != nullptr );
1104
0
    m_pSet.reset(pInSet ? new SfxItemSet(*pInSet) : nullptr);
1105
1106
0
    if (!bSet && !m_xExampleSet && !m_pOutSet && m_pSet)
1107
0
    {
1108
0
        m_xExampleSet.reset(new SfxItemSet(*m_pSet));
1109
0
        m_pOutSet.reset(new SfxItemSet( *m_pSet->GetPool(), m_pSet->GetRanges() ));
1110
0
    }
1111
0
}
1112
1113
SfxItemSet* SfxTabDialogController::GetInputSetImpl()
1114
1115
/*  [Description]
1116
1117
    Derived classes may create new storage for the InputSet. This has to be
1118
    released in the Destructor. To do this, this method must be called.
1119
*/
1120
1121
0
{
1122
0
    return m_pSet.get();
1123
0
}
1124
1125
void SfxTabDialogController::RemoveResetButton()
1126
0
{
1127
0
    m_xResetBtn->hide();
1128
0
    m_pImpl->bHideResetBtn = true;
1129
0
}
1130
1131
void SfxTabDialogController::RemoveStandardButton()
1132
0
{
1133
0
    m_xBaseFmtBtn->hide();
1134
0
}
1135
1136
SfxTabPage* SfxTabDialogController::GetTabPage(std::u16string_view rPageId) const
1137
1138
/*  [Description]
1139
1140
    Return TabPage with the specified Id.
1141
*/
1142
1143
0
{
1144
0
    auto it = Find(m_pImpl->aData, rPageId);
1145
0
    if (it != m_pImpl->aData.end())
1146
0
        return (*it)->xTabPage.get();
1147
0
    return nullptr;
1148
0
}
1149
1150
void SfxTabDialogController::SetApplyHandler(const Link<weld::Button&, void>& _rHdl)
1151
0
{
1152
0
    DBG_ASSERT( m_xApplyBtn, "SfxTabDialog::GetApplyHandler: no apply button enabled!" );
1153
0
    if (m_xApplyBtn)
1154
0
        m_xApplyBtn->connect_clicked(_rHdl);
1155
0
}
1156
1157
bool SfxTabDialogController::Apply()
1158
0
{
1159
0
    bool bApplied = false;
1160
0
    if (PrepareLeaveCurrentPage())
1161
0
    {
1162
0
        bApplied = (Ok() == RET_OK);
1163
        //let the pages update their saved values
1164
0
        GetInputSetImpl()->Put(*GetOutputItemSet());
1165
0
        for (auto pDataObject : m_pImpl->aData)
1166
0
        {
1167
0
            if (!pDataObject->xTabPage)
1168
0
                continue;
1169
0
            pDataObject->xTabPage->ChangesApplied();
1170
0
        }
1171
0
    }
1172
0
    return bApplied;
1173
0
}
1174
1175
std::vector<OUString> SfxTabDialogController::getAllPageUIXMLDescriptions() const
1176
0
{
1177
0
    int nPages = m_xTabCtrl->get_n_pages();
1178
0
    std::vector<OUString> aRet;
1179
0
    aRet.reserve(nPages);
1180
0
    for (int i = 0; i < nPages; ++i)
1181
0
        aRet.push_back(m_xTabCtrl->get_page_ident(i));
1182
0
    return aRet;
1183
0
}
1184
1185
bool SfxTabDialogController::selectPageByUIXMLDescription(const OUString& rUIXMLDescription)
1186
0
{
1187
0
    ShowPage(rUIXMLDescription);
1188
0
    return m_xTabCtrl->get_current_page_ident() == rUIXMLDescription;
1189
0
}
1190
1191
Bitmap SfxTabDialogController::createScreenshot() const
1192
0
{
1193
    // if we haven't run Start_Impl yet, do so now to create the initial pages
1194
0
    if (!m_pImpl->bStarted)
1195
0
    {
1196
0
        const_cast<SfxTabDialogController*>(this)->Start_Impl();
1197
0
    }
1198
1199
0
    VclPtr<VirtualDevice> xDialogSurface(m_xDialog->screenshot());
1200
0
    return xDialogSurface->GetBitmap(Point(), xDialogSurface->GetOutputSizePixel());
1201
0
}
1202
1203
OUString SfxTabDialogController::GetScreenshotId() const
1204
0
{
1205
0
    const OUString sId = m_xTabCtrl->get_current_page_ident();
1206
0
    auto it = Find(m_pImpl->aData, sId);
1207
0
    SfxTabPage* pPage = it != m_pImpl->aData.end() ? (*it)->xTabPage.get() : nullptr;
1208
0
    if (pPage)
1209
0
    {
1210
0
        OUString sHelpId(pPage->GetHelpId());
1211
0
        if (!sHelpId.isEmpty())
1212
0
            return sHelpId;
1213
0
    }
1214
0
    return m_xDialog->get_help_id();
1215
0
}
1216
1217
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */