diff options
author | Chris Sherlock <chris.sherlock79@gmail.com> | 2017-04-14 15:29:06 +1000 |
---|---|---|
committer | Chris Sherlock <chris.sherlock79@gmail.com> | 2017-04-25 10:55:17 +0200 |
commit | 3b85b72d643e26fd9fda5eeb05f774b3c37917fd (patch) | |
tree | 3776cff123fb2ab776105c96335c0a0fcad8570e /vcl/source/window/errinf.cxx | |
parent | 6b448d3634f26224e480c0f30c617eacd7b4e3ab (diff) |
errinf.hxx moved out of tools and into vcl module
ErrorInfo has a hard depency on VCL, yet is in the tools package. It is more
appropriate to have it reside in the VCL module.
Change-Id: Ica54a46c3a7f86cf0331ed7245234bea69c05650
Reviewed-on: https://gerrit.libreoffice.org/36839
Reviewed-by: Chris Sherlock <chris.sherlock79@gmail.com>
Tested-by: Chris Sherlock <chris.sherlock79@gmail.com>
Diffstat (limited to 'vcl/source/window/errinf.cxx')
-rw-r--r-- | vcl/source/window/errinf.cxx | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/vcl/source/window/errinf.cxx b/vcl/source/window/errinf.cxx new file mode 100644 index 000000000000..cfe44da63c2f --- /dev/null +++ b/vcl/source/window/errinf.cxx @@ -0,0 +1,350 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <limits.h> +#include <vcl/errinf.hxx> +#include <rtl/strbuf.hxx> +#include <osl/diagnose.h> +#include <vcl/window.hxx> +#include <vector> + +class ErrorHandler; + +namespace { + typedef void (* DisplayFnPtr)(); +} + +struct ErrorRegistry +{ +public: + std::vector<ErrorHandler*> errorHandlers; + std::vector<ErrorContext*> contexts; + DisplayFnPtr pDsp; + bool bIsWindowDsp; + + DynamicErrorInfo* ppDynErrInfo[ERRCODE_DYNAMIC_COUNT]; + sal_uInt16 nNextDcr; + ErrorRegistry(); +}; + +struct TheErrorRegistry: public rtl::Static<ErrorRegistry, TheErrorRegistry> {}; + +class DynamicErrorInfo_Impl +{ + ErrCode lErrId; + ErrorHandlerFlags nMask; + + void RegisterEDcr(DynamicErrorInfo *); + static void UnRegisterEDcr(DynamicErrorInfo const *); + static ErrorInfo* GetDynamicErrorInfo(sal_uIntPtr lId); + +friend class DynamicErrorInfo; +friend class ErrorInfo; +}; + +ErrorRegistry::ErrorRegistry() + : pDsp(nullptr) + , bIsWindowDsp(false) + , nNextDcr(0) +{ + for(DynamicErrorInfo*& rp : ppDynErrInfo) + rp = nullptr; +} + +void DynamicErrorInfo_Impl::RegisterEDcr(DynamicErrorInfo *pDynErrInfo) +{ + // Register dynamic identifier + ErrorRegistry& rData = TheErrorRegistry::get(); + lErrId = (((sal_uIntPtr)rData.nNextDcr + 1) << ERRCODE_DYNAMIC_SHIFT) + + pDynErrInfo->GetErrorCode(); + + if(rData.ppDynErrInfo[rData.nNextDcr]) + { + delete rData.ppDynErrInfo[rData.nNextDcr]; + } + rData.ppDynErrInfo[rData.nNextDcr] = pDynErrInfo; + if(++rData.nNextDcr>=ERRCODE_DYNAMIC_COUNT) + rData.nNextDcr=0; +} + +void DynamicErrorInfo_Impl::UnRegisterEDcr(DynamicErrorInfo const *pDynErrInfo) +{ + DynamicErrorInfo **ppDynErrInfo = TheErrorRegistry::get().ppDynErrInfo; + sal_uIntPtr lIdx = (((sal_uIntPtr)(*pDynErrInfo) & ERRCODE_DYNAMIC_MASK) >> ERRCODE_DYNAMIC_SHIFT) - 1; + DBG_ASSERT(ppDynErrInfo[lIdx]==pDynErrInfo, "ErrHdl: Error not found"); + if(ppDynErrInfo[lIdx]==pDynErrInfo) + ppDynErrInfo[lIdx]=nullptr; +} + +ErrorInfo::~ErrorInfo() +{ +} + + +ErrorInfo *ErrorInfo::GetErrorInfo(sal_uIntPtr lId) +{ + if(lId & ERRCODE_DYNAMIC_MASK) + return DynamicErrorInfo_Impl::GetDynamicErrorInfo(lId); + else + return new ErrorInfo(lId); +} + +DynamicErrorInfo::operator sal_uIntPtr() const +{ + return pImpl->lErrId; +} + +DynamicErrorInfo::DynamicErrorInfo(sal_uIntPtr lArgUserId, ErrorHandlerFlags nMask) +: ErrorInfo(lArgUserId), + pImpl(new DynamicErrorInfo_Impl) +{ + pImpl->RegisterEDcr(this); + pImpl->nMask=nMask; +} + +DynamicErrorInfo::~DynamicErrorInfo() +{ + DynamicErrorInfo_Impl::UnRegisterEDcr(this); +} + +ErrorInfo* DynamicErrorInfo_Impl::GetDynamicErrorInfo(sal_uIntPtr lId) +{ + sal_uIntPtr lIdx = ((lId & ERRCODE_DYNAMIC_MASK)>>ERRCODE_DYNAMIC_SHIFT)-1; + DynamicErrorInfo* pDynErrInfo = TheErrorRegistry::get().ppDynErrInfo[lIdx]; + if(pDynErrInfo && (sal_uIntPtr)(*pDynErrInfo)==lId) + return pDynErrInfo; + else + return new ErrorInfo(lId & ~ERRCODE_DYNAMIC_MASK); +} + +ErrorHandlerFlags DynamicErrorInfo::GetDialogMask() const +{ + return pImpl->nMask; +} + +StringErrorInfo::StringErrorInfo( + sal_uIntPtr UserId, const OUString& aStringP, ErrorHandlerFlags nMask) +: DynamicErrorInfo(UserId, nMask), aString(aStringP) +{ +} + +class ErrorHandler_Impl +{ +public: + static bool CreateString(const ErrorInfo*, OUString&); +}; + +static void aDspFunc(const OUString &rErr, const OUString &rAction) +{ + OStringBuffer aErr("Action: "); + aErr.append(OUStringToOString(rAction, RTL_TEXTENCODING_ASCII_US)); + aErr.append(" Error: "); + aErr.append(OUStringToOString(rErr, RTL_TEXTENCODING_ASCII_US)); + OSL_FAIL(aErr.getStr()); +} + +// FIXME: this is a horrible reverse dependency on VCL +struct ErrorContextImpl +{ + vcl::Window *pWin; // should be VclPtr for strong lifecycle +}; + +ErrorContext::ErrorContext(vcl::Window *pWinP) + : pImpl( new ErrorContextImpl ) +{ + pImpl->pWin = pWinP; + TheErrorRegistry::get().contexts.insert(TheErrorRegistry::get().contexts.begin(), this); +} + +ErrorContext::~ErrorContext() +{ + auto &rContexts = TheErrorRegistry::get().contexts; + rContexts.erase( ::std::remove(rContexts.begin(), rContexts.end(), this), rContexts.end()); +} + +ErrorContext *ErrorContext::GetContext() +{ + return TheErrorRegistry::get().contexts.empty() ? nullptr : TheErrorRegistry::get().contexts.front(); +} + + +ErrorHandler::ErrorHandler() +{ + ErrorRegistry &rData = TheErrorRegistry::get(); + rData.errorHandlers.insert(rData.errorHandlers.begin(), this); + if(!rData.pDsp) + RegisterDisplay(&aDspFunc); +} + +ErrorHandler::~ErrorHandler() +{ + auto &rErrorHandlers = TheErrorRegistry::get().errorHandlers; + rErrorHandlers.erase( ::std::remove(rErrorHandlers.begin(), rErrorHandlers.end(), this), rErrorHandlers.end()); +} + +vcl::Window* ErrorContext::GetParent() +{ + return pImpl ? pImpl->pWin : nullptr; +} + +void ErrorHandler::RegisterDisplay(WindowDisplayErrorFunc *aDsp) +{ + ErrorRegistry &rData = TheErrorRegistry::get(); + rData.bIsWindowDsp = true; + rData.pDsp = reinterpret_cast< DisplayFnPtr >(aDsp); +} + +void ErrorHandler::RegisterDisplay(BasicDisplayErrorFunc *aDsp) +{ + ErrorRegistry &rData = TheErrorRegistry::get(); + rData.bIsWindowDsp = false; + rData.pDsp = reinterpret_cast< DisplayFnPtr >(aDsp); +} + +/** Handles an error. + + If nFlags is not set, the DynamicErrorInfo flags or the + resource flags will be used. + Thus: + + 1. nFlags, + 2. Resource Flags + 3. Dynamic Flags + 4. Default ButtonsOk, MessageError + + @param nErrCodeId error id + @param nFlags error flags. + @param bJustCreateString ??? + @param rError ??? + + @return ??? +*/ +ErrorHandlerFlags ErrorHandler::HandleError_Impl( + sal_uIntPtr nErrCodeId, ErrorHandlerFlags nFlags, bool bJustCreateString, OUString & rError) +{ + OUString aErr; + OUString aAction; + if(!nErrCodeId || nErrCodeId == ERRCODE_ABORT) + return ErrorHandlerFlags::NONE; + ErrorRegistry &rData = TheErrorRegistry::get(); + vcl::Window *pParent = nullptr; + ErrorInfo *pInfo = ErrorInfo::GetErrorInfo(nErrCodeId); + if (!rData.contexts.empty()) + { + rData.contexts.front()->GetString(pInfo->GetErrorCode(), aAction); + // Remove parent from context + for(ErrorContext *pCtx : rData.contexts) + if(pCtx->GetParent()) + { + pParent=pCtx->GetParent(); + break; + } + } + + bool bWarning = ((nErrCodeId & ERRCODE_WARNING_MASK) == ERRCODE_WARNING_MASK); + ErrorHandlerFlags nErrFlags = ErrorHandlerFlags::ButtonDefaultsOk | ErrorHandlerFlags::ButtonsOk; + if (bWarning) + nErrFlags |= ErrorHandlerFlags::MessageWarning; + else + nErrFlags |= ErrorHandlerFlags::MessageError; + + DynamicErrorInfo* pDynPtr=dynamic_cast<DynamicErrorInfo*>(pInfo); + if(pDynPtr) + { + ErrorHandlerFlags nDynFlags = pDynPtr->GetDialogMask(); + if( nDynFlags != ErrorHandlerFlags::NONE ) + nErrFlags = nDynFlags; + } + + if(ErrorHandler_Impl::CreateString(pInfo,aErr)) + { + if (bJustCreateString) + { + rError = aErr; + return ErrorHandlerFlags::ButtonsOk; + } + else + { + if(!rData.pDsp) + { + OStringBuffer aStr("Action: "); + aStr.append(OUStringToOString(aAction, RTL_TEXTENCODING_ASCII_US)); + aStr.append("\nFehler: "); + aStr.append(OUStringToOString(aErr, RTL_TEXTENCODING_ASCII_US)); + OSL_FAIL(aStr.getStr()); + } + else + { + delete pInfo; + if(!rData.bIsWindowDsp) + { + (*reinterpret_cast<BasicDisplayErrorFunc*>(rData.pDsp))(aErr,aAction); + return ErrorHandlerFlags::NONE; + } + else + { + if (nFlags != ErrorHandlerFlags::MAX) + nErrFlags = nFlags; + return (*reinterpret_cast<WindowDisplayErrorFunc*>(rData.pDsp))( + pParent, nErrFlags, aErr, aAction); + } + } + } + } + OSL_FAIL("Error not handled"); + // Error 1 is General Error in the Sfx + if(pInfo->GetErrorCode()!=1) + { + HandleError_Impl(1, ErrorHandlerFlags::MAX, bJustCreateString, rError); + } + else + { + OSL_FAIL("Error 1 not handled"); + } + delete pInfo; + return ErrorHandlerFlags::NONE; +} + +// static +bool ErrorHandler::GetErrorString(sal_uIntPtr lId, OUString& rStr) +{ + return HandleError_Impl( lId, ErrorHandlerFlags::MAX, true, rStr ) != ErrorHandlerFlags::NONE; +} + +/** Handles an error. + + @see ErrorHandler::HandleError_Impl +*/ +ErrorHandlerFlags ErrorHandler::HandleError(sal_uIntPtr lId, ErrorHandlerFlags nFlags) +{ + OUString aDummy; + return HandleError_Impl( lId, nFlags, false, aDummy ); +} + +bool ErrorHandler_Impl::CreateString(const ErrorInfo* pInfo, OUString& rStr) +{ + for(const ErrorHandler *pHdl : TheErrorRegistry::get().errorHandlers) + { + if(pHdl->CreateString(pInfo, rStr)) + return true; + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |