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 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 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