Continued porting the web browser. QtWebEngine

Tue, 29 Mar 2016 10:32:22 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Tue, 29 Mar 2016 10:32:22 +0200
branch
QtWebEngine
changeset 4906
939ff20f712d
parent 4905
09f38f85a3af
child 4907
1e3d61349671

Continued porting the web browser.

- added the user agents manager

Preferences/__init__.py file | annotate | diff | comparison | revisions
WebBrowser/Network/NetworkUrlInterceptor.py file | annotate | diff | comparison | revisions
WebBrowser/Sync/DirectorySyncHandler.py file | annotate | diff | comparison | revisions
WebBrowser/Sync/FtpSyncHandler.py file | annotate | diff | comparison | revisions
WebBrowser/Sync/SyncManager.py file | annotate | diff | comparison | revisions
WebBrowser/UserAgent/UserAgentDefaults.qrc file | annotate | diff | comparison | revisions
WebBrowser/UserAgent/UserAgentDefaults.xml file | annotate | diff | comparison | revisions
WebBrowser/UserAgent/UserAgentDefaults_rc.py file | annotate | diff | comparison | revisions
WebBrowser/UserAgent/UserAgentManager.py file | annotate | diff | comparison | revisions
WebBrowser/UserAgent/UserAgentMenu.py file | annotate | diff | comparison | revisions
WebBrowser/UserAgent/UserAgentModel.py file | annotate | diff | comparison | revisions
WebBrowser/UserAgent/UserAgentReader.py file | annotate | diff | comparison | revisions
WebBrowser/UserAgent/UserAgentWriter.py file | annotate | diff | comparison | revisions
WebBrowser/UserAgent/UserAgentsDialog.py file | annotate | diff | comparison | revisions
WebBrowser/UserAgent/UserAgentsDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/UserAgent/__init__.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserPage.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserView.py file | annotate | diff | comparison | revisions
WebBrowser/WebBrowserWindow.py file | annotate | diff | comparison | revisions
eric6.e4p file | annotate | diff | comparison | revisions
--- a/Preferences/__init__.py	Mon Mar 28 17:04:18 2016 +0200
+++ b/Preferences/__init__.py	Tue Mar 29 10:32:22 2016 +0200
@@ -1038,6 +1038,7 @@
         "KeepCookiesUntil": 0,      # CookieJar.KeepUntilExpire
         "FilterTrackingCookies": True,
         "SaveUrlColor": QColor(184, 248, 169),
+        "UserAgent": "",
         # Grease Monkey
         "GreaseMonkeyDisabledScripts": [],
         # Downloads
--- a/WebBrowser/Network/NetworkUrlInterceptor.py	Mon Mar 28 17:04:18 2016 +0200
+++ b/WebBrowser/Network/NetworkUrlInterceptor.py	Tue Mar 29 10:32:22 2016 +0200
@@ -12,6 +12,8 @@
 
 from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInterceptor
 
+from ..WebBrowserPage import WebBrowserPage
+
 import Preferences
 
 
@@ -49,6 +51,10 @@
                 Preferences.getWebBrowser("SendRefererWhitelist"):
             info.setHttpHeader(b"Referer", b"")
         
+        # User Agents header
+        userAgent = WebBrowserPage.userAgentForUrl(info.requestUrl())
+        info.setHttpHeader(b"User-Agent", userAgent.encode())
+        
         for interceptor in self.__interceptors:
             interceptor.interceptRequest(info)
     
--- a/WebBrowser/Sync/DirectorySyncHandler.py	Mon Mar 28 17:04:18 2016 +0200
+++ b/WebBrowser/Sync/DirectorySyncHandler.py	Tue Mar 29 10:32:22 2016 +0200
@@ -200,13 +200,12 @@
                 "passwords",
                 WebBrowserWindow.passwordManager().getFileName())
         
-        # TODO: UserAgents
-##        QCoreApplication.processEvents()
-##        # User Agent Settings
-##        if Preferences.getWebBrowser("SyncUserAgents"):
-##            self.__initialSyncFile(
-##                "useragents",
-##                WebBrowserWindow.userAgentsManager().getFileName())
+        QCoreApplication.processEvents()
+        # User Agent Settings
+        if Preferences.getWebBrowser("SyncUserAgents"):
+            self.__initialSyncFile(
+                "useragents",
+                WebBrowserWindow.userAgentsManager().getFileName())
         
         QCoreApplication.processEvents()
         # Speed Dial Settings
@@ -254,14 +253,13 @@
             "passwords",
             WebBrowserWindow.passwordManager().getFileName())
     
-    # TODO: UserAgents
     def syncUserAgents(self):
         """
         Public method to synchronize the user agents.
         """
-##        self.__syncFile(
-##            "useragents",
-##            WebBrowserWindow.userAgentsManager().getFileName())
+        self.__syncFile(
+            "useragents",
+            WebBrowserWindow.userAgentsManager().getFileName())
     
     def syncSpeedDial(self):
         """
--- a/WebBrowser/Sync/FtpSyncHandler.py	Mon Mar 28 17:04:18 2016 +0200
+++ b/WebBrowser/Sync/FtpSyncHandler.py	Tue Mar 29 10:32:22 2016 +0200
@@ -297,12 +297,11 @@
                 "passwords",
                 WebBrowserWindow.passwordManager().getFileName())
         
-        # TODO: UserAgents
         # User Agent Settings
-##        if Preferences.getWebBrowser("SyncUserAgents"):
-##            self.__initialSyncFile(
-##                "useragents",
-##                WebBrowserWindow.userAgentsManager().getFileName())
+        if Preferences.getWebBrowser("SyncUserAgents"):
+            self.__initialSyncFile(
+                "useragents",
+                WebBrowserWindow.userAgentsManager().getFileName())
         
         # Speed Dial Settings
         if Preferences.getWebBrowser("SyncSpeedDial"):
@@ -366,14 +365,13 @@
             "passwords",
             WebBrowserWindow.passwordManager().getFileName())
     
-    # TODO: UserAgents
     def syncUserAgents(self):
         """
         Public method to synchronize the user agents.
         """
-##        self.__syncFile(
-##            "useragents",
-##            WebBrowserWindow.userAgentsManager().getFileName())
+        self.__syncFile(
+            "useragents",
+            WebBrowserWindow.userAgentsManager().getFileName())
     
     def syncSpeedDial(self):
         """
--- a/WebBrowser/Sync/SyncManager.py	Mon Mar 28 17:04:18 2016 +0200
+++ b/WebBrowser/Sync/SyncManager.py	Tue Mar 29 10:32:22 2016 +0200
@@ -125,18 +125,17 @@
                 except TypeError:
                     pass
             
-            # TODO: UserAgents
             # connect sync manager to user agent manager
-##            if Preferences.getWebBrowser("SyncUserAgents"):
-##                WebBrowserWindow.userAgentsManager()\
-##                    .userAgentSettingsSaved.connect(self.__syncUserAgents)
-##            else:
-##                try:
-##                    WebBrowserWindow.userAgentsManager()\
-##                        .userAgentSettingsSaved.disconnect(
-##                            self.__syncUserAgents)
-##                except TypeError:
-##                    pass
+            if Preferences.getWebBrowser("SyncUserAgents"):
+                WebBrowserWindow.userAgentsManager()\
+                    .userAgentSettingsSaved.connect(self.__syncUserAgents)
+            else:
+                try:
+                    WebBrowserWindow.userAgentsManager()\
+                        .userAgentSettingsSaved.disconnect(
+                            self.__syncUserAgents)
+                except TypeError:
+                    pass
             
             # connect sync manager to speed dial
             if Preferences.getWebBrowser("SyncSpeedDial"):
