Coverage Report

Created: 2026-07-10 11:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/uui/source/iahndl-errorhandler.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/errinf.hxx>
21
#include <vcl/svapp.hxx>
22
#include <vcl/stdtext.hxx>
23
#include <vcl/vclenum.hxx>
24
#include <vcl/weld/MessageDialog.hxx>
25
#include <vcl/wintypes.hxx>
26
27
#include <com/sun/star/task/XInteractionAbort.hpp>
28
#include <com/sun/star/task/XInteractionApprove.hpp>
29
#include <com/sun/star/task/XInteractionDisapprove.hpp>
30
#include <com/sun/star/task/XInteractionRetry.hpp>
31
32
#include <svx/svxerr.hxx>
33
#include <unotools/resmgr.hxx>
34
#include <osl/diagnose.h>
35
#include <rtl/ustrbuf.hxx>
36
37
#include <ids.hrc>
38
#include <strings.hrc>
39
#include "getcontinuations.hxx"
40
41
#include "iahndl.hxx"
42
#include <memory>
43
#include <string_view>
44
45
using namespace com::sun::star;
46
47
namespace {
48
49
enum class MessageBoxStyle {
50
    NONE              = 0x0000,
51
    Ok                = 0x0001,
52
    OkCancel          = 0x0002,
53
    YesNo             = 0x0004,
54
    YesNoCancel       = 0x0008,
55
    RetryCancel       = 0x0010
56
};
57
58
DialogMask
59
executeErrorDialog(
60
    weld::Window* pParent,
61
    task::InteractionClassification eClassification,
62
    std::u16string_view rContext,
63
    std::u16string_view rMessage,
64
    MessageBoxStyle nButtonMask)
65
0
{
66
0
    SolarMutexGuard aGuard;
67
68
0
    OUStringBuffer aText(rContext);
69
0
    if (!rContext.empty() && !rMessage.empty())
70
0
        aText.append(":\n");
71
            //TODO! must be internationalized
72
0
    aText.append(rMessage);
73
74
0
    std::unique_ptr<weld::MessageDialog> xBox;
75
76
0
    switch (eClassification)
77
0
    {
78
0
        case task::InteractionClassification_ERROR:
79
0
            xBox.reset(Application::CreateMessageDialog(pParent,
80
0
                        VclMessageType::Error, VclButtonsType::NONE, aText.makeStringAndClear()));
81
0
            break;
82
0
        case task::InteractionClassification_WARNING:
83
0
            xBox.reset(Application::CreateMessageDialog(pParent,
84
0
                        VclMessageType::Warning, VclButtonsType::NONE, aText.makeStringAndClear()));
85
0
            break;
86
0
        case task::InteractionClassification_INFO:
87
0
            xBox.reset(Application::CreateMessageDialog(pParent,
88
0
                        VclMessageType::Info, VclButtonsType::NONE, aText.makeStringAndClear()));
89
0
            break;
90
0
        case task::InteractionClassification_QUERY:
91
0
            xBox.reset(Application::CreateMessageDialog(pParent,
92
0
                        VclMessageType::Question, VclButtonsType::NONE, aText.makeStringAndClear()));
93
0
            break;
94
0
        default:
95
0
            assert(false);
96
0
            break;
97
0
    }
98
99
0
    switch (nButtonMask)
100
0
    {
101
0
        case MessageBoxStyle::NONE:
102
0
            break;
103
0
        case MessageBoxStyle::Ok:
104
0
            xBox->add_button(GetStandardText(StandardButtonType::OK), static_cast<int>(DialogMask::ButtonsOk));
105
0
            break;
106
0
        case MessageBoxStyle::OkCancel:
107
0
            xBox->add_button(GetStandardText(StandardButtonType::OK), static_cast<int>(DialogMask::ButtonsOk));
108
0
            xBox->add_button(GetStandardText(StandardButtonType::Cancel), static_cast<int>(DialogMask::ButtonsCancel));
109
0
            break;
110
0
        case MessageBoxStyle::YesNo:
111
0
            xBox->add_button(GetStandardText(StandardButtonType::Yes), static_cast<int>(DialogMask::ButtonsYes));
112
0
            xBox->add_button(GetStandardText(StandardButtonType::No), static_cast<int>(DialogMask::ButtonsNo));
113
0
            break;
114
0
        case MessageBoxStyle::YesNoCancel:
115
0
            xBox->add_button(GetStandardText(StandardButtonType::Yes), static_cast<int>(DialogMask::ButtonsYes));
116
0
            xBox->add_button(GetStandardText(StandardButtonType::No), static_cast<int>(DialogMask::ButtonsNo));
117
0
            xBox->add_button(GetStandardText(StandardButtonType::Cancel), static_cast<int>(DialogMask::ButtonsCancel));
118
0
            break;
119
0
        case MessageBoxStyle::RetryCancel:
120
0
            xBox->add_button(GetStandardText(StandardButtonType::Retry), static_cast<int>(DialogMask::ButtonsRetry));
121
0
            xBox->add_button(GetStandardText(StandardButtonType::Cancel), static_cast<int>(DialogMask::ButtonsCancel));
122
0
            break;
123
0
    }
124
125
0
    return static_cast<DialogMask>(xBox->run());
126
0
}
127
128
}
129
130
void
131
UUIInteractionHelper::handleErrorHandlerRequest(
132
    task::InteractionClassification eClassification,
133
    ErrCode nErrorCode,
134
    std::vector< OUString > const & rArguments,
135
    uno::Sequence< uno::Reference< task::XInteractionContinuation > > const &
136
        rContinuations,
137
    bool bObtainErrorStringOnly,
138
    bool & bHasErrorString,
139
    OUString & rErrorString)
