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