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 <osl/diagnose.h>
21 #include <sal/log.hxx>
22
23 #include <tools/debug.hxx>
24 #include <utility>
25 #include <vcl/errinf.hxx>
26
27 #include <algorithm>
28 #include <vector>
29
30 class ErrorHandler;
31
32 namespace {
33
GetErrorRegistry()34 ErrorRegistry& GetErrorRegistry()
35 {
36 static ErrorRegistry gErrorRegistry;
37 return gErrorRegistry;
38 }
39
40 }
41
CreateString(const ErrCodeMsg & nInfo,OUString & rStr)42 bool ErrorStringFactory::CreateString(const ErrCodeMsg& nInfo, OUString& rStr)
43 {
44 for(const ErrorHandler *pHdlr : GetErrorRegistry().errorHandlers)
45 {
46 if(pHdlr->CreateString(nInfo, rStr))
47 return true;
48 }
49 return false;
50 }
51
ErrorRegistry()52 ErrorRegistry::ErrorRegistry()
53 : pDsp(nullptr)
54 , bIsWindowDsp(false)
55 , m_bLock(false)
56 {
57 }
58
RegisterDisplay(BasicDisplayErrorFunc * aDsp)59 void ErrorRegistry::RegisterDisplay(BasicDisplayErrorFunc *aDsp)
60 {
61 ErrorRegistry &rData = GetErrorRegistry();
62 rData.bIsWindowDsp = false;
63 rData.pDsp = reinterpret_cast< DisplayFnPtr >(aDsp);
64 }
65
RegisterDisplay(WindowDisplayErrorFunc * aDsp)66 void ErrorRegistry::RegisterDisplay(WindowDisplayErrorFunc *aDsp)
67 {
68 ErrorRegistry &rData = GetErrorRegistry();
69 rData.bIsWindowDsp = true;
70 rData.pDsp = reinterpret_cast< DisplayFnPtr >(aDsp);
71 }
72
SetLock(bool bLock)73 void ErrorRegistry::SetLock(bool bLock)
74 {
75 ErrorRegistry& rData = GetErrorRegistry();
76 rData.m_bLock = bLock;
77 }
78
GetLock()79 bool ErrorRegistry::GetLock()
80 {
81 ErrorRegistry& rData = GetErrorRegistry();
82 return rData.m_bLock;
83 }
84
Reset()85 void ErrorRegistry::Reset()
86 {
87 ErrorRegistry &rData = GetErrorRegistry();
88 rData = ErrorRegistry();
89 }
90
aDspFunc(const OUString & rErr,const OUString & rAction)91 static void aDspFunc(const OUString &rErr, const OUString &rAction)
92 {
93 SAL_WARN("vcl", "Action: " << rAction << " Error: " << rErr);
94 }
95
ErrorHandler()96 ErrorHandler::ErrorHandler()
97 {
98 ErrorRegistry &rData = GetErrorRegistry();
99 rData.errorHandlers.insert(rData.errorHandlers.begin(), this);
100
101 if(!rData.pDsp)
102 ErrorRegistry::RegisterDisplay(&aDspFunc);
103 }
104
~ErrorHandler()105 ErrorHandler::~ErrorHandler()
106 {
107 auto &rErrorHandlers = GetErrorRegistry().errorHandlers;
108 std::erase(rErrorHandlers, this);
109 }
110
GetErrorString(const ErrCodeMsg & nErrCode,OUString & rErrStr)111 bool ErrorHandler::GetErrorString(const ErrCodeMsg& nErrCode, OUString& rErrStr)
112 {
113 OUString aErr;
114
115 if(!nErrCode || nErrCode == ERRCODE_ABORT)
116 return false;
117
118 if (ErrorStringFactory::CreateString(nErrCode, aErr))
119 {
120 rErrStr = aErr;
121 return true;
122 }
123
124 return false;
125 }
126
HandleError(const ErrCodeMsg & nErr,weld::Window * pParent,DialogMask nFlags)127 DialogMask ErrorHandler::HandleError(const ErrCodeMsg& nErr, weld::Window *pParent, DialogMask nFlags)
128 {
129 if (nErr == ERRCODE_NONE || nErr == ERRCODE_ABORT)
130 return DialogMask::NONE;
131
132 ErrorRegistry &rData = GetErrorRegistry();
133 OUString aAction;
134
135 if (!rData.contexts.empty())
136 {
137 rData.contexts.front()->GetString(nErr, aAction);
138
139 for(ErrorContext *pCtx : rData.contexts)
140 {
141 if(pCtx->GetParent())
142 {
143 pParent = pCtx->GetParent();
144 break;
145 }
146 }
147 }
148
149 bool bWarning = nErr.IsWarning();
150 DialogMask nErrFlags = DialogMask::ButtonDefaultsOk | DialogMask::ButtonsOk;
151 if (bWarning)
152 nErrFlags |= DialogMask::MessageWarning;
153 else
154 nErrFlags |= DialogMask::MessageError;
155
156 if( nErr.GetDialogMask() != DialogMask::NONE )
157 nErrFlags = nErr.GetDialogMask();
158
159 OUString aErr;
160 if (ErrorStringFactory::CreateString(nErr, aErr))
161 {
162 if (!rData.pDsp || rData.m_bLock)
163 {
164 SAL_WARN( "vcl", "Action: " << aAction << "Error: " << aErr);
165 }
166 else
167 {
168 if(!rData.bIsWindowDsp)
169 {
170 (*reinterpret_cast<BasicDisplayErrorFunc*>(rData.pDsp))(aErr,aAction);
171 return DialogMask::NONE;
172 }
173 else
174 {
175 if (nFlags != DialogMask::MAX)
176 nErrFlags = nFlags;
177
178 return (*reinterpret_cast<WindowDisplayErrorFunc*>(rData.pDsp))(
179 pParent, nErrFlags, aErr, aAction);
180 }
181 }
182 }
183
184 SAL_WARN( "vcl", "Error not handled " << nErr);
185 // Error 1 (ERRCODE_ABORT) is classified as a General Error in sfx
186 if (nErr.GetCode() != ERRCODE_ABORT)
187 HandleError(ERRCODE_ABORT);
188 else
189 OSL_FAIL("ERRCODE_ABORT not handled");
190
191 return DialogMask::NONE;
192 }
193
194 struct ImplErrorContext
195 {
196 weld::Window *pWin;
197 };
198
ErrorContext(weld::Window * pWinP)199 ErrorContext::ErrorContext(weld::Window *pWinP)
200 : pImpl( new ImplErrorContext )
201 {
202 pImpl->pWin = pWinP;
203 GetErrorRegistry().contexts.insert(GetErrorRegistry().contexts.begin(), this);
204 }
205
~ErrorContext()206 ErrorContext::~ErrorContext()
207 {
208 auto &rContexts = GetErrorRegistry().contexts;
209 std::erase(rContexts, this);
210 }
211
GetContext()212 ErrorContext *ErrorContext::GetContext()
213 {
214 return GetErrorRegistry().contexts.empty() ? nullptr : GetErrorRegistry().contexts.front();
215 }
216
GetParent()217 weld::Window* ErrorContext::GetParent()
218 {
219 return pImpl ? pImpl->pWin : nullptr;
220 }
221
222 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
223