Coverage Report

Created: 2025-07-07 10:01

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