1# -*- coding: utf-8 -*- 2 3# Copyright (c) 2013 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> 4# 5 6""" 7Module implementing a specialized error message dialog. 8""" 9 10import contextlib 11 12from PyQt5.QtCore import ( 13 qInstallMessageHandler, Qt, Q_ARG, QSettings, QtMsgType, QThread, 14 QMetaObject 15) 16from PyQt5.QtWidgets import QErrorMessage, QDialog 17 18from E5Gui.E5Application import e5App 19 20import Globals 21import Utilities 22import 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 "eric6messagefilters") 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 48def 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 64class 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 105def 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 < 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 182def 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 200def 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 210def 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 221