UI/Previewers/PreviewerHTML.py

branch
6_1_x
changeset 4849
4eb0fba3b6c5
parent 4632
ca310db386ed
child 4930
53c81938e911
equal deleted inserted replaced
4848:36b1d9bec8f6 4849:4eb0fba3b6c5
20 import shutil 20 import shutil
21 import tempfile 21 import tempfile
22 import sys 22 import sys
23 23
24 from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QUrl, QSize, QThread 24 from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QUrl, QSize, QThread
25 from PyQt5.QtWidgets import QWidget 25 from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QCheckBox, \
26 from PyQt5.QtWebKitWidgets import QWebPage 26 QSizePolicy
27 27
28 from E5Gui.E5Application import e5App 28 from E5Gui.E5Application import e5App
29
30 from .Ui_PreviewerHTML import Ui_PreviewerHTML
31 29
32 import Utilities 30 import Utilities
33 import Preferences 31 import Preferences
34 32
35 33
36 class PreviewerHTML(QWidget, Ui_PreviewerHTML): 34 class PreviewerHTML(QWidget):
37 """ 35 """
38 Class implementing a previewer widget for HTML, Markdown and ReST files. 36 Class implementing a previewer widget for HTML, Markdown and ReST files.
39 """ 37 """
40 def __init__(self, parent=None): 38 def __init__(self, parent=None):
41 """ 39 """
42 Constructor 40 Constructor
43 41
44 @param parent reference to the parent widget (QWidget) 42 @param parent reference to the parent widget (QWidget)
45 """ 43 """
46 super(PreviewerHTML, self).__init__(parent) 44 super(PreviewerHTML, self).__init__(parent)
47 self.setupUi(self) 45
46 self.__layout = QVBoxLayout(self)
47
48 self.titleLabel = QLabel(self)
49 self.titleLabel.setWordWrap(True)
50 self.titleLabel.setTextInteractionFlags(Qt.NoTextInteraction)
51 self.__layout.addWidget(self.titleLabel)
52
53 try:
54 from PyQt5.QtWebKitWidgets import QWebPage, QWebView
55 self.previewView = QWebView(self)
56 self.previewView.page().setLinkDelegationPolicy(
57 QWebPage.DelegateAllLinks)
58 self.__usesWebKit = True
59 except ImportError:
60 from PyQt5.QtWebEngineWidgets import QWebEngineView
61 self.previewView = QWebEngineView(self)
62 self.__usesWebKit = False
63
64 sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
65 sizePolicy.setHorizontalStretch(0)
66 sizePolicy.setVerticalStretch(0)
67 sizePolicy.setHeightForWidth(
68 self.previewView.sizePolicy().hasHeightForWidth())
69 self.previewView.setSizePolicy(sizePolicy)
70 self.previewView.setContextMenuPolicy(Qt.NoContextMenu)
71 self.previewView.setUrl(QUrl("about:blank"))
72 self.__layout.addWidget(self.previewView)
73
74 self.jsCheckBox = QCheckBox(self.tr("Enable JavaScript"), self)
75 self.jsCheckBox.setToolTip(self.tr(
76 "Select to enable JavaScript for HTML previews"))
77 self.__layout.addWidget(self.jsCheckBox)
78
79 self.ssiCheckBox = QCheckBox(self.tr("Enable Server Side Includes"),
80 self)
81 self.ssiCheckBox.setToolTip(self.tr(
82 "Select to enable support for Server Side Includes"))
83 self.__layout.addWidget(self.ssiCheckBox)
84
85 self.jsCheckBox.clicked[bool].connect(self.on_jsCheckBox_clicked)
86 self.ssiCheckBox.clicked[bool].connect(self.on_ssiCheckBox_clicked)
87 self.previewView.titleChanged.connect(self.on_previewView_titleChanged)
88 if self.__usesWebKit:
89 self.previewView.linkClicked.connect(
90 self.on_previewView_linkClicked)
48 91
49 self.jsCheckBox.setChecked( 92 self.jsCheckBox.setChecked(
50 Preferences.getUI("ShowFilePreviewJS")) 93 Preferences.getUI("ShowFilePreviewJS"))
51 self.ssiCheckBox.setChecked( 94 self.ssiCheckBox.setChecked(
52 Preferences.getUI("ShowFilePreviewSSI")) 95 Preferences.getUI("ShowFilePreviewSSI"))
53
54 self.previewView.page().setLinkDelegationPolicy(
55 QWebPage.DelegateAllLinks)
56 96
57 self.__scrollBarPositions = {} 97 self.__scrollBarPositions = {}
58 self.__vScrollBarAtEnd = {} 98 self.__vScrollBarAtEnd = {}
59 self.__hScrollBarAtEnd = {} 99 self.__hScrollBarAtEnd = {}
60 100
156 positions. 196 positions.
157 197
158 @param filePath file path of the previewed editor (string) 198 @param filePath file path of the previewed editor (string)
159 @param html processed HTML text ready to be shown (string) 199 @param html processed HTML text ready to be shown (string)
160 """ 200 """
161 self.__saveScrollBarPositions()
162 self.__previewedPath = Utilities.normcasepath( 201 self.__previewedPath = Utilities.normcasepath(
163 Utilities.fromNativeSeparators(filePath)) 202 Utilities.fromNativeSeparators(filePath))
164 self.previewView.page().mainFrame().contentsSizeChanged.connect( 203 self.__saveScrollBarPositions()
165 self.__restoreScrollBarPositions) 204 if self.__usesWebKit:
205 self.previewView.page().mainFrame().contentsSizeChanged.connect(
206 self.__restoreScrollBarPositions)
207 else:
208 self.previewView.page().loadFinished.connect(
209 self.__restoreScrollBarPositions)
166 self.previewView.setHtml(html, baseUrl=QUrl.fromLocalFile(filePath)) 210 self.previewView.setHtml(html, baseUrl=QUrl.fromLocalFile(filePath))
167 211
168 @pyqtSlot(str) 212 @pyqtSlot(str)
169 def on_previewView_titleChanged(self, title): 213 def on_previewView_titleChanged(self, title):
170 """ 214 """
179 223
180 def __saveScrollBarPositions(self): 224 def __saveScrollBarPositions(self):
181 """ 225 """
182 Private method to save scroll bar positions for a previewed editor. 226 Private method to save scroll bar positions for a previewed editor.
183 """ 227 """
184 frame = self.previewView.page().mainFrame() 228 if self.__usesWebKit:
185 if frame.contentsSize() == QSize(0, 0): 229 frame = self.previewView.page().mainFrame()
186 return # no valid data, nothing to save 230 if frame.contentsSize() == QSize(0, 0):
187 231 return # no valid data, nothing to save
188 pos = frame.scrollPosition() 232
189 self.__scrollBarPositions[self.__previewedPath] = pos 233 pos = frame.scrollPosition()
190 self.__hScrollBarAtEnd[self.__previewedPath] = \ 234 self.__scrollBarPositions[self.__previewedPath] = pos
191 frame.scrollBarMaximum(Qt.Horizontal) == pos.x() 235 self.__hScrollBarAtEnd[self.__previewedPath] = \
192 self.__vScrollBarAtEnd[self.__previewedPath] = \ 236 frame.scrollBarMaximum(Qt.Horizontal) == pos.x()
193 frame.scrollBarMaximum(Qt.Vertical) == pos.y() 237 self.__vScrollBarAtEnd[self.__previewedPath] = \
238 frame.scrollBarMaximum(Qt.Vertical) == pos.y()
239 else:
240 from PyQt5.QtCore import QPoint
241 pos = self.__execJavaScript(
242 "(function() {"
243 "var res = {"
244 " x: 0,"
245 " y: 0,"
246 "};"
247 "res.x = window.scrollX;"
248 "res.y = window.scrollY;"
249 "return res;"
250 "})()"
251 )
252 pos = QPoint(pos["x"], pos["y"])
253 self.__scrollBarPositions[self.__previewedPath] = pos
254 self.__hScrollBarAtEnd[self.__previewedPath] = False
255 self.__vScrollBarAtEnd[self.__previewedPath] = False
194 256
195 def __restoreScrollBarPositions(self): 257 def __restoreScrollBarPositions(self):
196 """ 258 """
197 Private method to restore scroll bar positions for a previewed editor. 259 Private method to restore scroll bar positions for a previewed editor.
198 """ 260 """
199 try: 261 if self.__usesWebKit:
200 self.previewView.page().mainFrame().contentsSizeChanged.disconnect( 262 try:
201 self.__restoreScrollBarPositions) 263 self.previewView.page().mainFrame().contentsSizeChanged.\
202 except TypeError: 264 disconnect(self.__restoreScrollBarPositions)
203 # not connected, simply ignore it 265 except TypeError:
204 pass 266 # not connected, simply ignore it
205 267 pass
206 if self.__previewedPath not in self.__scrollBarPositions: 268
207 return 269 if self.__previewedPath not in self.__scrollBarPositions:
208 270 return
209 frame = self.previewView.page().mainFrame() 271
210 frame.setScrollPosition( 272 frame = self.previewView.page().mainFrame()
211 self.__scrollBarPositions[self.__previewedPath]) 273 frame.setScrollPosition(
212 274 self.__scrollBarPositions[self.__previewedPath])
213 if self.__hScrollBarAtEnd[self.__previewedPath]: 275
214 frame.setScrollBarValue( 276 if self.__hScrollBarAtEnd[self.__previewedPath]:
215 Qt.Horizontal, frame.scrollBarMaximum(Qt.Horizontal)) 277 frame.setScrollBarValue(
216 278 Qt.Horizontal, frame.scrollBarMaximum(Qt.Horizontal))
217 if self.__vScrollBarAtEnd[self.__previewedPath]: 279
218 frame.setScrollBarValue( 280 if self.__vScrollBarAtEnd[self.__previewedPath]:
219 Qt.Vertical, frame.scrollBarMaximum(Qt.Vertical)) 281 frame.setScrollBarValue(
282 Qt.Vertical, frame.scrollBarMaximum(Qt.Vertical))
283 else:
284 if self.__previewedPath not in self.__scrollBarPositions:
285 return
286
287 pos = self.__scrollBarPositions[self.__previewedPath]
288 self.previewView.page().runJavaScript(
289 "window.scrollTo({0}, {1});".format(pos.x(), pos.y()))
220 290
221 @pyqtSlot(QUrl) 291 @pyqtSlot(QUrl)
222 def on_previewView_linkClicked(self, url): 292 def on_previewView_linkClicked(self, url):
223 """ 293 """
224 Private slot handling the clicking of a link. 294 Private slot handling the clicking of a link.
225 295
226 @param url url of the clicked link (QUrl) 296 @param url url of the clicked link (QUrl)
227 """ 297 """
228 e5App().getObject("UserInterface").launchHelpViewer(url.toString()) 298 e5App().getObject("UserInterface").launchHelpViewer(url.toString())
299
300 def __execJavaScript(self, script):
301 """
302 Private function to execute a JavaScript function Synchroneously.
303
304 @param script JavaScript script source to be executed
305 @type str
306 @return result of the script
307 @rtype depending upon script result
308 """
309 from PyQt5.QtCore import QEventLoop
310 loop = QEventLoop()
311 resultDict = {"res": None}
312
313 def resultCallback(res, resDict=resultDict):
314 if loop and loop.isRunning():
315 resDict["res"] = res
316 loop.quit()
317
318 self.previewView.page().runJavaScript(
319 script, resultCallback)
320
321 loop.exec_()
322 return resultDict["res"]
229 323
230 324
231 class PreviewProcessingThread(QThread): 325 class PreviewProcessingThread(QThread):
232 """ 326 """
233 Class implementing a thread to process some text into HTML usable by the 327 Class implementing a thread to process some text into HTML usable by the

eric ide

mercurial