eric7/UI/LogView.py

branch
eric7
changeset 8312
800c432b34c8
parent 8260
2161475d9639
child 8318
962bce857696
equal deleted inserted replaced
8311:4e8b98454baa 8312:800c432b34c8
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2006 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the log viewer widget and the log widget.
8 """
9
10 from PyQt5.QtCore import pyqtSignal, Qt, QRegularExpression
11 from PyQt5.QtGui import QBrush, QTextCursor, QTextDocument
12 from PyQt5.QtWidgets import (
13 QTextEdit, QApplication, QMenu, QWidget, QHBoxLayout, QSizePolicy
14 )
15
16 from E5Gui.E5Application import e5App
17
18 import UI.PixmapCache
19 import Preferences
20 import Utilities
21
22
23 class LogViewer(QWidget):
24 """
25 Class implementing the containing widget for the log viewer.
26 """
27 def __init__(self, ui, parent=None):
28 """
29 Constructor
30
31 @param ui reference to the main window (UserInterface)
32 @param parent reference to the parent widget (QWidget)
33 """
34 super().__init__(parent)
35
36 self.setWindowIcon(UI.PixmapCache.getIcon("eric"))
37
38 self.__ui = ui
39
40 self.__logViewer = LogViewerEdit(self)
41 from .SearchWidget import SearchWidget
42 self.__searchWidget = SearchWidget(self.__logViewer, self)
43 self.__searchWidget.setSizePolicy(
44 QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred)
45 self.__searchWidget.hide()
46
47 self.__layout = QHBoxLayout(self)
48 self.__layout.setContentsMargins(1, 1, 1, 1)
49 self.__layout.addWidget(self.__logViewer)
50 self.__layout.addWidget(self.__searchWidget)
51
52 self.__searchWidget.searchNext.connect(self.__logViewer.searchNext)
53 self.__searchWidget.searchPrevious.connect(self.__logViewer.searchPrev)
54 self.__logViewer.searchStringFound.connect(
55 self.__searchWidget.searchStringFound)
56
57 def appendToStdout(self, txt):
58 """
59 Public slot to appand text to the "stdout" tab.
60
61 @param txt text to be appended (string)
62 """
63 added = self.__logViewer.appendToStdout(txt)
64 if added:
65 self.__ui.showLogViewer()
66
67 def appendToStderr(self, txt):
68 """
69 Public slot to appand text to the "stderr" tab.
70
71 @param txt text to be appended (string)
72 """
73 added = self.__logViewer.appendToStderr(txt)
74 if added:
75 self.__ui.showLogViewer()
76
77 def preferencesChanged(self):
78 """
79 Public slot to handle a change of the preferences.
80 """
81 self.__logViewer.preferencesChanged()
82
83 def showFind(self, txt=""):
84 """
85 Public method to display the search widget.
86
87 @param txt text to be shown in the combo (string)
88 """
89 self.__searchWidget.showFind(txt)
90
91
92 class LogViewerEdit(QTextEdit):
93 """
94 Class providing a specialized text edit for displaying logging information.
95
96 @signal searchStringFound(found) emitted to indicate the search result
97 (boolean)
98 """
99 searchStringFound = pyqtSignal(bool)
100
101 def __init__(self, parent=None):
102 """
103 Constructor
104
105 @param parent reference to the parent widget (QWidget)
106 """
107 super().__init__(parent)
108 self.setAcceptRichText(False)
109 self.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap)
110 self.setReadOnly(True)
111
112 self.__mainWindow = parent
113 self.__lastSearch = ()
114
115 # create the context menu
116 self.__menu = QMenu(self)
117 self.__menu.addAction(self.tr('Clear'), self.clear)
118 self.__menu.addAction(self.tr('Copy'), self.copy)
119 self.__menu.addSeparator()
120 self.__menu.addAction(self.tr('Find'), self.__find)
121 self.__menu.addSeparator()
122 self.__menu.addAction(self.tr('Select All'), self.selectAll)
123 self.__menu.addSeparator()
124 self.__menu.addAction(self.tr("Configure..."), self.__configure)
125
126 self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
127 self.customContextMenuRequested.connect(self.__handleShowContextMenu)
128
129 self.cNormalFormat = self.currentCharFormat()
130 self.cErrorFormat = self.currentCharFormat()
131 self.cErrorFormat.setForeground(
132 QBrush(Preferences.getUI("LogStdErrColour")))
133
134 self.__stdoutFilter = Preferences.getUI("LogViewerStdoutFilter")
135 self.__stderrFilter = Preferences.getUI("LogViewerStderrFilter")
136 self.__stdxxxFilter = Preferences.getUI("LogViewerStdxxxFilter")
137
138 def __handleShowContextMenu(self, coord):
139 """
140 Private slot to show the context menu.
141
142 @param coord the position of the mouse pointer (QPoint)
143 """
144 coord = self.mapToGlobal(coord)
145 self.__menu.popup(coord)
146
147 def __appendText(self, txt, isErrorMessage=False):
148 """
149 Private method to append text to the end.
150
151 @param txt text to insert (string)
152 @param isErrorMessage flag indicating to insert error text (boolean)
153 """
154 tc = self.textCursor()
155 tc.movePosition(QTextCursor.MoveOperation.End)
156 self.setTextCursor(tc)
157 if isErrorMessage:
158 self.setCurrentCharFormat(self.cErrorFormat)
159 else:
160 self.setCurrentCharFormat(self.cNormalFormat)
161 self.insertPlainText(Utilities.filterAnsiSequences(txt))
162 self.ensureCursorVisible()
163
164 def __filterMessage(self, message, isErrorMessage=False):
165 """
166 Private method to filter messages.
167
168 @param message message to be checked (string)
169 @param isErrorMessage flag indicating to check an error message
170 (boolean)
171 @return flag indicating that the message should be filtered out
172 (boolean)
173 """
174 message = Utilities.filterAnsiSequences(message)
175
176 filters = (
177 self.__stderrFilter + self.__stdxxxFilter
178 if isErrorMessage else
179 self.__stdoutFilter + self.__stdxxxFilter
180 )
181
182 return any(msgFilter in message for msgFilter in filters)
183
184 def appendToStdout(self, txt):
185 """
186 Public slot to appand text to the "stdout" tab.
187
188 @param txt text to be appended (string)
189 @return flag indicating text was appended (boolean)
190 """
191 if self.__filterMessage(txt, isErrorMessage=False):
192 return False
193
194 self.__appendText(txt, isErrorMessage=False)
195 QApplication.processEvents()
196 return True
197
198 def appendToStderr(self, txt):
199 """
200 Public slot to appand text to the "stderr" tab.
201
202 @param txt text to be appended (string)
203 @return flag indicating text was appended (boolean)
204 """
205 if self.__filterMessage(txt, isErrorMessage=True):
206 return False
207
208 self.__appendText(txt, isErrorMessage=True)
209 QApplication.processEvents()
210 return True
211
212 def preferencesChanged(self):
213 """
214 Public slot to handle a change of the preferences.
215 """
216 self.cErrorFormat.setForeground(
217 QBrush(Preferences.getUI("LogStdErrColour")))
218
219 self.__stdoutFilter = Preferences.getUI("LogViewerStdoutFilter")
220 self.__stderrFilter = Preferences.getUI("LogViewerStderrFilter")
221 self.__stdxxxFilter = Preferences.getUI("LogViewerStdxxxFilter")
222
223 def __configure(self):
224 """
225 Private method to open the configuration dialog.
226 """
227 e5App().getObject("UserInterface").showPreferences("logViewerPage")
228
229 def __find(self):
230 """
231 Private slot to show the find widget.
232 """
233 txt = self.textCursor().selectedText()
234 self.__mainWindow.showFind(txt)
235
236 def searchNext(self, txt, caseSensitive, wholeWord, regexp):
237 """
238 Public method to search the next occurrence of the given text.
239
240 @param txt text to search for
241 @type str
242 @param caseSensitive flag indicating to perform a case sensitive
243 search
244 @type bool
245 @param wholeWord flag indicating to search for whole words
246 only
247 @type bool
248 @param regexp flag indicating a regular expression search
249 @type bool
250 """
251 self.__lastSearch = (txt, caseSensitive, wholeWord, regexp)
252 flags = QTextDocument.FindFlags()
253 if caseSensitive:
254 flags |= QTextDocument.FindFlag.FindCaseSensitively
255 if wholeWord:
256 flags |= QTextDocument.FindFlag.FindWholeWords
257 ok = (
258 self.find(QRegularExpression(
259 txt,
260 QRegularExpression.PatternOption.NoPatternOption
261 if caseSensitive
262 else QRegularExpression.PatternOption.CaseInsensitiveOption),
263 flags
264 )
265 if regexp else
266 self.find(txt, flags)
267 )
268 self.searchStringFound.emit(ok)
269
270 def searchPrev(self, txt, caseSensitive, wholeWord, regexp):
271 """
272 Public method to search the previous occurrence of the given text.
273
274 @param txt text to search for
275 @type str
276 @param caseSensitive flag indicating to perform a case sensitive
277 search
278 @type bool
279 @param wholeWord flag indicating to search for whole words
280 only
281 @type bool
282 @param regexp flag indicating a regular expression search
283 @type bool
284 """
285 self.__lastSearch = (txt, caseSensitive, wholeWord, regexp)
286 flags = QTextDocument.FindFlags(QTextDocument.FindFlag.FindBackward)
287 if caseSensitive:
288 flags |= QTextDocument.FindFlag.FindCaseSensitively
289 if wholeWord:
290 flags |= QTextDocument.FindFlag.FindWholeWords
291 ok = (
292 self.find(QRegularExpression(
293 txt,
294 QRegularExpression.PatternOption.NoPatternOption
295 if caseSensitive
296 else QRegularExpression.PatternOption.CaseInsensitiveOption),
297 flags
298 )
299 if regexp else
300 self.find(txt, flags)
301 )
302 self.searchStringFound.emit(ok)
303
304 def keyPressEvent(self, evt):
305 """
306 Protected method handling key press events.
307
308 @param evt key press event (QKeyEvent)
309 """
310 if evt.modifiers() == Qt.KeyboardModifier.ControlModifier:
311 if evt.key() == Qt.Key.Key_F:
312 self.__find()
313 evt.accept()
314 return
315 elif evt.key() == Qt.Key.Key_C:
316 self.copy()
317 evt.accept()
318 return
319 elif evt.key() == Qt.Key.Key_A:
320 self.selectAll()
321 evt.accept()
322 return
323 elif (
324 evt.modifiers() == Qt.KeyboardModifier.NoModifier and
325 evt.key() == Qt.Key.Key_F3 and
326 self.__lastSearch
327 ):
328 self.searchNext(*self.__lastSearch)
329 evt.accept()
330 return
331 elif (
332 evt.modifiers() == Qt.KeyboardModifier.ShiftModifier and
333 evt.key() == Qt.Key.Key_F3 and
334 self.__lastSearch
335 ):
336 self.searchPrev(*self.__lastSearch)
337 evt.accept()
338 return

eric ide

mercurial