1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2013 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing a specialized error message dialog. |
|
8 """ |
|
9 |
|
10 import contextlib |
|
11 |
|
12 from PyQt6.QtCore import ( |
|
13 qInstallMessageHandler, Qt, Q_ARG, QSettings, QtMsgType, QThread, |
|
14 QMetaObject |
|
15 ) |
|
16 from PyQt6.QtWidgets import QErrorMessage, QDialog |
|
17 |
|
18 from E5Gui.E5Application import e5App |
|
19 |
|
20 import Globals |
|
21 import Utilities |
|
22 import Preferences |
|
23 |
|
24 |
|
25 _msgHandlerDialog = None |
|
26 _origMsgHandler = None |
|
27 |
|
28 _filterSettings = QSettings( |
|
29 QSettings.Format.IniFormat, |
|
30 QSettings.Scope.UserScope, |
|
31 Globals.settingsNameOrganization, |
|
32 "eric7messagefilters") |
|
33 _defaultFilters = [ |
|
34 "QFont::", |
|
35 "QCocoaMenu::removeMenuItem", |
|
36 "QCocoaMenu::insertNative", |
|
37 ",type id:", |
|
38 "Remote debugging server started successfully", |
|
39 "Uncaught SecurityError:", |
|
40 "Content Security Policy", |
|
41 "QXcbClipboard:", |
|
42 "QXcbConnection: XCB error", |
|
43 "libpng warning: iCCP:", |
|
44 "Uncaught ReferenceError: $ is not defined", |
|
45 ] |
|
46 |
|
47 |
|
48 def filterMessage(message): |
|
49 """ |
|
50 Module function to filter messages. |
|
51 |
|
52 @param message message to be checked |
|
53 @type str |
|
54 @return flag indicating that the message should be filtered out |
|
55 @rtype bool |
|
56 """ |
|
57 return any( |
|
58 filterStr in message |
|
59 for filterStr in Globals.toList(_filterSettings.value( |
|
60 "MessageFilters", [])) + _defaultFilters |
|
61 ) |
|
62 |
|
63 |
|
64 class E5ErrorMessage(QErrorMessage): |
|
65 """ |
|
66 Class implementing a specialized error message dialog. |
|
67 """ |
|
68 def __init__(self, parent=None): |
|
69 """ |
|
70 Constructor |
|
71 |
|
72 @param parent reference to the parent widget |
|
73 @type QWidget |
|
74 """ |
|
75 super().__init__(parent) |
|
76 |
|
77 def showMessage(self, message, msgType=""): |
|
78 """ |
|
79 Public method to show a message. |
|
80 |
|
81 @param message error message to be shown |
|
82 @type str |
|
83 @param msgType type of the error message |
|
84 @type str |
|
85 """ |
|
86 if not filterMessage(message): |
|
87 if msgType: |
|
88 super().showMessage(message, msgType) |
|
89 else: |
|
90 super().showMessage(message) |
|
91 |
|
92 def editMessageFilters(self): |
|
93 """ |
|
94 Public method to edit the list of message filters. |
|
95 """ |
|
96 from .E5ErrorMessageFilterDialog import E5ErrorMessageFilterDialog |
|
97 dlg = E5ErrorMessageFilterDialog( |
|
98 Globals.toList(_filterSettings.value( |
|
99 "MessageFilters", []))) |
|
100 if dlg.exec() == QDialog.DialogCode.Accepted: |
|
101 filters = dlg.getFilters() |
|
102 _filterSettings.setValue("MessageFilters", filters) |
|
103 |
|
104 |
|
105 def messageHandler(msgType, context, message): |
|
106 """ |
|
107 Module function handling messages. |
|
108 |
|
109 @param msgType type of the message |
|
110 @type int, QtMsgType |
|
111 @param context context information |
|
112 @type QMessageLogContext |
|
113 @param message message to be shown |
|
114 @type bytes |
|
115 """ |
|
116 if _msgHandlerDialog: |
|
117 if msgType.value < Preferences.getUI("MinimumMessageTypeSeverity"): |
|
118 # severity is lower than configured |
|
119 # just ignore the message |
|
120 return |
|
121 |
|
122 with contextlib.suppress(RuntimeError): |
|
123 if msgType == QtMsgType.QtDebugMsg: |
|
124 messageType = "Debug Message:" |
|
125 elif msgType == QtMsgType.QtInfoMsg: |
|
126 messageType = "Info Message:" |
|
127 elif msgType == QtMsgType.QtWarningMsg: |
|
128 messageType = "Warning:" |
|
129 elif msgType == QtMsgType.QtCriticalMsg: |
|
130 messageType = "Critical:" |
|
131 elif msgType == QtMsgType.QtFatalMsg: |
|
132 messageType = "Fatal Error:" |
|
133 if isinstance(message, bytes): |
|
134 message = Utilities.decodeBytes(message) |
|
135 if filterMessage(message): |
|
136 return |
|
137 message = ( |
|
138 message.replace("\r\n", "<br/>") |
|
139 .replace("\n", "<br/>") |
|
140 .replace("\r", "<br/>") |
|
141 ) |
|
142 msg = ( |
|
143 ( |
|
144 "<p><b>{0}</b></p><p>{1}</p><p>File: {2}</p>" |
|
145 "<p>Line: {3}</p><p>Function: {4}</p>" |
|
146 ).format(messageType, Utilities.html_uencode(message), |
|
147 context.file, context.line, context.function) |
|
148 if context.file is not None else |
|
149 "<p><b>{0}</b></p><p>{1}</p>".format( |
|
150 messageType, Utilities.html_uencode(message)) |
|
151 ) |
|
152 if QThread.currentThread() == e5App().thread(): |
|
153 _msgHandlerDialog.showMessage(msg) |
|
154 else: |
|
155 QMetaObject.invokeMethod( |
|
156 _msgHandlerDialog, |
|
157 "showMessage", |
|
158 Qt.ConnectionType.QueuedConnection, |
|
159 Q_ARG(str, msg)) |
|
160 return |
|
161 elif _origMsgHandler: |
|
162 _origMsgHandler(msgType, message) |
|
163 return |
|
164 |
|
165 if msgType == QtMsgType.QtDebugMsg: |
|
166 messageType = "Debug Message" |
|
167 elif msgType == QtMsgType.QtInfoMsg: |
|
168 messageType = "Info Message:" |
|
169 elif msgType == QtMsgType.QtWarningMsg: |
|
170 messageType = "Warning" |
|
171 elif msgType == QtMsgType.QtCriticalMsg: |
|
172 messageType = "Critical" |
|
173 elif msgType == QtMsgType.QtFatalMsg: |
|
174 messageType = "Fatal Error" |
|
175 if isinstance(message, bytes): |
|
176 message = message.decode() |
|
177 print("{0}: {1} in {2} at line {3} ({4})".format( |
|
178 messageType, message, context.file, context.line, |
|
179 context.function)) |
|
180 |
|
181 |
|
182 def qtHandler(): |
|
183 """ |
|
184 Module function to install an E5ErrorMessage dialog as the global |
|
185 message handler. |
|
186 |
|
187 @return reference to the message handler dialog |
|
188 @rtype E5ErrorMessage |
|
189 """ |
|
190 global _msgHandlerDialog, _origMsgHandler |
|
191 |
|
192 if _msgHandlerDialog is None: |
|
193 # Install an E5ErrorMessage dialog as the global message handler. |
|
194 _msgHandlerDialog = E5ErrorMessage() |
|
195 _origMsgHandler = qInstallMessageHandler(messageHandler) |
|
196 |
|
197 return _msgHandlerDialog |
|
198 |
|
199 |
|
200 def editMessageFilters(): |
|
201 """ |
|
202 Module function to edit the list of message filters. |
|
203 """ |
|
204 if _msgHandlerDialog: |
|
205 _msgHandlerDialog.editMessageFilters() |
|
206 else: |
|
207 print("No message handler installed.") |
|
208 |
|
209 |
|
210 def messageHandlerInstalled(): |
|
211 """ |
|
212 Module function to check, if a message handler was installed. |
|
213 |
|
214 @return flag indicating an installed message handler |
|
215 @rtype bool |
|
216 """ |
|
217 return _msgHandlerDialog is not None |
|
218 |
|
219 # |
|
220 # eflag: noqa = M801 |
|