1#!/usr/bin/env python 2 3############################################################################# 4## 5## Copyright (C) 2013 Riverbank Computing Limited 6## Copyright (C) 2010 Hans-Peter Jansen <hpj@urpla.net>. 7## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 8## All rights reserved. 9## 10## This file is part of the examples of PyQt. 11## 12## $QT_BEGIN_LICENSE:BSD$ 13## You may use this file under the terms of the BSD license as follows: 14## 15## "Redistribution and use in source and binary forms, with or without 16## modification, are permitted provided that the following conditions are 17## met: 18## * Redistributions of source code must retain the above copyright 19## notice, this list of conditions and the following disclaimer. 20## * Redistributions in binary form must reproduce the above copyright 21## notice, this list of conditions and the following disclaimer in 22## the documentation and/or other materials provided with the 23## distribution. 24## * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor 25## the names of its contributors may be used to endorse or promote 26## products derived from this software without specific prior written 27## permission. 28## 29## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 40## $QT_END_LICENSE$ 41## 42########################################################################### 43 44 45from PyQt5.QtCore import QFile, QIODevice, Qt, QTextStream, QUrl 46from PyQt5.QtWidgets import (QAction, QApplication, QLineEdit, QMainWindow, 47 QSizePolicy, QStyle, QTextEdit) 48from PyQt5.QtNetwork import QNetworkProxyFactory, QNetworkRequest 49from PyQt5.QtWebKitWidgets import QWebPage, QWebView 50 51import jquery_rc 52 53 54class MainWindow(QMainWindow): 55 def __init__(self, url): 56 super(MainWindow, self).__init__() 57 58 self.progress = 0 59 60 fd = QFile(":/jquery.min.js") 61 62 if fd.open(QIODevice.ReadOnly | QFile.Text): 63 self.jQuery = QTextStream(fd).readAll() 64 fd.close() 65 else: 66 self.jQuery = '' 67 68 QNetworkProxyFactory.setUseSystemConfiguration(True) 69 70 self.view = QWebView(self) 71 self.view.load(url) 72 self.view.loadFinished.connect(self.adjustLocation) 73 self.view.titleChanged.connect(self.adjustTitle) 74 self.view.loadProgress.connect(self.setProgress) 75 self.view.loadFinished.connect(self.finishLoading) 76 77 self.locationEdit = QLineEdit(self) 78 self.locationEdit.setSizePolicy(QSizePolicy.Expanding, 79 self.locationEdit.sizePolicy().verticalPolicy()) 80 self.locationEdit.returnPressed.connect(self.changeLocation) 81 82 toolBar = self.addToolBar("Navigation") 83 toolBar.addAction(self.view.pageAction(QWebPage.Back)) 84 toolBar.addAction(self.view.pageAction(QWebPage.Forward)) 85 toolBar.addAction(self.view.pageAction(QWebPage.Reload)) 86 toolBar.addAction(self.view.pageAction(QWebPage.Stop)) 87 toolBar.addWidget(self.locationEdit) 88 89 viewMenu = self.menuBar().addMenu("&View") 90 viewSourceAction = QAction("Page Source", self) 91 viewSourceAction.triggered.connect(self.viewSource) 92 viewMenu.addAction(viewSourceAction) 93 94 effectMenu = self.menuBar().addMenu("&Effect") 95 effectMenu.addAction("Highlight all links", self.highlightAllLinks) 96 97 self.rotateAction = QAction( 98 self.style().standardIcon(QStyle.SP_FileDialogDetailedView), 99 "Turn images upside down", self, checkable=True, 100 toggled=self.rotateImages) 101 effectMenu.addAction(self.rotateAction) 102 103 toolsMenu = self.menuBar().addMenu("&Tools") 104 toolsMenu.addAction("Remove GIF images", self.removeGifImages) 105 toolsMenu.addAction("Remove all inline frames", 106 self.removeInlineFrames) 107 toolsMenu.addAction("Remove all object elements", 108 self.removeObjectElements) 109 toolsMenu.addAction("Remove all embedded elements", 110 self.removeEmbeddedElements) 111 self.setCentralWidget(self.view) 112 113 def viewSource(self): 114 accessManager = self.view.page().networkAccessManager() 115 request = QNetworkRequest(self.view.url()) 116 reply = accessManager.get(request) 117 reply.finished.connect(self.slotSourceDownloaded) 118 119 def slotSourceDownloaded(self): 120 reply = self.sender() 121 self.textEdit = QTextEdit() 122 self.textEdit.setAttribute(Qt.WA_DeleteOnClose) 123 self.textEdit.show() 124 self.textEdit.setPlainText(QTextStream(reply).readAll()) 125 self.textEdit.resize(600, 400) 126 reply.deleteLater() 127 128 def adjustLocation(self): 129 self.locationEdit.setText(self.view.url().toString()) 130 131 def changeLocation(self): 132 url = QUrl.fromUserInput(self.locationEdit.text()) 133 self.view.load(url) 134 self.view.setFocus() 135 136 def adjustTitle(self): 137 if 0 < self.progress < 100: 138 self.setWindowTitle("%s (%s%%)" % (self.view.title(), self.progress)) 139 else: 140 self.setWindowTitle(self.view.title()) 141 142 def setProgress(self, p): 143 self.progress = p 144 self.adjustTitle() 145 146 def finishLoading(self): 147 self.progress = 100 148 self.adjustTitle() 149 self.view.page().mainFrame().evaluateJavaScript(self.jQuery) 150 self.rotateImages(self.rotateAction.isChecked()) 151 152 def highlightAllLinks(self): 153 code = """$('a').each( 154 function () { 155 $(this).css('background-color', 'yellow') 156 } 157 )""" 158 self.view.page().mainFrame().evaluateJavaScript(code) 159 160 def rotateImages(self, invert): 161 if invert: 162 code = """ 163 $('img').each( 164 function () { 165 $(this).css('-webkit-transition', '-webkit-transform 2s'); 166 $(this).css('-webkit-transform', 'rotate(180deg)') 167 } 168 )""" 169 else: 170 code = """ 171 $('img').each( 172 function () { 173 $(this).css('-webkit-transition', '-webkit-transform 2s'); 174 $(this).css('-webkit-transform', 'rotate(0deg)') 175 } 176 )""" 177 178 self.view.page().mainFrame().evaluateJavaScript(code) 179 180 def removeGifImages(self): 181 code = "$('[src*=gif]').remove()" 182 self.view.page().mainFrame().evaluateJavaScript(code) 183 184 def removeInlineFrames(self): 185 code = "$('iframe').remove()" 186 self.view.page().mainFrame().evaluateJavaScript(code) 187 188 def removeObjectElements(self): 189 code = "$('object').remove()" 190 self.view.page().mainFrame().evaluateJavaScript(code) 191 192 def removeEmbeddedElements(self): 193 code = "$('embed').remove()" 194 self.view.page().mainFrame().evaluateJavaScript(code) 195 196 197if __name__ == '__main__': 198 199 import sys 200 201 app = QApplication(sys.argv) 202 203 if len(sys.argv) > 1: 204 url = QUrl(sys.argv[1]) 205 else: 206 url = QUrl('http://www.google.com/ncr') 207 208 browser = MainWindow(url) 209 browser.show() 210 211 sys.exit(app.exec_()) 212