140
0
{
141
0
    if (bObtainErrorStringOnly)
142
0
    {
143
0
        bHasErrorString = isInformationalErrorMessageRequest(rContinuations);
144
0
        if (!bHasErrorString)
145
0
            return;
146
0
    }
147
148
0
    OUString aMessage;
149
0
    {
150
0
        enum Source { SOURCE_DEFAULT, SOURCE_SVX, SOURCE_UUI };
151
0
        static char const * const aManager[3] = { "svt", "svx", "uui" };
152
0
        static const ErrMsgCode* const aId[3]
153
0
            = { RID_ERRHDL,
154
0
                RID_SVXERRCODE,
155
0
                RID_UUI_ERRHDL };
156
0
        ErrCodeArea nErrorArea = nErrorCode.GetArea();
157
0
        Source eSource =
158
0
            nErrorArea < ErrCodeArea::Svx ? SOURCE_DEFAULT
159
0
                : nErrorArea == ErrCodeArea::Svx ? SOURCE_SVX : SOURCE_UUI;
160
161
0
        std::locale aResLocale = Translate::Create(aManager[eSource]);
162
0
        ErrorResource aErrorResource(aId[eSource], aResLocale);
163
0
        if (!aErrorResource.getString(nErrorCode, aMessage))
164
0
            return;
165
0
        if (nErrorCode == ERRCODE_INET_CONNECT)
166
0
        {
167
0
            OUString aMessage2;
168
0
            aErrorResource.getString(ERRCODE_INET_CONNECT_MSG, aMessage2);
169
0
            if (!aMessage2.isEmpty() && !rArguments[1].isEmpty())
170
0
            {
171
0
                aMessage2 = replaceMessageWithArguments(aMessage2, rArguments);
172
0
                aMessage += "\n" + aMessage2;
173
0
            }
174
0
        }
175
0
    }
176
177
0
    aMessage = replaceMessageWithArguments( aMessage, rArguments );
178
179
0
    if (bObtainErrorStringOnly)
180
0
    {
181
0
        rErrorString = aMessage;
182
0
        return;
183
0
    }
184
0
    else
185
0
    {
186
        //TODO! It can happen that the buttons calculated below do not match
187
        // the error text from the resource (e.g., some text that is not a
188
        // question, but YES and NO buttons).  Some error texts have
189
        // ExtraData that specifies a set of buttons, but that data is not
190
        // really useful, because a single error text may well make sense
191
        // both with only an OK button and with RETRY and CANCEL buttons.
192
193
0
        uno::Reference< task::XInteractionApprove > xApprove;
194
0
        uno::Reference< task::XInteractionDisapprove > xDisapprove;
195
0
        uno::Reference< task::XInteractionRetry > xRetry;
196
0
        uno::Reference< task::XInteractionAbort > xAbort;
197
0
        getContinuations(
198
0
            rContinuations, &xApprove, &xDisapprove, &xRetry, &xAbort);
199
200
        // The following mapping uses the bit mask
201
        //     Approve = 8,
202
        //     Disapprove = 4,
203
        //     Retry = 2,
204
        //     Abort = 1
205
206
        // The mapping has five properties on which the code to select the
207
        // correct continuation relies:
208
        // 1  The OK button is mapped to Approve if that is available,
209
        //    otherwise to Abort if that is available, otherwise to none.
210
        // 2  The CANCEL button is always mapped to Abort.
211
        // 3  The RETRY button is always mapped to Retry.
212
        // 4  The NO button is always mapped to Disapprove.
213
        // 5  The YES button is always mapped to Approve.
214
215
        // Because the WinBits button combinations are quite restricted, not
216
        // every request can be served here.
217
218
        // Finally, it seems to be better to leave default button
219
        // determination to VCL (the favouring of CANCEL as default button
220
        // seems to not always be what the user wants)...
221
0
        MessageBoxStyle const aButtonMask[16]
222
0
            = { MessageBoxStyle::NONE,
223
0
                MessageBoxStyle::Ok /*| MessBoxStyle::DefaultOk*/, // Abort
224
0
                MessageBoxStyle::NONE,
225
0
                MessageBoxStyle::RetryCancel /*| MessBoxStyle::DefaultCancel*/, // Retry, Abort
226
0
                MessageBoxStyle::NONE,
227
0
                MessageBoxStyle::NONE,
228
0
                MessageBoxStyle::NONE,
229
0
                MessageBoxStyle::NONE,
230
0
                MessageBoxStyle::Ok /*| MessBoxStyle::DefaultOk*/, // Approve
231
0
                MessageBoxStyle::OkCancel /*| MessBoxStyle::DefaultCancel*/, // Approve, Abort
232
0
                MessageBoxStyle::NONE,
233
0
                MessageBoxStyle::NONE,
234
0
                MessageBoxStyle::YesNo /*| MessBoxStyle::DefaultNo*/, // Approve, Disapprove
235
0
                MessageBoxStyle::YesNoCancel /*| MessBoxStyle::DefaultCancel*/,
236
                // Approve, Disapprove, Abort
237
0
                MessageBoxStyle::NONE,
238
0
                MessageBoxStyle::NONE };
239
240
0
        MessageBoxStyle nButtonMask = aButtonMask[(xApprove.is() ? 8 : 0)
241
0
                                          | (xDisapprove.is() ? 4 : 0)
242
0
                                          | (xRetry.is() ? 2 : 0)
243
0
                                          | (xAbort.is() ? 1 : 0)];
244
0
        if (nButtonMask == MessageBoxStyle::NONE)
245
0
            return;
246
247
        //TODO! remove this backwards compatibility?
248
0
        OUString aContext(m_aContextParam);
249
0
        if (aContext.isEmpty() && nErrorCode != ERRCODE_NONE)
250
0
        {
251
0
            SolarMutexGuard aGuard;
252
0
            ErrorContext * pContext = ErrorContext::GetContext();
253
0
            if (pContext)
254
0
            {
255
0
                OUString aContextString;
256
0
                if (pContext->GetString(nErrorCode, aContextString))
257
0
                    aContext = aContextString;
258
0
            }
259
0
        }
260
261
0
        uno::Reference<awt::XWindow> xParent = getParentXWindow();
262
0
        DialogMask nResult = executeErrorDialog(Application::GetFrameWeld(xParent),
263
0
                eClassification, aContext, aMessage, nButtonMask );
264
265
0
        switch (nResult)
266
0
        {
267
0
        case DialogMask::ButtonsOk:
268
0
            OSL_ENSURE(xApprove.is() || xAbort.is(), "unexpected situation");
269
0
            if (xApprove.is())
270
0
                xApprove->select();
271
0
            else if (xAbort.is())
272
0
                xAbort->select();
273
0
            break;
274
275
0
        case DialogMask::ButtonsCancel:
276
0
            OSL_ENSURE(xAbort.is(), "unexpected situation");
277
0
            if (xAbort.is())
278
0
                xAbort->select();
279
0
            break;
280
281
0
        case DialogMask::ButtonsRetry:
282
0
            OSL_ENSURE(xRetry.is(), "unexpected situation");
283
0
            if (xRetry.is())
284
0
                xRetry->select();
285
0
            break;
286
287
0
        case DialogMask::ButtonsNo:
288
0
            OSL_ENSURE(xDisapprove.is(), "unexpected situation");
289
0
            if (xDisapprove.is())
290
0
                xDisapprove->select();
291
0
            break;
292
293
0
        case DialogMask::ButtonsYes:
294
0
            OSL_ENSURE(xApprove.is(), "unexpected situation");
295
0
            if (xApprove.is())
296
0
                xApprove->select();
297
0
            break;
298
299
0
        default: break;
300
0
        }
301
302
0
    }
303
0
}
304
305
void
306
UUIInteractionHelper::handleLoadReadOnlyRequest(
307
    const OUString& sDocumentURL,
308
    uno::Sequence< uno::Reference< task::XInteractionContinuation > > const &
309
    rContinuations)
