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