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