eric6/UI/Previewers/PreviewerHTML.py

branch
maintenance
changeset 7286
7eb04391adf7
parent 6989
8b8cadf8d7e9
parent 7264
bedbe458d792
child 7322
cd8ee889589f
equal deleted inserted replaced
7226:babe80d84a3e 7286:7eb04391adf7
5 5
6 """ 6 """
7 Module implementing a previewer widget for HTML, Markdown and ReST files. 7 Module implementing a previewer widget for HTML, Markdown and ReST files.
8 """ 8 """
9 9
10 from __future__ import unicode_literals
11
12 try: # Only for Py2
13 import StringIO as io # __IGNORE_EXCEPTION__
14 str = unicode
15 except (ImportError, NameError):
16 import io # __IGNORE_WARNING__
17 10
18 import os 11 import os
19 import threading 12 import threading
20 import re 13 import re
21 import shutil 14 import shutil
22 import tempfile 15 import tempfile
23 import sys 16 import sys
24 17 import io
25 from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QUrl, QSize, QThread 18
19 from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QUrl, QThread
26 from PyQt5.QtGui import QCursor 20 from PyQt5.QtGui import QCursor
27 from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QCheckBox, \ 21 from PyQt5.QtWidgets import (
28 QSizePolicy, QToolTip 22 QWidget, QVBoxLayout, QLabel, QCheckBox, QSizePolicy, QToolTip
23 )
29 24
30 from E5Gui.E5Application import e5App 25 from E5Gui.E5Application import e5App
31 26
32 import Utilities 27 import Utilities
33 import Preferences 28 import Preferences
56 51
57 try: 52 try:
58 from PyQt5.QtWebEngineWidgets import QWebEngineView 53 from PyQt5.QtWebEngineWidgets import QWebEngineView
59 self.previewView = QWebEngineView(self) 54 self.previewView = QWebEngineView(self)
60 self.previewView.page().linkHovered.connect(self.__showLink) 55 self.previewView.page().linkHovered.connect(self.__showLink)
61 self.__usesWebKit = False
62 except ImportError: 56 except ImportError:
63 try: 57 self.__previewAvailable = False
64 from PyQt5.QtWebKitWidgets import QWebPage, QWebView 58 self.titleLabel.setText(self.tr(
65 self.previewView = QWebView(self) 59 "<b>HTML Preview is not available!<br/>"
66 self.previewView.page().setLinkDelegationPolicy( 60 "Install QtWebEngine.</b>"))
67 QWebPage.DelegateAllLinks) 61 self.titleLabel.setAlignment(Qt.AlignHCenter)
68 self.__usesWebKit = True 62 self.__layout.addStretch()
69 except ImportError: 63 return
70 self.__previewAvailable = False
71 self.titleLabel.setText(self.tr(
72 "<b>HTML Preview is not available!<br/>"
73 "Install QtWebEngine or QtWebKit.</b>"))
74 self.titleLabel.setAlignment(Qt.AlignHCenter)
75 self.__layout.addStretch()
76 return
77 64
78 sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) 65 sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
79 sizePolicy.setHorizontalStretch(0) 66 sizePolicy.setHorizontalStretch(0)
80 sizePolicy.setVerticalStretch(0) 67 sizePolicy.setVerticalStretch(0)
81 sizePolicy.setHeightForWidth( 68 sizePolicy.setHeightForWidth(
97 self.__layout.addWidget(self.ssiCheckBox) 84 self.__layout.addWidget(self.ssiCheckBox)
98 85
99 self.jsCheckBox.clicked[bool].connect(self.on_jsCheckBox_clicked) 86 self.jsCheckBox.clicked[bool].connect(self.on_jsCheckBox_clicked)
100 self.ssiCheckBox.clicked[bool].connect(self.on_ssiCheckBox_clicked) 87 self.ssiCheckBox.clicked[bool].connect(self.on_ssiCheckBox_clicked)
101 self.previewView.titleChanged.connect(self.on_previewView_titleChanged) 88 self.previewView.titleChanged.connect(self.on_previewView_titleChanged)
102 if self.__usesWebKit:
103 self.previewView.linkClicked.connect(
104 self.on_previewView_linkClicked)
105 89
106 self.jsCheckBox.setChecked( 90 self.jsCheckBox.setChecked(
107 Preferences.getUI("ShowFilePreviewJS")) 91 Preferences.getUI("ShowFilePreviewJS"))
108 self.ssiCheckBox.setChecked( 92 self.ssiCheckBox.setChecked(
109 Preferences.getUI("ShowFilePreviewSSI")) 93 Preferences.getUI("ShowFilePreviewSSI"))
187 171
188 if fn: 172 if fn:
189 extension = os.path.normcase(os.path.splitext(fn)[1][1:]) 173 extension = os.path.normcase(os.path.splitext(fn)[1][1:])
190 else: 174 else:
191 extension = "" 175 extension = ""
192 if extension in \ 176 if (
193 Preferences.getEditor("PreviewHtmlFileNameExtensions") or \ 177 extension in Preferences.getEditor(
194 editor.getLanguage() == "HTML": 178 "PreviewHtmlFileNameExtensions") or
179 editor.getLanguage() == "HTML"
180 ):
195 language = "HTML" 181 language = "HTML"
196 elif extension in \ 182 elif (
197 Preferences.getEditor("PreviewMarkdownFileNameExtensions") or \ 183 extension in Preferences.getEditor(
198 editor.getLanguage().lower() == "markdown": 184 "PreviewMarkdownFileNameExtensions") or
185 editor.getLanguage().lower() == "markdown"
186 ):
199 language = "Markdown" 187 language = "Markdown"
200 elif extension in \ 188 elif (
201 Preferences.getEditor("PreviewRestFileNameExtensions") or \ 189 extension in Preferences.getEditor(
202 editor.getLanguage().lower() == "restructuredtext": 190 "PreviewRestFileNameExtensions") or
191 editor.getLanguage().lower() == "restructuredtext"
192 ):
203 language = "ReST" 193 language = "ReST"
204 else: 194 else:
205 self.__setHtml(fn, self.tr( 195 self.__setHtml(fn, self.tr(
206 "<p>No preview available for this type of file.</p>")) 196 "<p>No preview available for this type of file.</p>"))
207 return 197 return
237 @type str 227 @type str
238 """ 228 """
239 self.__previewedPath = Utilities.normcasepath( 229 self.__previewedPath = Utilities.normcasepath(
240 Utilities.fromNativeSeparators(filePath)) 230 Utilities.fromNativeSeparators(filePath))
241 self.__saveScrollBarPositions() 231 self.__saveScrollBarPositions()
242 if self.__usesWebKit: 232 self.previewView.page().loadFinished.connect(
243 self.previewView.page().mainFrame().contentsSizeChanged.connect( 233 self.__restoreScrollBarPositions)
244 self.__restoreScrollBarPositions) 234 if not filePath:
245 else: 235 filePath = "/"
246 self.previewView.page().loadFinished.connect(
247 self.__restoreScrollBarPositions)
248 if not filePath:
249 filePath = "/"
250 if rootPath: 236 if rootPath:
251 baseUrl = QUrl.fromLocalFile(rootPath + "/index.html") 237 baseUrl = QUrl.fromLocalFile(rootPath + "/index.html")
252 else: 238 else:
253 baseUrl = QUrl.fromLocalFile(filePath) 239 baseUrl = QUrl.fromLocalFile(filePath)
254 self.previewView.setHtml(html, baseUrl=baseUrl) 240 self.previewView.setHtml(html, baseUrl=baseUrl)
269 255
270 def __saveScrollBarPositions(self): 256 def __saveScrollBarPositions(self):
271 """ 257 """
272 Private method to save scroll bar positions for a previewed editor. 258 Private method to save scroll bar positions for a previewed editor.
273 """ 259 """
274 if self.__usesWebKit: 260 from PyQt5.QtCore import QPoint
275 frame = self.previewView.page().mainFrame() 261 try:
276 if frame.contentsSize() == QSize(0, 0): 262 pos = self.previewView.scrollPosition()
277 return # no valid data, nothing to save 263 except AttributeError:
278 264 pos = self.__execJavaScript(
279 pos = frame.scrollPosition() 265 "(function() {"
280 self.__scrollBarPositions[self.__previewedPath] = pos 266 "var res = {"
281 self.__hScrollBarAtEnd[self.__previewedPath] = \ 267 " x: 0,"
282 frame.scrollBarMaximum(Qt.Horizontal) == pos.x() 268 " y: 0,"
283 self.__vScrollBarAtEnd[self.__previewedPath] = \ 269 "};"
284 frame.scrollBarMaximum(Qt.Vertical) == pos.y() 270 "res.x = window.scrollX;"
285 else: 271 "res.y = window.scrollY;"
286 from PyQt5.QtCore import QPoint 272 "return res;"
287 try: 273 "})()"
288 pos = self.previewView.scrollPosition() 274 )
289 except AttributeError: 275 if pos is not None:
290 pos = self.__execJavaScript( 276 pos = QPoint(pos["x"], pos["y"])
291 "(function() {" 277 else:
292 "var res = {" 278 pos = QPoint(0, 0)
293 " x: 0," 279 self.__scrollBarPositions[self.__previewedPath] = pos
294 " y: 0," 280 self.__hScrollBarAtEnd[self.__previewedPath] = False
295 "};" 281 self.__vScrollBarAtEnd[self.__previewedPath] = False
296 "res.x = window.scrollX;"
297 "res.y = window.scrollY;"
298 "return res;"
299 "})()"
300 )
301 if pos is not None:
302 pos = QPoint(pos["x"], pos["y"])
303 else:
304 pos = QPoint(0, 0)
305 self.__scrollBarPositions[self.__previewedPath] = pos
306 self.__hScrollBarAtEnd[self.__previewedPath] = False
307 self.__vScrollBarAtEnd[self.__previewedPath] = False
308 282
309 def __restoreScrollBarPositions(self): 283 def __restoreScrollBarPositions(self):
310 """ 284 """
311 Private method to restore scroll bar positions for a previewed editor. 285 Private method to restore scroll bar positions for a previewed editor.
312 """ 286 """
313 if self.__usesWebKit: 287 if self.__previewedPath not in self.__scrollBarPositions:
314 try: 288 return
315 self.previewView.page().mainFrame().contentsSizeChanged.\ 289
316 disconnect(self.__restoreScrollBarPositions) 290 pos = self.__scrollBarPositions[self.__previewedPath]
317 except TypeError: 291 self.previewView.page().runJavaScript(
318 # not connected, simply ignore it 292 "window.scrollTo({0}, {1});".format(pos.x(), pos.y()))
319 pass
320
321 if self.__previewedPath not in self.__scrollBarPositions:
322 return
323
324 frame = self.previewView.page().mainFrame()
325 frame.setScrollPosition(
326 self.__scrollBarPositions[self.__previewedPath])
327
328 if self.__hScrollBarAtEnd[self.__previewedPath]:
329 frame.setScrollBarValue(
330 Qt.Horizontal, frame.scrollBarMaximum(Qt.Horizontal))
331
332 if self.__vScrollBarAtEnd[self.__previewedPath]:
333 frame.setScrollBarValue(
334 Qt.Vertical, frame.scrollBarMaximum(Qt.Vertical))
335 else:
336 if self.__previewedPath not in self.__scrollBarPositions:
337 return
338
339 pos = self.__scrollBarPositions[self.__previewedPath]
340 self.previewView.page().runJavaScript(
341 "window.scrollTo({0}, {1});".format(pos.x(), pos.y()))
342
343 @pyqtSlot(QUrl)
344 def on_previewView_linkClicked(self, url):
345 """
346 Private slot handling the clicking of a link.
347
348 @param url URL of the clicked link
349 @type QUrl
350 """
351 e5App().getObject("UserInterface").launchHelpViewer(url)
352 293
353 def __execJavaScript(self, script): 294 def __execJavaScript(self, script):
354 """ 295 """
355 Private function to execute a JavaScript function Synchroneously. 296 Private function to execute a JavaScript function Synchroneously.
356 297
715 extensions = ['fenced_code', 'nl2br', 'extra'] 656 extensions = ['fenced_code', 'nl2br', 'extra']
716 else: 657 else:
717 extensions = ['fenced_code', 'extra'] 658 extensions = ['fenced_code', 'extra']
718 659
719 # version 2.0 supports only extension names, not instances 660 # version 2.0 supports only extension names, not instances
720 if markdown.version_info[0] > 2 or \ 661 if (
721 (markdown.version_info[0] == 2 and 662 markdown.version_info[0] > 2 or
722 markdown.version_info[1] > 0): 663 (markdown.version_info[0] == 2 and
664 markdown.version_info[1] > 0)
665 ):
723 class _StrikeThroughExtension(markdown.Extension): 666 class _StrikeThroughExtension(markdown.Extension):
724 """ 667 """
725 Class is placed here, because it depends on imported markdown, 668 Class is placed here, because it depends on imported markdown,
726 and markdown import is lazy. 669 and markdown import is lazy.
727 670

eric ide

mercurial