310
0
{
311
0
    std::locale aLocale(Translate::Create("uui"));
312
0
    std::vector<OUString> aArguments = { sDocumentURL };
313
0
    uno::Reference<task::XInteractionRetry> xRetry;
314
0
    uno::Reference<task::XInteractionAbort> xAbort;
315
0
    uno::Reference<task::XInteractionApprove> xApprove;
316
0
    uno::Reference<task::XInteractionDisapprove> xDisapprove;
317
0
    uno::Reference<awt::XWindow> xParent = getParentXWindow();
318
0
    OUString aMessage(Translate::get(STR_LOADREADONLY_MSG, aLocale));
319
320
0
    aMessage = replaceMessageWithArguments(aMessage, aArguments);
321
0
    getContinuations(rContinuations, &xApprove, &xDisapprove, &xRetry, &xAbort);
322
323
0
    std::unique_ptr<weld::MessageDialog> xBox(
324
0
        Application::CreateMessageDialog(Application::GetFrameWeld(xParent),
325
0
                                         VclMessageType::Question,
326
0
                                         VclButtonsType::YesNo,
327
0
                                         aMessage));
328
329
0
    if (xBox->run() == RET_YES)
330
0
    {
331
0
        if (xApprove.is())
332
0
            xApprove->select();
333
0
    }
334
0
    else
335
0
    {
336
0
        if (xDisapprove.is())
337
0
            xDisapprove->select();
338
0
    }
339
0
}
340
341
342
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */