Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/dialog/basedlgs.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
#include <vcl/help.hxx>
21
#include <svl/eitem.hxx>
22
#include <unotools/viewoptions.hxx>
23
#include <vcl/idle.hxx>
24
#include <vcl/weld/Builder.hxx>
25
#include <vcl/weld/Dialog.hxx>
26
#include <vcl/windowstate.hxx>
27
28
#include <sfx2/basedlgs.hxx>
29
#include <sfx2/tabdlg.hxx>
30
#include <sfx2/bindings.hxx>
31
#include <sfx2/dispatch.hxx>
32
#include <sfx2/childwin.hxx>
33
#include <sfx2/viewsh.hxx>
34
#include <workwin.hxx>
35
#include <comphelper/lok.hxx>
36
37
using namespace ::com::sun::star::uno;
38
39
constexpr OUString USERITEM_NAME = u"UserItem"_ustr;
40
41
class SfxModelessDialog_Impl : public SfxListener
42
{
43
public:
44
    OUString aWinState;
45
    SfxChildWindow* pMgr;
46
    bool            bClosing;
47
    void            Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
48
49
    Idle            aMoveIdle { "SfxModelessDialog_Impl aMoveIdle" };
50
};
51
52
void SfxModelessDialog_Impl::Notify( SfxBroadcaster&, const SfxHint& rHint )
53
0
{
54
0
    if (pMgr && rHint.GetId() == SfxHintId::Dying) {
55
0
        pMgr->Destroy();
56
0
    }
57
0
}
58
59
void SfxModelessDialogController::Initialize(SfxChildWinInfo const *pInfo)
60
61
/*  [Description]
62
63
    Initialization of the class SfxModelessDialog via a SfxChildWinInfo.
64
    The initialization is done only in a 2nd step after the constructor, this
65
    constructor should be called from the derived class or from the
66
    SfxChildWindows.
67
*/
68
69
0
{
70
0
    if (!pInfo)
71
0
        return;
72
0
    m_xImpl->aWinState = pInfo->aWinState;
73
0
    if (m_xImpl->aWinState.isEmpty())
74
0
        return;
75
0
    m_xDialog->set_window_state(m_xImpl->aWinState);
76
0
}
77
78
SfxModelessDialogController::SfxModelessDialogController(SfxBindings* pBindinx,
79
    SfxChildWindow *pCW, weld::Window *pParent, const OUString& rUIXMLDescription,
80
    const OUString& rID)
81
0
    : SfxDialogController(pParent, rUIXMLDescription, rID)
