UI/CodeDocumentationViewer.py

changeset 6506
ff6172ce89a9
parent 6505
470d878cbe9f
child 6645
ad476851d7e0
equal deleted inserted replaced
6505:470d878cbe9f 6506:ff6172ce89a9
15 basestring = str 15 basestring = str
16 16
17 from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QUrl, QTimer 17 from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QUrl, QTimer
18 from PyQt5.QtGui import QCursor 18 from PyQt5.QtGui import QCursor
19 from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, \ 19 from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, \
20 QComboBox, QSizePolicy, QLineEdit, QTextEdit, QToolTip 20 QComboBox, QSizePolicy, QLineEdit, QTextBrowser, QToolTip
21 21
22 from E5Gui.E5TextEditSearchWidget import E5TextEditSearchWidget 22 from E5Gui.E5TextEditSearchWidget import E5TextEditSearchWidget
23 23
24 import Preferences 24 import Preferences
25 25
29 prepareDocumentationViewerHtmlWarningDocument 29 prepareDocumentationViewerHtmlWarningDocument
30 30
31 from .data import codeDocumentationViewer_rc # __IGNORE_WARNING__ 31 from .data import codeDocumentationViewer_rc # __IGNORE_WARNING__
32 32
33 33
34 class PlainTextDocumentationViewer(QWidget): 34 class DocumentationViewerWidget(QWidget):
35 """ 35 """
36 Class implementing the plain text documentation viewer. 36 Class implementing a rich text documentation viewer.
37 """ 37 """
38 def __init__(self, parent=None): 38 def __init__(self, parent=None):
39 """ 39 """
40 Constructor 40 Constructor
41 41
42 @param parent reference to the parent widget 42 @param parent reference to the parent widget
43 @type QWidget 43 @type QWidget
44 """ 44 """
45 super(PlainTextDocumentationViewer, self).__init__(parent) 45 super(DocumentationViewerWidget, self).__init__(parent)
46 self.setObjectName("PlainTextDocumentationViewer") 46 self.setObjectName("DocumentationViewerWidget")
47
48 self.__verticalLayout = QVBoxLayout(self)
49 self.__verticalLayout.setObjectName("verticalLayout")
50 self.__verticalLayout.setContentsMargins(0, 0, 0, 0)
51
52 self.__contents = QTextEdit(self)
53 self.__contents.setTabChangesFocus(True)
54 self.__contents.setReadOnly(True)
55 self.__contents.setLineWrapMode(QTextEdit.NoWrap)
56 self.__contents.setObjectName("contents")
57 self.__verticalLayout.addWidget(self.__contents)
58
59 self.__searchWidget = E5TextEditSearchWidget(self, False)
60 self.__searchWidget.setFocusPolicy(Qt.WheelFocus)
61 self.__searchWidget.setObjectName("searchWidget")
62 self.__verticalLayout.addWidget(self.__searchWidget)
63
64 self.__searchWidget.attachTextEdit(self.__contents, "QTextEdit")
65
66 self.preferencesChanged()
67
68 def clear(self):
69 """
70 Public method to clear the contents.
71 """
72 self.__contents.clear()
73
74 def setText(self, text):
75 """
76 Public method to set the text to be shown.
77
78 @param text text to be shown
79 @type str
80 """
81 self.__contents.setPlainText(text)
82
83 def preferencesChanged(self):
84 """
85 Public slot to handle a change of preferences.
86 """
87 font = Preferences.getEditorOtherFonts("MonospacedFont")
88 self.__contents.setFontFamily(font.family())
89 self.__contents.setFontPointSize(font.pointSize())
90
91
92 class WebViewDocumentationViewer(QWidget):
93 """
94 Class implementing the rich text documentation viewer.
95 """
96 def __init__(self, parent=None):
97 """
98 Constructor
99
100 @param parent reference to the parent widget
101 @type QWidget
102 """
103 super(WebViewDocumentationViewer, self).__init__(parent)
104 self.setObjectName("WebViewDocumentationViewer")
105 47
106 self.__verticalLayout = QVBoxLayout(self) 48 self.__verticalLayout = QVBoxLayout(self)
107 self.__verticalLayout.setObjectName("verticalLayout") 49 self.__verticalLayout.setObjectName("verticalLayout")
108 self.__verticalLayout.setContentsMargins(0, 0, 0, 0) 50 self.__verticalLayout.setContentsMargins(0, 0, 0, 0)
109 51
116 self.__contents.settings().setAttribute( 58 self.__contents.settings().setAttribute(
117 QWebEngineSettings.FocusOnNavigationEnabled, False) 59 QWebEngineSettings.FocusOnNavigationEnabled, False)
118 except AttributeError: 60 except AttributeError:
119 # pre Qt 5.8 61 # pre Qt 5.8
120 pass 62 pass
121 self.__usesWebKit = False 63 self.__viewerType = "QWebEngineView"
122 except ImportError: 64 except ImportError:
123 from PyQt5.QtWebKitWidgets import QWebPage, QWebView 65 try:
124 self.__contents = QWebView(self) 66 from PyQt5.QtWebKitWidgets import QWebPage, QWebView
125 self.__contents.page().setLinkDelegationPolicy( 67 self.__contents = QWebView(self)
126 QWebPage.DelegateAllLinks) 68 self.__contents.page().setLinkDelegationPolicy(
127 self.__usesWebKit = True 69 QWebPage.DelegateAllLinks)
70 self.__viewerType = "QWebView"
71 except ImportError:
72 self.__contents = QTextBrowser(self)
73 self.__contents.setOpenExternalLinks(True)
74 self.__viewerType = "QTextEdit"
128 75
129 sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) 76 sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
130 sizePolicy.setHorizontalStretch(0) 77 sizePolicy.setHorizontalStretch(0)
131 sizePolicy.setVerticalStretch(0) 78 sizePolicy.setVerticalStretch(0)
132 sizePolicy.setHeightForWidth( 79 sizePolicy.setHeightForWidth(
133 self.__contents.sizePolicy().hasHeightForWidth()) 80 self.__contents.sizePolicy().hasHeightForWidth())
134 self.__contents.setSizePolicy(sizePolicy) 81 self.__contents.setSizePolicy(sizePolicy)
135 self.__contents.setContextMenuPolicy(Qt.NoContextMenu) 82 self.__contents.setContextMenuPolicy(Qt.NoContextMenu)
136 self.__contents.setUrl(QUrl("about:blank")) 83 if self.__viewerType != "QTextEdit":
84 self.__contents.setUrl(QUrl("about:blank"))
137 self.__verticalLayout.addWidget(self.__contents) 85 self.__verticalLayout.addWidget(self.__contents)
138 86
139 self.__searchWidget = E5TextEditSearchWidget(self, False) 87 self.__searchWidget = E5TextEditSearchWidget(self, False)
140 self.__searchWidget.setFocusPolicy(Qt.WheelFocus) 88 self.__searchWidget.setFocusPolicy(Qt.WheelFocus)
141 self.__searchWidget.setObjectName("searchWidget") 89 self.__searchWidget.setObjectName("searchWidget")
142 self.__verticalLayout.addWidget(self.__searchWidget) 90 self.__verticalLayout.addWidget(self.__searchWidget)
143 91
144 self.__searchWidget.attachTextEdit( 92 self.__searchWidget.attachTextEdit(
145 self.__contents, 93 self.__contents, self.__viewerType)
146 "QWebView" if self.__usesWebKit else "QWebEngineView",
147 )
148 94
149 @pyqtSlot(str) 95 @pyqtSlot(str)
150 def __showLink(self, urlStr): 96 def __showLink(self, urlStr):
151 """ 97 """
152 Private slot to show the hovered link in a tooltip. 98 Private slot to show the hovered link in a tooltip.
169 115
170 def clear(self): 116 def clear(self):
171 """ 117 """
172 Public method to clear the shown contents. 118 Public method to clear the shown contents.
173 """ 119 """
174 self.__contents.setHtml("") 120 if self.__viewerType == "QTextEdit":
121 self.__contents.clear()
122 else:
123 self.__contents.setHtml("")
175 124
176 125
177 class CodeDocumentationViewer(QWidget): 126 class CodeDocumentationViewer(QWidget):
178 """ 127 """
179 Class implementing a widget to show some source code information provided 128 Class implementing a widget to show some source code information provided
254 self.objectLineEdit.setObjectName("objectLineEdit") 203 self.objectLineEdit.setObjectName("objectLineEdit")
255 204
256 self.verticalLayout.addLayout(self.horizontalLayout1) 205 self.verticalLayout.addLayout(self.horizontalLayout1)
257 self.verticalLayout.addWidget(self.objectLineEdit) 206 self.verticalLayout.addWidget(self.objectLineEdit)
258 207
259 try: 208 # Rich Text (Web) Viewer
260 # Rich Text (Web) Viewer 209 self.__viewerWidget = DocumentationViewerWidget(self)
261 self.__richTextViewer = WebViewDocumentationViewer(self) 210 self.__viewerWidget.setObjectName("__viewerWidget")
262 self.__richTextViewer.setObjectName("__richTextViewer") 211 self.verticalLayout.addWidget(self.__viewerWidget)
263 self.verticalLayout.addWidget(self.__richTextViewer) 212
264 213 # backward compatibility for plug-ins before 2018-09-17
265 self.__plainTextViewer = None 214 Preferences.setDocuViewer("ShowInfoAsRichText", True)
266
267 # backward compatibility for plug-ins before 2018-09-17
268 Preferences.setDocuViewer("ShowInfoAsRichText", True)
269 except ImportError:
270 # neither QtWebEngineWidgets nor QtWebKitWidgets is available
271 self.__richTextViewer = None
272
273 # Plain Text Viewer
274 self.__plainTextViewer = PlainTextDocumentationViewer(self)
275 self.__plainTextViewer.setObjectName("__plainTextViewer")
276 self.verticalLayout.addWidget(self.__plainTextViewer)
277
278 # backward compatibility for plug-ins before 2018-09-17
279 Preferences.setDocuViewer("ShowInfoAsRichText", False)
280 215
281 self.providerComboBox.currentIndexChanged[int].connect( 216 self.providerComboBox.currentIndexChanged[int].connect(
282 self.on_providerComboBox_currentIndexChanged) 217 self.on_providerComboBox_currentIndexChanged)
283 218
284 def finalizeSetup(self): 219 def finalizeSetup(self):
404 # try again one index before 339 # try again one index before
405 word = editor.getWord(line, index - 1) 340 word = editor.getWord(line, index - 1)
406 self.objectLineEdit.setText(word) 341 self.objectLineEdit.setText(word)
407 342
408 if self.__selectedProvider != self.__disabledProvider: 343 if self.__selectedProvider != self.__disabledProvider:
409 if self.__richTextViewer: 344 self.__viewerWidget.clear()
410 self.__richTextViewer.clear()
411 else:
412 self.__plainTextViewer.clear()
413 self.__providers[self.__selectedProvider][0](editor) 345 self.__providers[self.__selectedProvider][0](editor)
414 346
415 def documentationReady(self, documentationInfo, isWarning=False, 347 def documentationReady(self, documentationInfo, isWarning=False,
416 isDocWarning=False): 348 isDocWarning=False):
417 """ 349 """
444 self.__showDisabledMessage() 376 self.__showDisabledMessage()
445 else: 377 else:
446 self.documentationReady(self.tr("No documentation available"), 378 self.documentationReady(self.tr("No documentation available"),
447 isDocWarning=True) 379 isDocWarning=True)
448 else: 380 else:
449 if self.__richTextViewer: 381 if isWarning:
450 if isWarning: 382 html = prepareDocumentationViewerHtmlWarningDocument(
451 html = prepareDocumentationViewerHtmlWarningDocument( 383 documentationInfo)
452 documentationInfo) 384 elif isDocWarning:
453 elif isDocWarning: 385 html = prepareDocumentationViewerHtmlDocWarningDocument(
454 html = prepareDocumentationViewerHtmlDocWarningDocument( 386 documentationInfo)
455 documentationInfo) 387 elif isinstance(documentationInfo, dict):
456 elif isinstance(documentationInfo, dict): 388 html = prepareDocumentationViewerHtmlDocument(
457 html = prepareDocumentationViewerHtmlDocument( 389 documentationInfo)
458 documentationInfo)
459 else:
460 html = documentationInfo
461 self.__setHtml(html)
462 else: 390 else:
463 if isinstance(documentationInfo, basestring): 391 html = documentationInfo
464 fullText = documentationInfo 392 self.__viewerWidget.setHtml(html)
465 elif isinstance(documentationInfo, dict):
466 name = documentationInfo["name"]
467 if name:
468 title = "".join([name, "\n",
469 "=" * len(name), "\n\n"])
470
471 if "argspec" in documentationInfo and \
472 documentationInfo["argspec"]:
473 definition = self.tr("Definition: {0}{1}\n")\
474 .format(name, documentationInfo["argspec"])
475 elif name:
476 definition = self.tr("Definition: {0}\n")\
477 .format(name)
478 else:
479 definition = ""
480
481 if "typ" in documentationInfo and \
482 documentationInfo["typ"]:
483 typeInfo = self.tr("Type: {0}\n").format(
484 documentationInfo["typ"])
485 else:
486 typeInfo = ""
487
488 if "note" in documentationInfo and \
489 documentationInfo["note"]:
490 note = self.tr("Note: {0}\n").format(
491 documentationInfo["note"])
492 else:
493 note = ""
494
495 header = "".join([title, definition, typeInfo, note])
496 else:
497 header = ""
498
499 if "docstring" not in documentationInfo or \
500 not documentationInfo["docstring"]:
501 docString = self.tr(
502 "No further documentation available")
503 else:
504 if header:
505 docString = "\n----\n\n{0}".format(
506 documentationInfo["docstring"])
507 else:
508 docString = documentationInfo["docstring"]
509
510 fullText = "".join([header, docString])
511
512 self.__plainTextViewer.setText(fullText)
513 393
514 def __showDisabledMessage(self): 394 def __showDisabledMessage(self):
515 """ 395 """
516 Private method to show a message giving the reason for being disabled. 396 Private method to show a message giving the reason for being disabled.
517 """ 397 """
523 else: 403 else:
524 self.documentationReady( 404 self.documentationReady(
525 self.tr("This function has been disabled."), 405 self.tr("This function has been disabled."),
526 isWarning=True) 406 isWarning=True)
527 407
528 def __setHtml(self, html):
529 """
530 Private slot to set the prepared HTML text.
531
532 @param html prepared HTML text
533 @type str
534 """
535 if self.__richTextViewer:
536 self.__richTextViewer.setHtml(html)
537
538 @pyqtSlot(int) 408 @pyqtSlot(int)
539 def on_providerComboBox_currentIndexChanged(self, index): 409 def on_providerComboBox_currentIndexChanged(self, index):
540 """ 410 """
541 Private slot to handle the selection of a provider. 411 Private slot to handle the selection of a provider.
542 412
543 @param index index of the selected provider 413 @param index index of the selected provider
544 @type int 414 @type int
545 """ 415 """
546 if not self.__shuttingDown and not self.__startingUp: 416 if not self.__shuttingDown and not self.__startingUp:
547 if self.__richTextViewer: 417 self.__viewerWidget.clear()
548 self.__richTextViewer.clear()
549 else:
550 self.__plainTextViewer.clear()
551 self.objectLineEdit.clear() 418 self.objectLineEdit.clear()
552 419
553 provider = self.providerComboBox.itemData(index) 420 provider = self.providerComboBox.itemData(index)
554 if provider == self.__disabledProvider: 421 if provider == self.__disabledProvider:
555 self.__showDisabledMessage() 422 self.__showDisabledMessage()

eric ide

mercurial