1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include <memory>
25
26 #include "vos/mutex.hxx"
27 #include "vcl/svapp.hxx"
28 #include "vcl/msgbox.hxx"
29
30 #include "com/sun/star/task/XInteractionAbort.hpp"
31 #include "com/sun/star/task/XInteractionApprove.hpp"
32 #include "com/sun/star/task/XInteractionDisapprove.hpp"
33 #include "com/sun/star/task/XInteractionRetry.hpp"
34
35 #include "tools/errinf.hxx" // ErrorHandler, ErrorContext, ...
36 #include "svtools/svtools.hrc" // RID_ERRHDL
37
38 #include "ids.hrc"
39 #include "getcontinuations.hxx"
40
41 #include "iahndl.hxx"
42
43 using namespace com::sun::star;
44
45 namespace {
46
47 sal_uInt16
executeErrorDialog(Window * pParent,task::InteractionClassification eClassification,rtl::OUString const & rContext,rtl::OUString const & rMessage,WinBits nButtonMask)48 executeErrorDialog(
49 Window * pParent,
50 task::InteractionClassification eClassification,
51 rtl::OUString const & rContext,
52 rtl::OUString const & rMessage,
53 WinBits nButtonMask)
54 SAL_THROW((uno::RuntimeException))
55 {
56 vos::OGuard aGuard(Application::GetSolarMutex());
57
58 rtl::OUStringBuffer aText(rContext);
59 if (rContext.getLength() != 0 && rMessage.getLength() != 0)
60 aText.appendAscii(RTL_CONSTASCII_STRINGPARAM(":\n"));
61 //TODO! must be internationalized
62 aText.append(rMessage);
63
64 std::auto_ptr< MessBox > xBox;
65 try
66 {
67 switch (eClassification)
68 {
69 case task::InteractionClassification_ERROR:
70 xBox.reset(new ErrorBox(pParent,
71 nButtonMask,
72 aText.makeStringAndClear()));
73 break;
74
75 case task::InteractionClassification_WARNING:
76 xBox.reset(new WarningBox(pParent,
77 nButtonMask,
78 aText.makeStringAndClear()));
79 break;
80
81 case task::InteractionClassification_INFO:
82 if ((nButtonMask & 0x01F00000) == WB_DEF_OK)
83 //TODO! missing win bit button mask define (want to ignore
84 // any default button settings)...
85 xBox.reset(new InfoBox(pParent,
86 aText.makeStringAndClear()));
87 else
88 xBox.reset(new ErrorBox(pParent,
89 nButtonMask,
90 aText.makeStringAndClear()));
91 break;
92
93 case task::InteractionClassification_QUERY:
94 xBox.reset(new QueryBox(pParent,
95 nButtonMask,
96 aText.makeStringAndClear()));
97 break;
98
99 default:
100 OSL_ASSERT(false);
101 break;
102 }
103 }
104 catch (std::bad_alloc const &)
105 {
106 throw uno::RuntimeException(
107 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("out of memory")),
108 uno::Reference< uno::XInterface >());
109 }
110
111 sal_uInt16 aResult = xBox->Execute();
112 switch( aResult )
113 {
114 case BUTTONID_OK:
115 aResult = ERRCODE_BUTTON_OK;
116 break;
117 case BUTTONID_CANCEL:
118 aResult = ERRCODE_BUTTON_CANCEL;
119 break;
120 case BUTTONID_YES:
121 aResult = ERRCODE_BUTTON_YES;
122 break;
123 case BUTTONID_NO:
124 aResult = ERRCODE_BUTTON_NO;
125 break;
126 case BUTTONID_RETRY:
127 aResult = ERRCODE_BUTTON_RETRY;
128 break;
129 }
130
131 return aResult;
132 }
133
134 }
135
136 void
handleErrorHandlerRequest(task::InteractionClassification eClassification,ErrCode nErrorCode,std::vector<rtl::OUString> const & rArguments,uno::Sequence<uno::Reference<task::XInteractionContinuation>> const & rContinuations,bool bObtainErrorStringOnly,bool & bHasErrorString,rtl::OUString & rErrorString)137 UUIInteractionHelper::handleErrorHandlerRequest(
138 task::InteractionClassification eClassification,
139 ErrCode nErrorCode,
140 std::vector< rtl::OUString > const & rArguments,
141 uno::Sequence< uno::Reference< task::XInteractionContinuation > > const &
142 rContinuations,
143 bool bObtainErrorStringOnly,
144 bool & bHasErrorString,
145 rtl::OUString & rErrorString)
146 SAL_THROW((uno::RuntimeException))
147 {
148 if (bObtainErrorStringOnly)
149 {
150 bHasErrorString = isInformationalErrorMessageRequest(rContinuations);
151 if (!bHasErrorString)
152 return;
153 }
154
155 rtl::OUString aMessage;
156 {
157 enum Source { SOURCE_DEFAULT, SOURCE_CNT, SOURCE_SVX, SOURCE_UUI };
158 static char const * const aManager[4]
159 = { CREATEVERSIONRESMGR_NAME(ofa),
160 CREATEVERSIONRESMGR_NAME(cnt),
161 CREATEVERSIONRESMGR_NAME(svx),
162 CREATEVERSIONRESMGR_NAME(uui) };
163 static sal_uInt16 const aId[4]
164 = { RID_ERRHDL,
165 RID_CHAOS_START + 12,
166 // cf. chaos/source/inc/cntrids.hrc, where
167 // #define RID_CHAOS_ERRHDL (RID_CHAOS_START + 12)
168 RID_SVX_START + 350, // RID_SVXERRCODE
169 RID_UUI_ERRHDL };
170 ErrCode nErrorId = nErrorCode & ~ERRCODE_WARNING_MASK;
171 Source eSource = nErrorId < ERRCODE_AREA_LIB1 ?
172 SOURCE_DEFAULT :
173 nErrorId >= ERRCODE_AREA_CHAOS
174 && nErrorId < ERRCODE_AREA_CHAOS_END ?
175 SOURCE_CNT :
176 nErrorId >= ERRCODE_AREA_SVX
177 && nErrorId <= ERRCODE_AREA_SVX_END ?
178 SOURCE_SVX :
179 SOURCE_UUI;
180
181 vos::OGuard aGuard(Application::GetSolarMutex());
182 std::auto_ptr< ResMgr > xManager;
183 xManager.reset(ResMgr::CreateResMgr(aManager[eSource]));
184 if (!xManager.get())
185 return;
186 ResId aResId(aId[eSource], *xManager.get());
187 if (!ErrorResource(aResId).getString(nErrorCode, &aMessage))
188 return;
189 }
190
191 aMessage = replaceMessageWithArguments( aMessage, rArguments );
192
193 if (bObtainErrorStringOnly)
194 {
195 rErrorString = aMessage;
196 return;
197 }
198 else
199 {
200 //TODO! It can happen that the buttons calculated below do not match
201 // the error text from the resource (e.g., some text that is not a
202 // question, but YES and NO buttons). Some error texts have
203 // ExtraData that specifies a set of buttons, but that data is not
204 // really useful, because a single error text may well make sense
205 // both with only an OK button and with RETRY and CANCEL buttons.
206
207 uno::Reference< task::XInteractionApprove > xApprove;
208 uno::Reference< task::XInteractionDisapprove > xDisapprove;
209 uno::Reference< task::XInteractionRetry > xRetry;
210 uno::Reference< task::XInteractionAbort > xAbort;
211 getContinuations(
212 rContinuations, &xApprove, &xDisapprove, &xRetry, &xAbort);
213
214 // The following mapping uses the bit mask
215 // Approve = 8,
216 // Disapprove = 4,
217 // Retry = 2,
218 // Abort = 1
219 //
220 // The mapping has five properties on which the code to select the
221 // correct continuation relies:
222 // 1 The OK button is mapped to Approve if that is available,
223 // otherwise to Abort if that is available, otherwise to none.
224 // 2 The CANCEL button is always mapped to Abort.
225 // 3 The RETRY button is always mapped to Retry.
226 // 4 The NO button is always mapped to Disapprove.
227 // 5 The YES button is always mapped to Approve.
228 //
229 // Because the WinBits button combinations are quite restricted, not
230 // every request can be served here.
231 //
232 // Finally, it seems to be better to leave default button
233 // determination to VCL (the favouring of CANCEL as default button
234 // seems to not always be what the user wants)...
235 WinBits const aButtonMask[16]
236 = { 0,
237 WB_OK /*| WB_DEF_OK*/, // Abort
238 0,
239 WB_RETRY_CANCEL /*| WB_DEF_CANCEL*/, // Retry, Abort
240 0,
241 0,
242 0,
243 0,
244 WB_OK /*| WB_DEF_OK*/, // Approve
245 WB_OK_CANCEL /*| WB_DEF_CANCEL*/, // Approve, Abort
246 0,
247 0,
248 WB_YES_NO /*| WB_DEF_NO*/, // Approve, Disapprove
249 WB_YES_NO_CANCEL /*| WB_DEF_CANCEL*/,
250 // Approve, Disapprove, Abort
251 0,
252 0 };
253
254 WinBits nButtonMask = aButtonMask[(xApprove.is() ? 8 : 0)
255 | (xDisapprove.is() ? 4 : 0)
256 | (xRetry.is() ? 2 : 0)
257 | (xAbort.is() ? 1 : 0)];
258 if (nButtonMask == 0)
259 return;
260
261 //TODO! remove this backwards compatibility?
262 rtl::OUString aContext(getContextProperty());
263 if (aContext.getLength() == 0 && nErrorCode != 0)
264 {
265 vos::OGuard aGuard(Application::GetSolarMutex());
266 ErrorContext * pContext = ErrorContext::GetContext();
267 if (pContext)
268 {
269 UniString aContextString;
270 if (pContext->GetString(nErrorCode, aContextString))
271 aContext = aContextString;
272 }
273 }
274
275 sal_uInt16 nResult = executeErrorDialog(
276 getParentProperty(), eClassification, aContext, aMessage, nButtonMask );
277
278 switch (nResult)
279 {
280 case ERRCODE_BUTTON_OK:
281 OSL_ENSURE(xApprove.is() || xAbort.is(), "unexpected situation");
282 if (xApprove.is())
283 xApprove->select();
284 else if (xAbort.is())
285 xAbort->select();
286 break;
287
288 case ERRCODE_BUTTON_CANCEL:
289 OSL_ENSURE(xAbort.is(), "unexpected situation");
290 if (xAbort.is())
291 xAbort->select();
292 break;
293
294 case ERRCODE_BUTTON_RETRY:
295 OSL_ENSURE(xRetry.is(), "unexpected situation");
296 if (xRetry.is())
297 xRetry->select();
298 break;
299
300 case ERRCODE_BUTTON_NO:
301 OSL_ENSURE(xDisapprove.is(), "unexpected situation");
302 if (xDisapprove.is())
303 xDisapprove->select();
304 break;
305
306 case ERRCODE_BUTTON_YES:
307 OSL_ENSURE(xApprove.is(), "unexpected situation");
308 if (xApprove.is())
309 xApprove->select();
310 break;
311 }
312
313 }
314 }
315