82
0
{
83
0
    Init(pBindinx, pCW);
84
0
}
85
86
/*  [Description]
87
88
    Fills a SfxChildWinInfo with specific data from SfxModelessDialog,
89
    so that it can be written in the INI file. It is assumed that rinfo
90
    receives all other possible relevant data in the ChildWindow class.
91
    ModelessDialogs have no specific information, so that the base
92
    implementation does nothing and therefore must not be called.
93
*/
94
void SfxModelessDialogController::FillInfo(SfxChildWinInfo& rInfo) const
95
0
{
96
0
    rInfo.aSize = m_xDialog->get_size();
97
0
}
98
99
void SfxModelessDialogController::Init(SfxBindings *pBindinx, SfxChildWindow *pCW)
100
0
{
101
0
    m_pBindings = pBindinx;
102
0
    m_xImpl.reset(new SfxModelessDialog_Impl);
103
0
    m_xImpl->pMgr = pCW;
104
0
    m_xImpl->bClosing = false;
105
0
    if (pBindinx)
106
0
        m_xImpl->StartListening( *pBindinx );
107
0
}
108
109
/*  [Description]
110
111
    If a ModelessDialog is enabled its ViewFrame will be activated.
112
    This is necessary by PluginInFrames.
113
*/
114
IMPL_LINK_NOARG(SfxDialogController, FocusChangeHdl, weld::Container&, void)
115
0
{
116
0
    if (m_xDialog->has_toplevel_focus())
117
0
        Activate();
118
0
    else
119
0
        Deactivate();
120
0
}
121
122
void SfxModelessDialogController::Activate()
123
0
{
124
0
    if (!m_xImpl || !m_xImpl->pMgr)
125
0
        return;
126
0
    m_pBindings->SetActiveFrame(m_xImpl->pMgr->GetFrame());
127
0
    m_xImpl->pMgr->Activate_Impl();
128
0
}
129
130
void SfxModelessDialogController::Deactivate()
131
0
{
132
0
    if (!m_xImpl)
133
0
        return;
134
0
    m_pBindings->SetActiveFrame(css::uno::Reference< css::frame::XFrame>());
135
0
}
136
137
SfxModelessDialogController::~SfxModelessDialogController()
138
0
{
139
0
    if (!m_xImpl->pMgr)
140
0
        return;
141
0
    auto xFrame = m_xImpl->pMgr->GetFrame();
142
0
    if (!xFrame)
143
0
        return;
144
0
    if (xFrame == m_pBindings->GetActiveFrame())
145
0
        m_pBindings->SetActiveFrame(nullptr);
146
0
}
147
148
void SfxDialogController::EndDialog(int nResponse)
149
0
{
150
0
    if (!m_xDialog->get_visible())
151
0
        return;
152
0
    response(nResponse);
153
0
}
154
155
bool SfxModelessDialogController::IsClosing() const
156
0
{
157
0
    return m_xImpl->bClosing;
158
0
}
159
160
void SfxModelessDialogController::EndDialog(int nResponse)
161
0
{
162
0
    if (m_xImpl->bClosing)
163
0
        return;
164
    // In the case of async dialogs, the call to SfxDialogController::EndDialog
165
    // may delete this object, so keep myself alive for the duration of this
166
    // stack frame.
167
0
    auto aHoldSelf = shared_from_this();
168
0
    m_xImpl->bClosing = true;
169
0
    SfxDialogController::EndDialog(nResponse);
170
0
    if (!m_xImpl)
171
0
        return;
172
0
    m_xImpl->bClosing = false;
173
0
}
174
175
void SfxModelessDialogController::ChildWinDispose()
176
0
{
177
0
    if (m_xImpl->pMgr)
178
0
    {
179
0
        vcl::WindowDataMask nMask = vcl::WindowDataMask::Pos | vcl::WindowDataMask::State;
180
0
        if (m_xDialog->get_resizable())
181
0
            nMask |= vcl::WindowDataMask::Size;
182
0
        m_xImpl->aWinState = m_xDialog->get_window_state(nMask);
183
0
        GetBindings().GetWorkWindow_Impl()->ConfigChild_Impl( SfxChildIdentifier::DOCKINGWINDOW, SfxDockingConfig::ALIGNDOCKINGWINDOW, m_xImpl->pMgr->GetType() );
184
0
    }
185
186
0
    m_xImpl->pMgr = nullptr;
187
0
}
188
189
/*  [Description]
190
191
    The window is closed when the ChildWindow is destroyed by running the
192
    ChildWindow-slots.
193
*/
194
void SfxModelessDialogController::Close()
195
0
{
196
0
    if (m_xImpl->bClosing)
197
0
        return;
198
    // Execute with Parameters, since Toggle is ignored by some ChildWindows.
199
0
    SfxBoolItem aValue(m_xImpl->pMgr->GetType(), false);
200
0
    m_pBindings->GetDispatcher_Impl()->ExecuteList(
201
0
        m_xImpl->pMgr->GetType(),
202
0
        SfxCallMode::RECORD|SfxCallMode::SYNCHRON, { &aValue } );
203
0
    SfxDialogController::Close();
204
0
}
205
206
static bool isLOKMobilePhone()
207
0
{
208
0
    if (!comphelper::LibreOfficeKit::isActive())
209
0
        return false;
210
0
    const SfxViewShell* pCurrentShell = SfxViewShell::Current();
211
0
    return pCurrentShell && pCurrentShell->isLOKMobilePhone();
212
0
}
213
214
SfxDialogController::SfxDialogController(weld::Widget* pParent, const OUString& rUIFile,
215
                                         const OUString& rDialogId)
216
0
    : GenericDialogController(pParent, rUIFile, rDialogId, isLOKMobilePhone())
217
0
{
218
0
    m_xDialog->SetInstallLOKNotifierHdl(LINK(this, SfxDialogController, InstallLOKNotifierHdl));
219
0
    m_xDialog->connect_container_focus_changed(LINK(this, SfxDialogController, FocusChangeHdl));
220
0
}
221
222
void SfxDialogController::Close()
223
0
{
224
    // tdf3146571 ignore focus changes after we've closed
225
0
    m_xDialog->connect_container_focus_changed(Link<weld::Container&, void>());
226
0
}
227
228
IMPL_STATIC_LINK_NOARG(SfxDialogController, InstallLOKNotifierHdl, void*, vcl::ILibreOfficeKitNotifier*)
229
0
{
230
0
    return SfxViewShell::Current();
231
0
}
232
233
SfxSingleTabDialogController::SfxSingleTabDialogController(weld::Widget *pParent, const SfxItemSet* pSet,
234
    const OUString& rUIXMLDescription, const OUString& rID)
235
0
    : SfxOkDialogController(pParent, rUIXMLDescription, rID)
236
0
    , m_pInputSet(pSet)
237
0
    , m_xContainer(m_xDialog->weld_content_area())
238
0
    , m_xOKBtn(m_xBuilder->weld_button(u"ok"_ustr))