@@ -166,12 +165,11 @@
                     .passwordsSaved.disconnect(self.__syncPasswords)
             except TypeError:
                 pass
-            # TODO: UserAgents
-##            try:
-##                WebBrowserWindow.userAgentsManager()\
-##                    .userAgentSettingsSaved.disconnect(self.__syncUserAgents)
-##            except TypeError:
-##                pass
+            try:
+                WebBrowserWindow.userAgentsManager()\
+                    .userAgentSettingsSaved.disconnect(self.__syncUserAgents)
+            except TypeError:
+                pass
             try:
                 WebBrowserWindow.speedDial()\
                     .speedDialSaved.disconnect(self.__syncSpeedDial)
@@ -248,9 +246,8 @@
                 WebBrowserWindow.historyManager().reload()
             elif type_ == "passwords":
                 WebBrowserWindow.passwordManager().reload()
-            # TODO: UserAgents
-##            elif type_ == "useragents":
-##                WebBrowserWindow.userAgentsManager().reload()
+            elif type_ == "useragents":
+                WebBrowserWindow.userAgentsManager().reload()
             elif type_ == "speeddial":
                 WebBrowserWindow.speedDial().reload()
         self.syncFinished.emit(type_, status, download)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/UserAgent/UserAgentDefaults.qrc	Tue Mar 29 10:32:22 2016 +0200
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+<qresource>
+  <file>UserAgentDefaults.xml</file>
+</qresource>
+</RCC>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/UserAgent/UserAgentDefaults.xml	Tue Mar 29 10:32:22 2016 +0200
@@ -0,0 +1,53 @@
+<useragentswitcher>
+    <useragentmenu title="Firefox">
+        <useragent description="Firefox 9.0.1 (Windows)" useragent="Mozilla/5.0 (Windows; U; Windows NT 6.2; rv:9.0.1) Gecko/20100101 Firefox/9.0.1"/>
+        <useragent description="Firefox 4.0.1 (Windows)" useragent="Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"/>
+        <useragent description="Firefox 3.5.3 (Windows)" useragent="Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3"/>
+    </useragentmenu>
+
+    <useragentmenu title="Chrome">
+        <useragent description="Chrome 18.0 (Windows)" useragent="Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.12 (KHTML, like Gecko) Chrome/18.6.872.0 Safari/535.12"/>
+        <useragent description="Chrome 17.0 (Windows)" useragent="Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.12 Safari/535.11"/>
+        <useragent description="Chrome 12.0 (Windows)" useragent="Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.30 (KHTML, like Gecko) Chrome/12.0.742.0 Safari/534.30"/>
+        <useragent description="Chrome 11.0 (Windows)" useragent="Mozilla/5.0 (Windows NT 6.1) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.50 Safari/534.24"/>
+    </useragentmenu>
+
+    <useragentmenu title="Internet Explorer">
+        <useragent description="Internet Explorer 10.0" useragent="Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1)"/>
+        <useragent description="Internet Explorer 9.0" useragent="Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1)"/>
+        <useragent description="Internet Explorer 8.0" useragent="Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1)"/>
+        <useragent description="Internet Explorer 7.0" useragent="Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"/>
+        <useragent description="Internet Explorer 6.0" useragent="Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"/>
+    </useragentmenu>
+
+    <useragentmenu title="Opera">
+        <useragent description="Opera 12.0 (Linux)" useragent="Opera/9.80 (X11; Linux x86_64; U) Presto/2.9.181 Version/12.00"/>
+        <useragent description="Opera 12.0 (Mac)" useragent="Opera/9.80 (Macintosh; Intel Mac OS X 10.6.7; U) Presto/2.9.181 Version/12.00"/>
+        <useragent description="Opera 12.0 (Windows)" useragent="Opera/9.80 (Windows NT 6.1; U) Presto/2.9.181 Version/12.00"/>
+        <useragent description="Opera 11.1 (Linux)" useragent="Opera/9.80 (X11; Linux x86_64; U; en) Presto/2.8.131 Version/11.10"/>
+        <useragent description="Opera 11.1 (Mac)" useragent="Opera/9.80 (Macintosh; Intel Mac OS X 10.6.7; U; en) Presto/2.8.131 Version/11.10"/>
+        <useragent description="Opera 11.1 (Windows)" useragent="Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.10"/>
+        <useragent description="Opera 10.0 (Linux)" useragent="Opera/9.80 (X11; Linux x86_64; U; de) Presto/2.2.15 Version/10.00"/>
+        <useragent description="Opera 10.0 (Mac)" useragent="Opera/9.80 (Macintosh; Intel Mac OS X; U; en) Presto/2.2.15 Version/10.00"/>
+        <useragent description="Opera 10.0 (Windows)" useragent="Opera/9.80 (Windows NT 6.0; U; en) Presto/2.2.15 Version/10.00"/>
+    </useragentmenu>
+
+    <useragentmenu title="Safari">
+        <useragent description="Safari 5.0.5 (Mac)" useragent="Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_7_2; en-us) AppleWebKit/535.12 (KHTML, like Gecko) Version/5.0.5 Safari/535.12"/>
+        <useragent description="Safari 5.0.4 (Mac)" useragent="Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us) AppleWebKit/533.20.25 (KHTML, like Gecko) Version/5.0.4 Safari/533.20.27"/>
+        <useragent description="Safari 4.0.4 (Mac)" useragent="Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_1; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10"/>
+        <separator/>
+        <useragent description="Mobile Safari 4.3.2 (iPad)" useragent="Mozilla/5.0 (iPad; U; CPU OS 4_3_2 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8H7 Safari/6533.18.5"/>
+        <useragent description="Mobile Safari 4.3.2 (iPhone)" useragent="Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_2 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8H7 Safari/6533.18.5"/>
+        <useragent description="Mobile Safari 4.3.2 (iPod touch)" useragent="Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_2 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8H7 Safari/6533.18.5"/>
+        <useragent description="Mobile Safari 3.1.2 (iPhone)" useragent="Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_1_2 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7D11 Safari/528.16"/>
+        <useragent description="Mobile Safari 3.1.2 (iPod touch)" useragent="Mozilla/5.0 (iPod; U; CPU iPhone OS 3_1_2 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7D11 Safari/528.16"/>
+    </useragentmenu>
+
+    <useragentmenu title="v_a_r_i_o_u_s">
+        <useragent description="Googlebot 2.1" useragent="Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"/>
+        <useragent description="Msnbot 1.1" useragent="msnbot/1.1 (+http://search.msn.com/msnbot.htm)" appcodename="" appname="" appversion="" platform="" vendor="" vendorsub=""/>
+        <useragent description="Yahoo Slurp" useragent="Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)" appcodename="" appname="" appversion="" platform="" vendor="" vendorsub=""/>
+    </useragentmenu>
+
+</useragentswitcher>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/UserAgent/UserAgentDefaults_rc.py	Tue Mar 29 10:32:22 2016 +0200
@@ -0,0 +1,98 @@
+# -*- coding: utf-8 -*-
+
+# Resource object code
+#
+# Created: So. Juni 29 18:58:08 2014
+#      by: The Resource Compiler for PyQt (Qt v5.3.1)
+#
+# WARNING! All changes made in this file will be lost!
+
+from PyQt5 import QtCore
+
+qt_resource_data = b"\
+\x00\x00\x03\xd6\
+\x00\
+\x00\x15\xe1\x78\x9c\xd5\x58\xdb\x6e\xdb\x38\x10\x7d\xef\x57\xcc\
+\xfa\x29\xc6\xee\x52\xa2\xee\xae\xd3\x02\x45\xef\x68\xbd\x0d\xe0\
+\x66\xdb\x3e\x09\xb2\xcd\x44\x42\x65\x51\xa0\xe4\x38\xdd\xaf\xdf\
+\x21\xe5\x8b\x6c\xc7\x0a\x65\xab\x05\x1a\xe4\x41\x24\x67\x74\xce\
+\x99\x19\x72\x28\x5f\x2e\x0a\x26\xa2\x5b\x96\x95\xc5\x32\x29\xa7\
+\x31\x13\xcf\x9f\x00\xfe\x5d\x6e\xe6\xe7\x2c\x5b\x40\x99\x94\x29\
+\x7b\xd6\x7b\x93\x08\x76\xc3\xef\x7b\x95\xcd\xae\x1d\xcc\x58\x31\
+\x15\x49\x5e\x26\x3c\xdb\x58\xc2\x80\x98\x84\xc2\xc5\x97\x24\x9b\
+\xf1\x65\xd1\xef\xc1\xc6\xfe\x59\x6f\xc4\xff\x4b\xd2\x34\x32\x5c\
+\x62\x6e\x2c\x86\x70\x3d\x84\xd5\x33\xfc\xf3\x19\x3c\x62\x0d\x41\
+\xdc\x3d\x55\xef\xe9\xc3\x5b\x36\xfd\xce\x0d\xcb\xa4\x26\xfe\x53\
+\x58\xa1\x18\x6a\xb5\x67\xe8\xd3\x72\xce\xa6\x45\x87\xc0\xb2\xbf\
+\xaf\xc7\x8a\x9d\xd5\xc8\xce\x69\xcb\xce\x26\x2e\xb1\xbb\x63\x47\
+\xc9\x80\x50\x62\x6f\xf9\x99\x03\x33\xb0\x9c\x0d\x3f\x05\xb7\xe6\
+\x77\x69\xec\x64\xfe\xf9\x93\x86\x72\x78\x19\x0b\x3e\x67\x1a\xd5\
+\x50\x19\x02\x0d\x6a\xa4\x1f\x97\xb5\x92\xd2\x87\x17\x79\x9e\xb2\
+\x2f\x6c\xf2\x21\x29\x0d\xd7\x76\x09\xb5\xe0\xe2\xc3\xbb\xcf\xa3\
+\x8f\x7f\x41\x9a\x7c\x67\x95\xae\x3e\x54\x28\x06\xa2\x78\x24\xf0\
+\x31\x27\x30\x8e\x6e\x22\x91\xac\x7c\x74\x32\xb0\x26\xea\x77\x44\
+\x94\x36\x12\x45\x14\x32\xf0\x6c\xa9\xa7\xce\x54\xab\x56\xd6\x4c\
+\xad\x2e\x98\x3a\xc4\x36\x1b\x99\xca\x02\xf7\x9d\x9d\x90\x4a\x9f\
+\x36\x44\x69\x37\x44\xb1\x6e\x9b\x88\x22\x0a\xf1\x06\x1e\x71\x77\
+\x98\x5a\xce\x29\xe5\xfd\x3e\x2b\x99\xc8\x58\x09\xaf\xef\xf3\x94\
+\x0b\x26\x34\x2a\xfd\xc0\x07\xa8\x49\xcc\xe3\x72\xa7\x7c\x9e\x47\
+\x65\x32\x49\xd9\x10\x46\xe3\xf7\xaf\x95\xf9\xfe\x66\xee\xeb\xc4\
+\xf9\x10\x79\x70\x04\xd8\x79\x10\x78\xd0\x19\x6e\xd0\x0a\x37\xe8\
+\x0c\xd7\x6f\x85\xeb\x1f\xe0\x9a\x27\xe2\x7a\xad\x70\xbd\x3d\x5c\
+\xb7\xa6\xb7\x4d\x75\x7e\xca\x71\x52\xa3\x22\x95\xdd\xea\x9c\xf8\
+\x98\x64\x8b\xfb\xdd\xcd\xa7\x96\xb1\x81\x06\xb8\xfc\x95\x62\xdf\
+\x50\x36\x70\x1f\x78\xa1\xe7\x60\x63\xe9\xc3\x95\x60\x45\x89\x6d\
+\x43\x76\x91\x80\xc2\xbf\x4c\x14\xf8\x62\x75\x26\x68\x1d\x00\x75\
+\x02\xa3\x68\x7a\x1c\x1e\x17\x93\xac\xe4\x45\x3c\x04\x19\xe4\x14\
+\x70\x02\x3e\x8d\xe1\xab\xdc\x14\x1e\xf1\x3b\x67\xf3\xe0\x69\x54\
+\x67\xb4\xdf\x53\xbb\xc3\xa7\xf2\xfa\x71\x42\x3a\x64\x5f\xaf\x91\
+\x08\x08\xb5\x6b\x24\xf0\xad\xad\x49\x9c\x9b\x92\xee\x19\xb5\x4f\
+\x4b\xa7\x1c\xcc\x13\x77\xca\x10\xdf\x56\x23\x61\x11\xea\x6e\x39\
+\x98\xed\xca\xc3\x3c\x7d\xb3\x1c\x86\xe3\x7c\x26\xed\x32\x62\xb6\
+\xa1\xd0\xe6\xc8\xab\x3a\xba\xc6\x99\x57\x19\xe2\xd1\x6a\x12\xf7\
+\x81\x38\xee\x74\xe0\x5a\x20\xaf\x1f\xa8\xf2\xd0\x0f\x2d\x75\x99\
+\x5e\x14\xda\x17\xd1\xb5\xd0\x0a\xbf\xf5\x25\xb4\xc6\xde\x39\x97\
+\xbd\x17\xfa\x47\xd8\xdb\xc4\x32\x89\xe5\x3e\x2a\xc0\xd9\x0a\xa8\
+\x5c\xfc\x16\x1a\x9c\x6e\x34\xd0\x23\x1a\x28\xb1\x28\x09\x1a\x25\
+\x38\xbb\x12\x94\xc7\xde\x71\x50\xb0\x3c\x12\x51\xc9\x85\x86\xae\
+\x11\x9f\x24\x29\x83\x8d\x3c\x0c\x09\x5c\x24\x57\xd1\xac\x41\x9f\
+\x5c\x56\xd2\x5e\x5e\x5d\x4b\x51\x4e\x68\x87\x56\x45\x76\xbb\x69\
+\x8f\xe4\x08\xbf\x11\x06\x8f\xa6\xc8\x82\x8a\x96\x11\xbc\xf3\xd7\
+\x52\x3d\xe5\x1d\x10\x57\x27\x5b\x47\x54\xc5\x3c\x63\x8d\xba\xa4\
+\xc1\x46\x59\x35\xfc\xad\x04\xf2\x19\x94\x7c\x31\x8d\x1b\x45\xf2\
+\xd9\x6f\x28\x11\xfd\xce\xcb\xa1\x1d\x52\x3d\x81\x16\x76\xdb\x47\
+\xb7\xe0\x5a\x9c\xff\x0a\x3f\x89\xd7\x9b\x51\x7a\x7a\x67\x48\x3b\
+\x3d\x7b\xbf\x5a\x5c\x9b\x26\x77\x17\x46\xa1\x08\x93\x90\x87\x8b\
+\xb0\xd0\xe8\x75\x6f\x39\xbf\x4d\xd9\x84\x97\x80\x4d\x56\xef\x43\
+\x73\xe3\x82\x9d\x19\x8f\xd6\x3f\xe3\xb2\xcc\x9f\x1a\xc6\x72\xb9\
+\x24\xb7\x6a\x89\xa0\xb5\x81\xeb\x24\x2e\xe7\xa9\xd6\x57\xd1\xa8\
+\xc8\x24\x05\xba\x47\x61\xae\xa6\x0d\x75\xad\x5b\xc3\x14\x2c\x12\
+\xd3\x98\xe0\x92\x82\xa9\x4c\x24\x12\xe6\x31\xca\xf3\x29\x9f\xb1\
+\x2c\x9a\x63\x24\xd4\xb0\xf6\x78\x57\x85\x5c\x8e\xf2\x34\x2a\x6f\
+\xb8\x98\xcb\xe7\x3b\x86\x77\x0f\xb1\x7d\x2a\x16\x13\x1c\x68\x70\
+\xfe\x16\xc5\x9c\xc3\x38\x5d\x88\x5c\x2f\x6e\xca\xe1\x8f\xca\x63\
+\x08\x2b\x39\x31\x4b\x73\xf2\x43\xae\x28\x39\x72\x88\xd9\x36\x7e\
+\x54\x32\x8d\x42\x1a\xff\x0c\x65\x87\x35\x55\x9b\xd9\xfe\x98\xfb\
+\x3f\x25\x8f\xae\x3e\
+"
+
+qt_resource_name = b"\
+\x00\x15\
+\x03\x80\x5a\x3c\
+\x00\x55\
+\x00\x73\x00\x65\x00\x72\x00\x41\x00\x67\x00\x65\x00\x6e\x00\x74\x00\x44\x00\x65\x00\x66\x00\x61\x00\x75\x00\x6c\x00\x74\x00\x73\
+\x00\x2e\x00\x78\x00\x6d\x00\x6c\
+"
+
+qt_resource_struct = b"\
+\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
+\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\
+"
+
+def qInitResources():
+    QtCore.qRegisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+def qCleanupResources():
+    QtCore.qUnregisterResourceData(0x01, qt_resource_struct, qt_resource_name, qt_resource_data)
+
+qInitResources()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/UserAgent/UserAgentManager.py	Tue Mar 29 10:32:22 2016 +0200
@@ -0,0 +1,195 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a user agent manager.
+"""
+
+from __future__ import unicode_literals
+
+import os
+
+from PyQt5.QtCore import pyqtSignal, QObject, QXmlStreamReader
+
+from E5Gui import E5MessageBox
+
+from Utilities.AutoSaver import AutoSaver
+import Utilities
+
+
+class UserAgentManager(QObject):
+    """
+    Class implementing a user agent manager.
+    
+    @signal changed() emitted to indicate a change
+    @signal userAgentSettingsSaved() emitted after the user agent settings
+        were saved
+    """
+    changed = pyqtSignal()
+    userAgentSettingsSaved = pyqtSignal()
+    
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent object (QObject)
+        """
+        super(UserAgentManager, self).__init__(parent)
+        
+        self.__agents = {}
+        # dictionary with agent strings indexed by host name
+        self.__loaded = False
+        self.__saveTimer = AutoSaver(self, self.save)
+        
+        self.changed.connect(self.__saveTimer.changeOccurred)
+    
+    def getFileName(self):
+        """
+        Public method to get the file name of the user agents file.
+        
+        @return name of the user agents file (string)
+        """
+        return os.path.join(
+            Utilities.getConfigDir(), "web_browser", "userAgentSettings.xml")
+    
+    def save(self):
+        """
+        Public slot to save the user agent entries to disk.
+        """
+        if not self.__loaded:
+            return
+        
+        from .UserAgentWriter import UserAgentWriter
+        agentFile = self.getFileName()
+        writer = UserAgentWriter()
+        if not writer.write(agentFile, self.__agents):
+            E5MessageBox.critical(
+                None,
+                self.tr("Saving user agent data"),
+                self.tr(
+                    """<p>User agent data could not be saved to"""
+                    """ <b>{0}</b></p>""").format(agentFile))
+        else:
+            self.userAgentSettingsSaved.emit()
+    
+    def __load(self):
+        """
+        Private method to load the saved user agent settings.
+        """
+        agentFile = self.getFileName()
+        from .UserAgentReader import UserAgentReader
+        reader = UserAgentReader()
+        self.__agents = reader.read(agentFile)
+        if reader.error() != QXmlStreamReader.NoError:
+            E5MessageBox.warning(
+                None,
+                self.tr("Loading user agent data"),
+                self.tr("""Error when loading user agent data on"""
+                        """ line {0}, column {1}:\n{2}""")
+                .format(reader.lineNumber(),
+                        reader.columnNumber(),
+                        reader.errorString()))
+        
+        self.__loaded = True
+    
+    def reload(self):
+        """
+        Public method to reload the user agent settings.
+        """
+        if not self.__loaded:
+            return
+        
+        self.__agents = {}
+        self.__load()
+    
+    def close(self):
+        """
+        Public method to close the user agents manager.
+        """
+        self.__saveTimer.saveIfNeccessary()
+    
+    def removeUserAgent(self, host):
+        """
+        Public method to remove a user agent entry.
+        
+        @param host host name (string)
+        """
+        if host in self.__agents:
+            del self.__agents[host]
+            self.changed.emit()
+    
+    def allHostNames(self):
+        """
+        Public method to get a list of all host names we a user agent setting
+        for.
+        
+        @return sorted list of all host names (list of strings)
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        return sorted(self.__agents.keys())
+    
+    def hostsCount(self):
+        """
+        Public method to get the number of available user agent settings.
+        
+        @return number of user agent settings (integer)
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        return len(self.__agents)
+    
+    def userAgent(self, host):
+        """
+        Public method to get the user agent setting for a host.
+        
+        @param host host name (string)
+        @return user agent string (string)
+        """
+        if not self.__loaded:
+            self.__load()
+        
+        for agentHost in self.__agents:
+            if host.endswith(agentHost):
+                return self.__agents[agentHost]
+        
+        return ""
+    
+    def setUserAgent(self, host, agent):
+        """
+        Public method to set the user agent string for a host.
+        
+        @param host host name (string)
+        @param agent user agent string (string)
+        """
+        if host != "" and agent != "":
+            self.__agents[host] = agent
+            self.changed.emit()
+    
+    def userAgentForUrl(self, url):
+        """
+        Public method to determine the user agent for the given URL.
+        
+        @param url URL to determine user agent for (QUrl)
+        @return user agent string (string)
+        """
+        if url.isValid():
+            host = url.host()
+            return self.userAgent(host)
+        
+        return ""
+    
+    def setUserAgentForUrl(self, url, agent):
+        """
+        Public method to set the user agent string for an URL.
+        
+        @param url URL to register user agent setting for (QUrl)
+        @param agent new current user agent string (string)
+        """
+        if url.isValid():
+            host = url.host()
+            self.setUserAgent(host, agent)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/UserAgent/UserAgentMenu.py	Tue Mar 29 10:32:22 2016 +0200
@@ -0,0 +1,190 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2010 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a menu to select the user agent string.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import QXmlStreamReader, QFile, QIODevice
+from PyQt5.QtWidgets import QMenu, QAction, QActionGroup, QInputDialog, \
+    QLineEdit
+
+from E5Gui import E5MessageBox
+
+
+class UserAgentMenu(QMenu):
+    """
+    Class implementing a menu to select the user agent string.
+    """
+    def __init__(self, title, url=None, parent=None):
+        """
+        Constructor
+        
+        @param title title of the menu (string)
+        @param url URL to set user agent for (QUrl)
+        @param parent reference to the parent widget (QWidget)
+        """
+        super(UserAgentMenu, self).__init__(title, parent)
+        
+        self.__manager = None
+        self.__url = url
+        if self.__url:
+            if self.__url.isValid():
+                from WebBrowser.WebBrowserWindow import WebBrowserWindow
+                self.__manager = WebBrowserWindow.userAgentsManager()
+            else:
+                self.__url = None
+        
+        self.aboutToShow.connect(self.__populateMenu)
+    
+    def __populateMenu(self):
+        """
+        Private slot to populate the menu.
+        """
+        self.aboutToShow.disconnect(self.__populateMenu)
+        
+        self.__actionGroup = QActionGroup(self)
+        
+        # add default action
+        self.__defaultUserAgent = QAction(self)
+        self.__defaultUserAgent.setText(self.tr("Default"))
+        self.__defaultUserAgent.setCheckable(True)
+        self.__defaultUserAgent.triggered.connect(
+            self.__switchToDefaultUserAgent)
+        if self.__url:
+            self.__defaultUserAgent.setChecked(
+                self.__manager.userAgentForUrl(self.__url) == "")
+        else:
+            from WebBrowser.WebBrowserPage import WebBrowserPage
+            self.__defaultUserAgent.setChecked(
+                WebBrowserPage.userAgent() == "")
+        self.addAction(self.__defaultUserAgent)
+        self.__actionGroup.addAction(self.__defaultUserAgent)
+        isChecked = self.__defaultUserAgent.isChecked()
+        
+        # add default extra user agents
+        isChecked = self.__addDefaultActions() or isChecked
+        
+        # add other action
+        self.addSeparator()
+        self.__otherUserAgent = QAction(self)
+        self.__otherUserAgent.setText(self.tr("Other..."))
+        self.__otherUserAgent.setCheckable(True)
+        self.__otherUserAgent.triggered.connect(
+            self.__switchToOtherUserAgent)
+        self.addAction(self.__otherUserAgent)
+        self.__actionGroup.addAction(self.__otherUserAgent)
+        self.__otherUserAgent.setChecked(not isChecked)
+    
+    def __switchToDefaultUserAgent(self):
+        """
+        Private slot to set the default user agent.
+        """
+        if self.__url:
+            self.__manager.removeUserAgent(self.__url.host())
+        else:
+            from WebBrowser.WebBrowserPage import WebBrowserPage
+            WebBrowserPage.setUserAgent("")
+    
+    def __switchToOtherUserAgent(self):
+        """
+        Private slot to set a custom user agent string.
+        """
+        from WebBrowser.WebBrowserPage import WebBrowserPage
+        userAgent, ok = QInputDialog.getText(
+            self,
+            self.tr("Custom user agent"),
+            self.tr("User agent:"),
+            QLineEdit.Normal,
+            WebBrowserPage.userAgent(resolveEmpty=True))
+        if ok:
+            if self.__url:
+                self.__manager.setUserAgentForUrl(self.__url, userAgent)
+            else:
+                WebBrowserPage.setUserAgent(userAgent)
+    
+    def __changeUserAgent(self):
+        """
+        Private slot to change the user agent.
+        """
+        act = self.sender()
+        if self.__url:
+            self.__manager.setUserAgentForUrl(self.__url, act.data())
+        else:
+            from WebBrowser.WebBrowserPage import WebBrowserPage
+            WebBrowserPage.setUserAgent(act.data())
+    
+    def __addDefaultActions(self):
+        """
+        Private slot to add the default user agent entries.
+        
+        @return flag indicating that a user agent entry is checked (boolean)
+        """
+        from . import UserAgentDefaults_rc              # __IGNORE_WARNING__
+        defaultUserAgents = QFile(":/UserAgentDefaults.xml")
+        defaultUserAgents.open(QIODevice.ReadOnly)
+        
+        menuStack = []
+        isChecked = False
+        
+        if self.__url:
+            currentUserAgentString = self.__manager.userAgentForUrl(self.__url)
+        else:
+            from WebBrowser.WebBrowserPage import WebBrowserPage
+            currentUserAgentString = WebBrowserPage.userAgent()
+        xml = QXmlStreamReader(defaultUserAgents)
+        while not xml.atEnd():
+            xml.readNext()
+            if xml.isStartElement() and xml.name() == "separator":
+                if menuStack:
+                    menuStack[-1].addSeparator()
+                else:
+                    self.addSeparator()
+                continue
+            
+            if xml.isStartElement() and xml.name() == "useragent":
+                attributes = xml.attributes()
+                title = attributes.value("description")
+                userAgent = attributes.value("useragent")
+                
+                act = QAction(self)
+                act.setText(title)
+                act.setData(userAgent)
+                act.setToolTip(userAgent)
+                act.setCheckable(True)
+                act.setChecked(userAgent == currentUserAgentString)
+                act.triggered.connect(self.__changeUserAgent)
+                if menuStack:
+                    menuStack[-1].addAction(act)
+                else:
+                    self.addAction(act)
+                self.__actionGroup.addAction(act)
+                isChecked = isChecked or act.isChecked()
+            
+            if xml.isStartElement() and xml.name() == "useragentmenu":
+                attributes = xml.attributes()
+                title = attributes.value("title")
+                if title == "v_a_r_i_o_u_s":
+                    title = self.tr("Various")
+                
+                menu = QMenu(self)
+                menu.setTitle(title)
+                self.addMenu(menu)
+                menuStack.append(menu)
+            
+            if xml.isEndElement() and xml.name() == "useragentmenu":
+                menuStack.pop()
+        
+        if xml.hasError():
+            E5MessageBox.critical(
+                self,
+                self.tr("Parsing default user agents"),
+                self.tr(
+                    """<p>Error parsing default user agents.</p><p>{0}</p>""")
+                .format(xml.errorString()))
+        
+        return isChecked
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/UserAgent/UserAgentModel.py	Tue Mar 29 10:32:22 2016 +0200
@@ -0,0 +1,129 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a model for user agent management.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import Qt, QModelIndex, QAbstractTableModel
+
+
+class UserAgentModel(QAbstractTableModel):
+    """
+    Class implementing a model for user agent management.
+    """
+    def __init__(self, manager, parent=None):
+        """
+        Constructor
+        
+        @param manager reference to the user agent manager (UserAgentManager)
+        @param parent reference to the parent object (QObject)
+        """
+        super(UserAgentModel, self).__init__(parent)
+        
+        self.__manager = manager
+        self.__manager.changed.connect(self.__userAgentsChanged)
+        
+        self.__headers = [
+            self.tr("Host"),
+            self.tr("User Agent String"),
+        ]
+    
+    def __userAgentsChanged(self):
+        """
+        Private slot handling a change of the registered user agent strings.
+        """
+        self.beginResetModel()
+        self.endResetModel()
+    
+    def removeRows(self, row, count, parent=QModelIndex()):
+        """
+        Public method to remove entries from the model.
+        
+        @param row start row (integer)
+        @param count number of rows to remove (integer)
+        @param parent parent index (QModelIndex)
+        @return flag indicating success (boolean)
+        """
+        if parent.isValid():
+            return False
+        
+        if count <= 0:
+            return False
+        
+        lastRow = row + count - 1
+        
+        self.beginRemoveRows(parent, row, lastRow)
+        
+        hostsList = self.__manager.allHostNames()
+        for index in range(row, lastRow + 1):
+            self.__manager.removeUserAgent(hostsList[index])
+        
+        return True
+    
+    def rowCount(self, parent=QModelIndex()):
+        """
+        Public method to get the number of rows of the model.
+        
+        @param parent parent index (QModelIndex)
+        @return number of rows (integer)
+        """
+        if parent.isValid():
+            return 0
+        else:
+            return self.__manager.hostsCount()
+    
+    def columnCount(self, parent=QModelIndex()):
+        """
+        Public method to get the number of columns of the model.
+        
+        @param parent parent index (QModelIndex)
+        @return number of columns (integer)
+        """
+        return len(self.__headers)
+    
+    def data(self, index, role):
+        """
+        Public method to get data from the model.
+        
+        @param index index to get data for (QModelIndex)
+        @param role role of the data to retrieve (integer)
+        @return requested data
+        """
+        if index.row() >= self.__manager.hostsCount() or index.row() < 0:
+            return None
+        
+        host = self.__manager.allHostNames()[index.row()]
+        userAgent = self.__manager.userAgent(host)
+        
+        if userAgent is None:
+            return None
+        
+        if role == Qt.DisplayRole:
+            if index.column() == 0:
+                return host
+            elif index.column() == 1:
+                return userAgent
+        
+        return None
+    
+    def headerData(self, section, orientation, role=Qt.DisplayRole):
+        """
+        Public method to get the header data.
+        
+        @param section section number (integer)
+        @param orientation header orientation (Qt.Orientation)
+        @param role data role (integer)
+        @return header data
+        """
+        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
+            try:
+                return self.__headers[section]
+            except IndexError:
+                pass
+        
+        return None
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/UserAgent/UserAgentReader.py	Tue Mar 29 10:32:22 2016 +0200
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+
+"""
+Module implementing a class to read user agent data files.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import QXmlStreamReader, QIODevice, QFile, QCoreApplication
+
+
+class UserAgentReader(QXmlStreamReader):
+    """
+    Class implementing a reader object for user agent data files.
+    """
+    def __init__(self):
+        """
+        Constructor
+        """
+        super(UserAgentReader, self).__init__()
+    
+    def read(self, fileNameOrDevice):
+        """
+        Public method to read a user agent file.
+        
+        @param fileNameOrDevice name of the file to read (string)
+            or reference to the device to read (QIODevice)
+        @return dictionary with user agent data (host as key, agent string as
+            value)
+        """
+        self.__agents = {}
+        
+        if isinstance(fileNameOrDevice, QIODevice):
+            self.setDevice(fileNameOrDevice)
+        else:
+            f = QFile(fileNameOrDevice)
+            if not f.exists():
+                return self.__agents
+            f.open(QFile.ReadOnly)
+            self.setDevice(f)
+        
+        while not self.atEnd():
+            self.readNext()
+            if self.isStartElement():
+                version = self.attributes().value("version")
+                if self.name() == "UserAgents" and \
+                   (not version or version == "1.0"):
+                    self.__readUserAgents()
+                else:
+                    self.raiseError(QCoreApplication.translate(
+                        "UserAgentReader",
+                        "The file is not a UserAgents version 1.0 file."))
+        
+        return self.__agents
+    
+    def __readUserAgents(self):
+        """
+        Private method to read the user agents data.
+        """
+        if not self.isStartElement() and self.name() != "UserAgents":
+            return
+        
+        while not self.atEnd():
+            self.readNext()
+            if self.isEndElement():
+                if self.name() == "UserAgent":
+                    continue
+                else:
+                    break
+            
+            if self.isStartElement():
+                if self.name() == "UserAgent":
+                    attributes = self.attributes()
+                    host = attributes.value("host")
+                    agent = attributes.value("agent")
+                    self.__agents[host] = agent
+                else:
+                    self.__skipUnknownElement()
+    
+    def __skipUnknownElement(self):
+        """
+        Private method to skip over all unknown elements.
+        """
+        if not self.isStartElement():
+            return
+        
+        while not self.atEnd():
+            self.readNext()
+            if self.isEndElement():
+                break
+            
+            if self.isStartElement():
+                self.__skipUnknownElement()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/UserAgent/UserAgentWriter.py	Tue Mar 29 10:32:22 2016 +0200
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a class to write user agent data files.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import QXmlStreamWriter, QIODevice, QFile
+
+
+class UserAgentWriter(QXmlStreamWriter):
+    """
+    Class implementing a writer object to generate user agent data files.
+    """
+    def __init__(self):
+        """
+        Constructor
+        """
+        super(UserAgentWriter, self).__init__()
+        
+        self.setAutoFormatting(True)
+    
+    def write(self, fileNameOrDevice, agents):
+        """
+        Public method to write a user agent data file.
+        
+        @param fileNameOrDevice name of the file to write (string)
+            or device to write to (QIODevice)
+        @param agents dictionary with user agent data (host as key, agent
+            string as value)
+        @return flag indicating success (boolean)
+        """
+        if isinstance(fileNameOrDevice, QIODevice):
+            f = fileNameOrDevice
+        else:
+            f = QFile(fileNameOrDevice)
+            if not f.open(QFile.WriteOnly):
+                return False
+        
+        self.setDevice(f)
+        return self.__write(agents)
+    
+    def __write(self, agents):
+        """
+        Private method to write a user agent file.
+        
+        @param agents dictionary with user agent data (host as key, agent
+            string as value)
+        @return flag indicating success (boolean)
+        """
+        self.writeStartDocument()
+        self.writeDTD("<!DOCTYPE useragents>")
+        self.writeStartElement("UserAgents")
+        self.writeAttribute("version", "1.0")
+        
+        for host, agent in agents.items():
+            self.writeEmptyElement("UserAgent")
+            self.writeAttribute("host", host)
+            self.writeAttribute("agent", agent)
+        
+        self.writeEndDocument()
+        return True
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/UserAgent/UserAgentsDialog.py	Tue Mar 29 10:32:22 2016 +0200
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to show all saved user agent settings.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import QSortFilterProxyModel
+from PyQt5.QtGui import QFont, QFontMetrics
+from PyQt5.QtWidgets import QDialog
+
+from WebBrowser.WebBrowserWindow import WebBrowserWindow
+
+from .UserAgentModel import UserAgentModel
+
+from .Ui_UserAgentsDialog import Ui_UserAgentsDialog
+
+
+class UserAgentsDialog(QDialog, Ui_UserAgentsDialog):
+    """
+    Class implementing a dialog to show all saved user agent settings.
+    """
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent widget (QWidget)
+        """
+        super(UserAgentsDialog, self).__init__(parent)
+        self.setupUi(self)
+        
+        self.removeButton.clicked.connect(
+            self.userAgentsTable.removeSelected)
+        self.removeAllButton.clicked.connect(
+            self.userAgentsTable.removeAll)
+        
+        self.userAgentsTable.verticalHeader().hide()
+        self.__userAgentModel = UserAgentModel(
+            WebBrowserWindow.userAgentsManager(), self)
+        self.__proxyModel = QSortFilterProxyModel(self)
+        self.__proxyModel.setSourceModel(self.__userAgentModel)
+        self.searchEdit.textChanged.connect(
+            self.__proxyModel.setFilterFixedString)
+        self.userAgentsTable.setModel(self.__proxyModel)
+        
+        fm = QFontMetrics(QFont())
+        height = fm.height() + fm.height() // 3
+        self.userAgentsTable.verticalHeader().setDefaultSectionSize(height)
+        self.userAgentsTable.verticalHeader().setMinimumSectionSize(-1)
+        
+        self.userAgentsTable.resizeColumnsToContents()
+        self.userAgentsTable.horizontalHeader().setStretchLastSection(True)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/UserAgent/UserAgentsDialog.ui	Tue Mar 29 10:32:22 2016 +0200
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UserAgentsDialog</class>
+ <widget class="QDialog" name="UserAgentsDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>700</width>
+    <height>400</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>User Agent Settings</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <layout class="QHBoxLayout" name="horizontalLayout">
+       <property name="spacing">
+        <number>0</number>
+       </property>
+       <item>
+        <widget class="E5ClearableLineEdit" name="searchEdit">
+         <property name="toolTip">
+          <string>Enter search term</string>
+         </property>
+        </widget>
+       </item>
+      </layout>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="E5TableView" name="userAgentsTable">
+     <property name="alternatingRowColors">
+      <bool>true</bool>
+     </property>
+     <property name="selectionBehavior">
+      <enum>QAbstractItemView::SelectRows</enum>
+     </property>
+     <property name="textElideMode">
+      <enum>Qt::ElideMiddle</enum>
+     </property>
+     <property name="showGrid">
+      <bool>false</bool>
+     </property>
+     <property name="sortingEnabled">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_3">
+     <item>
+      <widget class="QPushButton" name="removeButton">
+       <property name="toolTip">
+        <string>Press to remove the selected entries</string>
+       </property>
+       <property name="text">
+        <string>&amp;Remove</string>
+       </property>
+       <property name="autoDefault">
+        <bool>false</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="removeAllButton">
+       <property name="toolTip">
+        <string>Press to remove all entries</string>
+       </property>
+       <property name="text">
+        <string>Remove &amp;All</string>
+       </property>
+       <property name="autoDefault">
+        <bool>false</bool>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer_2">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>208</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>E5ClearableLineEdit</class>
+   <extends>QLineEdit</extends>
+   <header>E5Gui/E5LineEdit.h</header>
+  </customwidget>
+  <customwidget>
+   <class>E5TableView</class>
+   <extends>QTableView</extends>
+   <header>E5Gui/E5TableView.h</header>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>searchEdit</tabstop>
+  <tabstop>userAgentsTable</tabstop>
+  <tabstop>removeButton</tabstop>
+  <tabstop>removeAllButton</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>UserAgentsDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>237</x>
+     <y>390</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>UserAgentsDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>325</x>
+     <y>390</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/UserAgent/__init__.py	Tue Mar 29 10:32:22 2016 +0200
@@ -0,0 +1,8 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2010 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Package implementing the user agents manager.
+"""
--- a/WebBrowser/WebBrowserPage.py	Mon Mar 28 17:04:18 2016 +0200
+++ b/WebBrowser/WebBrowserPage.py	Tue Mar 29 10:32:22 2016 +0200
@@ -351,70 +351,45 @@
 ##        """
 ##        return self.__adBlockedEntries
     
-    # TODO: User Agent Manager
-##    def userAgent(self, resolveEmpty=False):
-##        """
-##        Public method to get the global user agent setting.
-##        
-##        @param resolveEmpty flag indicating to resolve an empty
-##            user agent (boolean)
-##        @return user agent string (string)
-##        """
-##        agent = Preferences.getWebBrowser("UserAgent")
-##        if agent == "" and resolveEmpty:
-##            agent = self.userAgentForUrl(QUrl())
-##        return agent
-##    
-##    def setUserAgent(self, agent):
-##        """
-##        Public method to set the global user agent string.
-##        
-##        @param agent new current user agent string (string)
-##        """
-##        Preferences.setWebBrowser("UserAgent", agent)
-##    
-##    def userAgentForUrl(self, url):
-##        """
-##        Public method to determine the user agent for the given URL.
-##        
-##        @param url URL to determine user agent for (QUrl)
-##        @return user agent string (string)
-##        """
-##        agent = WebBrowserWindow.userAgentsManager().userAgentForUrl(url)
-##        if agent == "":
-##            # no agent string specified for the given host -> use global one
-##            agent = Preferences.getWebBrowser("UserAgent")
-##            if agent == "":
-##                # no global agent string specified -> use default one
-##                agent = QWebPage.userAgentForUrl(self, url)
-##        return agent
-##    
-##    def hasValidSslInfo(self):
-##        """
-##        Public method to check, if the page has a valid SSL certificate.
-##        
-##        @return flag indicating a valid SSL certificate (boolean)
-##        """
-##        if self.__sslConfiguration is None:
-##            return False
-##        
-##        certList = self.__sslConfiguration.peerCertificateChain()
-##        if not certList:
-##            return False
-##        
-##        certificateDict = Globals.toDict(
-##            Preferences.Prefs.settings.value("Ssl/CaCertificatesDict"))
-##        for server in certificateDict:
-##            localCAList = QSslCertificate.fromData(certificateDict[server])
-##            for cert in certList:
-##                if cert in localCAList:
-##                    return True
-##        
-##        for cert in certList:
-##            if cert.isBlacklisted():
-##                return False
-##        
-##        return True
+    @classmethod
+    def userAgent(cls, resolveEmpty=False):
+        """
+        Class method to get the global user agent setting.
+        
+        @param resolveEmpty flag indicating to resolve an empty
+            user agent (boolean)
+        @return user agent string (string)
+        """
+        agent = Preferences.getWebBrowser("UserAgent")
+        if agent == "" and resolveEmpty:
+            agent = cls.userAgentForUrl(QUrl())
+        return agent
+    
+    @classmethod
+    def setUserAgent(cls, agent):
+        """
+        Class method to set the global user agent string.
+        
+        @param agent new current user agent string (string)
+        """
+        Preferences.setWebBrowser("UserAgent", agent)
+    
+    @classmethod
+    def userAgentForUrl(cls, url):
+        """
+        Class method to determine the user agent for the given URL.
+        
+        @param url URL to determine user agent for (QUrl)
+        @return user agent string (string)
+        """
+        agent = WebBrowserWindow.userAgentsManager().userAgentForUrl(url)
+        if agent == "":
+            # no agent string specified for the given host -> use global one
+            agent = Preferences.getWebBrowser("UserAgent")
+            if agent == "":
+                # no global agent string specified -> use default one
+                agent = WebBrowserWindow.webProfile().httpUserAgent()
+        return agent
     
 ##    @classmethod
 ##    def webPluginFactory(cls):
--- a/WebBrowser/WebBrowserView.py	Mon Mar 28 17:04:18 2016 +0200
+++ b/WebBrowser/WebBrowserView.py	Tue Mar 29 10:32:22 2016 +0200
@@ -827,12 +827,11 @@
             self.tr("Send Page Link"), self.__sendLink).setData(self.url())
         menu.addSeparator()
         
-        # TODO: User Agent
-##        from .UserAgent.UserAgentMenu import UserAgentMenu
-##        self.__userAgentMenu = UserAgentMenu(self.tr("User Agent"),
-##                                             url=self.url())
-##        menu.addMenu(self.__userAgentMenu)
-##        menu.addSeparator()
+        from .UserAgent.UserAgentMenu import UserAgentMenu
+        self.__userAgentMenu = UserAgentMenu(self.tr("User Agent"),
+                                             url=self.url())
+        menu.addMenu(self.__userAgentMenu)
+        menu.addSeparator()
         menu.addAction(self.__mw.backAct)
         menu.addAction(self.__mw.forwardAct)
         menu.addAction(self.__mw.homeAct)
--- a/WebBrowser/WebBrowserWindow.py	Mon Mar 28 17:04:18 2016 +0200
+++ b/WebBrowser/WebBrowserWindow.py	Tue Mar 29 10:32:22 2016 +0200
@@ -93,7 +93,7 @@
     _adblockManager = None
     _downloadManager = None
     _feedsManager = None
-##    _userAgentsManager = None
+    _userAgentsManager = None
     _syncManager = None
     _speedDial = None
     _personalInformationManager = None
@@ -1592,21 +1592,20 @@
             self.siteInfoAct.triggered.connect(self.__showSiteinfoDialog)
         self.__actions.append(self.siteInfoAct)
         
-        # TODO: User Agents
-##        self.userAgentManagerAct = E5Action(
-##            self.tr('Manage User Agent Settings'),
-##            self.tr('Manage &User Agent Settings'),
-##            0, 0, self, 'webbrowser_user_agent_settings')
-##        self.userAgentManagerAct.setStatusTip(self.tr(
-##            'Shows a dialog to manage the User Agent settings'))
-##        self.userAgentManagerAct.setWhatsThis(self.tr(
-##            """<b>Manage User Agent Settings</b>"""
-##            """<p>Shows a dialog to manage the User Agent settings.</p>"""
-##        ))
-##        if not self.__initShortcutsOnly:
-##            self.userAgentManagerAct.triggered.connect(
-##                self.__showUserAgentsDialog)
-##        self.__actions.append(self.userAgentManagerAct)
+        self.userAgentManagerAct = E5Action(
+            self.tr('Manage User Agent Settings'),
+            self.tr('Manage &User Agent Settings'),
+            0, 0, self, 'webbrowser_user_agent_settings')
+        self.userAgentManagerAct.setStatusTip(self.tr(
+            'Shows a dialog to manage the User Agent settings'))
+        self.userAgentManagerAct.setWhatsThis(self.tr(
+            """<b>Manage User Agent Settings</b>"""
+            """<p>Shows a dialog to manage the User Agent settings.</p>"""
+        ))
+        if not self.__initShortcutsOnly:
+            self.userAgentManagerAct.triggered.connect(
+                self.__showUserAgentsDialog)
+        self.__actions.append(self.userAgentManagerAct)
         
         self.synchronizationAct = E5Action(
             self.tr('Synchronize data'),
@@ -1792,12 +1791,11 @@
         self.__settingsMenu.aboutToShow.connect(
             self.__aboutToShowSettingsMenu)
         
-        # TODO: UserAgents
-##        from .UserAgent.UserAgentMenu import UserAgentMenu
-##        self.__userAgentMenu = UserAgentMenu(self.tr("Global User Agent"))
-##        menu.addMenu(self.__userAgentMenu)
-##        menu.addAction(self.userAgentManagerAct)
-##        menu.addSeparator()
+        from .UserAgent.UserAgentMenu import UserAgentMenu
+        self.__userAgentMenu = UserAgentMenu(self.tr("Global User Agent"))
+        menu.addMenu(self.__userAgentMenu)
+        menu.addAction(self.userAgentManagerAct)
+        menu.addSeparator()
         
         if WebBrowserWindow.useQtHelp:
             menu.addAction(self.manageQtHelpDocsAct)
@@ -2414,9 +2412,8 @@
         
         self.adBlockManager().close()
         
-        # TODO: UserAgents
-##        self.userAgentsManager().close()
-##        
+        self.userAgentsManager().close()
+        
         self.speedDial().close()
         
         self.syncManager().close()
@@ -3682,29 +3679,28 @@
         self.__siteinfoDialog = SiteInfoDialog(self.currentBrowser(), self)
         self.__siteinfoDialog.show()
 
-    # TODO: User Agents
-##    @classmethod
-##    def userAgentsManager(cls):
-##        """
-##        Class method to get a reference to the user agents manager.
-##        
-##        @return reference to the user agents manager (UserAgentManager)
-##        """
-##        if cls._userAgentsManager is None:
-##            from .UserAgent.UserAgentManager import UserAgentManager
-##            cls._userAgentsManager = UserAgentManager()
-##        
-##        return cls._userAgentsManager
-##    
-##    def __showUserAgentsDialog(self):
-##        """
-##        Private slot to show the user agents management dialog.
-##        """
-##        from .UserAgent.UserAgentsDialog import UserAgentsDialog
-##        
-##        dlg = UserAgentsDialog(self)
-##        dlg.exec_()
-##    
+    @classmethod
+    def userAgentsManager(cls):
+        """
+        Class method to get a reference to the user agents manager.
+        
+        @return reference to the user agents manager (UserAgentManager)
+        """
+        if cls._userAgentsManager is None:
+            from .UserAgent.UserAgentManager import UserAgentManager
+            cls._userAgentsManager = UserAgentManager()
+        
+        return cls._userAgentsManager
+    
+    def __showUserAgentsDialog(self):
+        """
+        Private slot to show the user agents management dialog.
+        """
+        from .UserAgent.UserAgentsDialog import UserAgentsDialog
+        
+        dlg = UserAgentsDialog(self)
+        dlg.exec_()
+    
     @classmethod
     def syncManager(cls):
         """
--- a/eric6.e4p	Mon Mar 28 17:04:18 2016 +0200
+++ b/eric6.e4p	Tue Mar 29 10:32:22 2016 +0200
@@ -1429,6 +1429,14 @@
     <Source>WebBrowser/UrlBar/StackedUrlBar.py</Source>
     <Source>WebBrowser/UrlBar/UrlBar.py</Source>
     <Source>WebBrowser/UrlBar/__init__.py</Source>
+    <Source>WebBrowser/UserAgent/UserAgentDefaults_rc.py</Source>
+    <Source>WebBrowser/UserAgent/UserAgentManager.py</Source>
+    <Source>WebBrowser/UserAgent/UserAgentMenu.py</Source>
+    <Source>WebBrowser/UserAgent/UserAgentModel.py</Source>
+    <Source>WebBrowser/UserAgent/UserAgentReader.py</Source>
+    <Source>WebBrowser/UserAgent/UserAgentWriter.py</Source>
+    <Source>WebBrowser/UserAgent/UserAgentsDialog.py</Source>
+    <Source>WebBrowser/UserAgent/__init__.py</Source>
     <Source>WebBrowser/VirusTotal/VirusTotalApi.py</Source>
     <Source>WebBrowser/VirusTotal/VirusTotalDomainReportDialog.py</Source>
     <Source>WebBrowser/VirusTotal/VirusTotalIpReportDialog.py</Source>
@@ -1896,6 +1904,7 @@
     <Form>WebBrowser/Tools/WebIconDialog.ui</Form>
     <Form>WebBrowser/UrlBar/BookmarkActionSelectionDialog.ui</Form>
     <Form>WebBrowser/UrlBar/BookmarkInfoDialog.ui</Form>
+    <Form>WebBrowser/UserAgent/UserAgentsDialog.ui</Form>
     <Form>WebBrowser/VirusTotal/VirusTotalDomainReportDialog.ui</Form>
     <Form>WebBrowser/VirusTotal/VirusTotalIpReportDialog.ui</Form>
     <Form>WebBrowser/VirusTotal/VirusTotalWhoisDialog.ui</Form>
@@ -1935,6 +1944,7 @@
     <Resource>IconEditor/cursors/cursors.qrc</Resource>
     <Resource>WebBrowser/Bookmarks/DefaultBookmarks.qrc</Resource>
     <Resource>WebBrowser/OpenSearch/DefaultSearchEngines/DefaultSearchEngines.qrc</Resource>
+    <Resource>WebBrowser/UserAgent/UserAgentDefaults.qrc</Resource>
     <Resource>WebBrowser/data/html.qrc</Resource>
     <Resource>WebBrowser/data/icons.qrc</Resource>
     <Resource>WebBrowser/data/javascript.qrc</Resource>
@@ -2060,6 +2070,7 @@
     <Other>WebBrowser/OpenSearch/DefaultSearchEngines/Wiktionary.xml</Other>
     <Other>WebBrowser/OpenSearch/DefaultSearchEngines/Yahoo.xml</Other>
     <Other>WebBrowser/OpenSearch/DefaultSearchEngines/YouTube.xml</Other>
+    <Other>WebBrowser/UserAgent/UserAgentDefaults.xml</Other>
     <Other>WebBrowser/data/html/adblockPage.html</Other>
     <Other>WebBrowser/data/html/speeddialPage.html</Other>
     <Other>WebBrowser/data/html/startPage.html</Other>

eric ide

mercurial