239
0
{
240
0
    m_xOKBtn->connect_clicked(LINK(this, SfxSingleTabDialogController, OKHdl_Impl));
241
0
}
242
243
SfxSingleTabDialogController::SfxSingleTabDialogController(weld::Widget *pParent, const SfxItemSet* pSet,
244
    const OUString& rContainerId, const OUString& rUIXMLDescription, const OUString& rID)
245
0
    : SfxOkDialogController(pParent, rUIXMLDescription, rID)
246
0
    , m_pInputSet(pSet)
247
0
    , m_xContainer(m_xBuilder->weld_container(rContainerId))
248
0
    , m_xOKBtn(m_xBuilder->weld_button(u"ok"_ustr))
249
0
{
250
0
    m_xOKBtn->connect_clicked(LINK(this, SfxSingleTabDialogController, OKHdl_Impl));
251
0
}
252
253
SfxSingleTabDialogController::~SfxSingleTabDialogController()
254
0
{
255
0
}
256
257
/*  [Description]
258
259
    Insert a (new) TabPage; an existing page is deleted.
260
    The passed on page is initialized with the initially given Itemset
261
    through calling Reset().
262
*/
263
void SfxSingleTabDialogController::SetTabPage(std::unique_ptr<SfxTabPage> xTabPage)
264
0
{
265
0
    m_xSfxPage = std::move(xTabPage);
266
0
    if (!m_xSfxPage)
267
0
        return;
268
269
    // First obtain the user data, only then Reset()
270
0
    OUString sConfigId = m_xSfxPage->GetConfigId();
271
0
    SvtViewOptions aPageOpt(EViewType::TabPage, sConfigId);
272
0
    Any aUserItem = aPageOpt.GetUserItem( USERITEM_NAME );
273
0
    OUString sUserData;
274
0
    aUserItem >>= sUserData;
275
0
    m_xSfxPage->SetUserData(sUserData);
276
0
    m_xSfxPage->Reset(GetInputItemSet());
277
278
    // Set TabPage text in the Dialog if there is any
279
0
    OUString sTitle(m_xSfxPage->GetPageTitle());
280
0
    if (!sTitle.isEmpty())
281
0
        m_xDialog->set_title(sTitle);
282
283
    // Dialog receives the HelpId of TabPage if there is any
284
0
    OUString sHelpId(m_xSfxPage->GetHelpId());
285
0
    if (!sHelpId.isEmpty())
286
0
        m_xDialog->set_help_id(sHelpId);
287
0
}
288
289
/*  [Description]
290
291
    Ok_Handler; FillItemSet() is called for setting of Page.
292
*/
293
IMPL_LINK_NOARG(SfxSingleTabDialogController, OKHdl_Impl, weld::Button&, void)
294
0
{
295
0
    const SfxItemSet* pInputSet = GetInputItemSet();
296
0
    if (!pInputSet)
297
0
    {
298
        // TabPage without ItemSet
299
0
        m_xDialog->response(RET_OK);
300
0
        return;
301
0
    }
302
303
0
    if (!GetOutputItemSet())
304
0
    {
305
0
        CreateOutputItemSet(*pInputSet);
306
0
    }
307
308
0
    bool bModified = false;
309
310
0
    if (m_xSfxPage->HasExchangeSupport())
311
0
    {
312
0
        DeactivateRC nRet = m_xSfxPage->DeactivatePage(m_xOutputSet.get());
313
0
        if (nRet != DeactivateRC::LeavePage)
314
0
            return;
315
0
        else
316
0
            bModified = m_xOutputSet->Count() > 0;
317
0
    }
318
0
    else
319
0
        bModified = m_xSfxPage->FillItemSet(m_xOutputSet.get());
320
321
0
    if (bModified)
322
0
    {
323
        // Save user data in IniManager.
324
0
        m_xSfxPage->FillUserData();
325
0
        OUString sData(m_xSfxPage->GetUserData());
326
327
0
        OUString sConfigId = m_xSfxPage->GetConfigId();
328
0
        SvtViewOptions aPageOpt(EViewType::TabPage, sConfigId);
329
0
        aPageOpt.SetUserItem( USERITEM_NAME, Any( sData ) );
330
0
        m_xDialog->response(RET_OK);
331
0
    }
332
0
    else
333
0
        m_xDialog->response(RET_CANCEL);
334
0
}
335
336
void SfxSingleTabDialogController::CreateOutputItemSet(const SfxItemSet& rSet)
337
0
{
338
    assert(!m_xOutputSet && "Double creation of OutputSet!");
339
0
    m_xOutputSet.reset(new SfxItemSet(rSet));
340
0
    m_xOutputSet->ClearItem();
341
0
}
342
343
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */