Continued porting the web browser. QtWebEngine

Sat, 20 Feb 2016 12:26:28 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 20 Feb 2016 12:26:28 +0100
branch
QtWebEngine
changeset 4752
a3bcc42a82a9
parent 4751
f745a556fd6f
child 4753
8d2ea02ed785

Continued porting the web browser.

- added the Personal Information Manager

Preferences/__init__.py file | annotate | diff | comparison | revisions
WebBrowser/FlashCookieManager/FlashCookieManager.py file | annotate | diff | comparison | revisions
WebBrowser/FlashCookieManager/FlashCookieManagerDialog.py file | annotate | diff | comparison | revisions
WebBrowser/PersonalInformationManager/PersonalDataDialog.py file | annotate | diff | comparison | revisions
WebBrowser/PersonalInformationManager/PersonalDataDialog.ui file | annotate | diff | comparison | revisions
WebBrowser/PersonalInformationManager/PersonalInformationManager.py file | annotate | diff | comparison | revisions
WebBrowser/PersonalInformationManager/__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	Fri Feb 19 19:55:56 2016 +0100
+++ b/Preferences/__init__.py	Sat Feb 20 12:26:28 2016 +0100
@@ -1025,13 +1025,9 @@
         "WebSearchKeywords": [],    # array of two tuples (keyword,
                                     # search engine name)
         "SearchLanguage": QLocale().language(),
-        # Flash Cookie Manager
-        "FlashCookiesDeleteOnStartExit": False,
-        "FlashCookieAutoRefresh": False,
-        "FlashCookieNotify": False,
-        "FlashCookiesWhitelist": [],
-        "FlashCookiesBlacklist": [],
-        "FlashCookiesDataPath": flashDataPathForOS(),
+        # Flash Cookie Manager: identical to helpDefaults
+        # PIM:                  identical to helpDefaults
+        # VirusTotal:           identical to helpDefaults
     }
     
     @classmethod
@@ -2654,6 +2650,11 @@
     @param prefClass preferences class used as the storage area
     @return the requested help setting
     """
+    # the following entries are identical to the ones of the help viewer
+    # and are being redirected there
+    if key.startswith(("FlashCookies", "Pim", "VirusTotal")):
+        return getHelp(key, prefClass)
+    
     if not prefClass.webEngineSettingsIntitialized:
         prefClass.initWebEngineSettingsDefaults()
     
@@ -2758,8 +2759,6 @@
                  "LocalContentCanAccessFileUrls", "XSSAuditingEnabled",
                  "ScrollAnimatorEnabled", "ErrorPageEnabled",
                  "WarnOnMultipleClose", "WebSearchSuggestions",
-                 "FlashCookiesDeleteOnStartExit", "FlashCookieAutoRefresh",
-                 "FlashCookieNotify",
                  ]:
         return toBool(prefClass.settings.value(
             "WebBrowser/" + key, prefClass.webBrowserDefaults[key]))
@@ -2768,10 +2767,8 @@
 ##                 "GreaseMonkeyDisabledScripts", "NoCacheHosts",
 ##                 "FlashCookiesWhitelist", "FlashCookiesBlacklist",
 ##                 ]:
-    elif key in ["FlashCookiesWhitelist", "FlashCookiesBlacklist",
-                 ]:
-        return toList(prefClass.settings.value(
-            "WebBrowser/" + key, prefClass.helpDefaults[key]))
+##        return toList(prefClass.settings.value(
+##            "WebBrowser/" + key, prefClass.helpDefaults[key]))
     else:
         return prefClass.settings.value("WebBrowser/" + key,
                                         prefClass.webBrowserDefaults[key])
@@ -2785,6 +2782,11 @@
     @param value the value to be set
     @param prefClass preferences class used as the storage area
     """
+    # the following entries are identical to the ones of the help viewer
+    # and are being redirected there
+    if key.startswith(("FlashCookies", "Pim", "VirusTotal")):
+        setHelp(key, value, prefClass)
+    
     if key in ["StandardFont", "FixedFont"]:
         prefClass.settings.setValue("WebBrowser/" + key, value.toString())
     elif key == "SaveUrlColor":
--- a/WebBrowser/FlashCookieManager/FlashCookieManager.py	Fri Feb 19 19:55:56 2016 +0100
+++ b/WebBrowser/FlashCookieManager/FlashCookieManager.py	Sat Feb 20 12:26:28 2016 +0100
@@ -54,7 +54,7 @@
         # start the timer if needed
         self.__startStopTimer()
         
-        if Preferences.getHelp("FlashCookiesDeleteOnStartExit"):
+        if Preferences.getWebBrowser("FlashCookiesDeleteOnStartExit"):
             self.__loadFlashCookies()
             self.__removeAllButWhitelisted()
     
@@ -65,7 +65,7 @@
         if self.__flashCookieManagerDialog is not None:
             self.__flashCookieManagerDialog.close()
         
-        if Preferences.getHelp("FlashCookiesDeleteOnStartExit"):
+        if Preferences.getWebBrowser("FlashCookiesDeleteOnStartExit"):
             self.__removeAllButWhitelisted()
     
     def setFlashCookies(self, cookies):
@@ -119,7 +119,8 @@
         @return flag indicating a blacklisted cookie
         @rtype bool
         """
-        return cookie.origin in Preferences.getHelp("FlashCookiesBlacklist")
+        return cookie.origin in \
+            Preferences.getWebBrowser("FlashCookiesBlacklist")
     
     def __isWhitelisted(self, cookie):
         """
@@ -130,7 +131,8 @@
         @return flag indicating a whitelisted cookie
         @rtype bool
         """
-        return cookie.origin in Preferences.getHelp("FlashCookiesWhitelist")
+        return cookie.origin in \
+            Preferences.getWebBrowser("FlashCookiesWhitelist")
     
     def __removeAllButWhitelisted(self):
         """
@@ -169,7 +171,7 @@
         @return Flash Player data path
         @rtype str
         """
-        return Preferences.getHelp("FlashCookiesDataPath")
+        return Preferences.getWebBrowser("FlashCookiesDataPath")
     
     def preferencesChanged(self):
         """
@@ -218,7 +220,7 @@
             if newCookie:
                 newCookieList.append(cookie.path + "/" + cookie.name)
         
-        if newCookieList and Preferences.getHelp("FlashCookieNotify"):
+        if newCookieList and Preferences.getWebBrowser("FlashCookieNotify"):
             self.__newCookiesList.extend(newCookieList)
             win = WebBrowser.WebBrowserWindow.WebBrowserWindow.mainWindow()
             if win is None:
@@ -250,7 +252,7 @@
         """
         Private slot to start or stop the auto refresh timer.
         """
-        if Preferences.getHelp("FlashCookieAutoRefresh"):
+        if Preferences.getWebBrowser("FlashCookieAutoRefresh"):
             if not self.__timer.isActive():
                 if not bool(self.__flashCookies):
                     self.__loadFlashCookies()
--- a/WebBrowser/FlashCookieManager/FlashCookieManagerDialog.py	Fri Feb 19 19:55:56 2016 +0100
+++ b/WebBrowser/FlashCookieManager/FlashCookieManagerDialog.py	Sat Feb 20 12:26:28 2016 +0100
@@ -394,8 +394,10 @@
         self.whiteList.clear()
         self.blackList.clear()
         
-        self.whiteList.addItems(Preferences.getHelp("FlashCookiesWhitelist"))
-        self.blackList.addItems(Preferences.getHelp("FlashCookiesBlacklist"))
+        self.whiteList.addItems(
+            Preferences.getWebBrowser("FlashCookiesWhitelist"))
+        self.blackList.addItems(
+            Preferences.getWebBrowser("FlashCookiesBlacklist"))
         
         self.on_whiteList_itemSelectionChanged()
         self.on_blackList_itemSelectionChanged()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/PersonalInformationManager/PersonalDataDialog.py	Sat Feb 20 12:26:28 2016 +0100
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a dialog to enter personal data.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtWidgets import QDialog
+
+from .Ui_PersonalDataDialog import Ui_PersonalDataDialog
+
+import UI.PixmapCache
+import Preferences
+
+
+class PersonalDataDialog(QDialog, Ui_PersonalDataDialog):
+    """
+    Class implementing a dialog to enter personal data.
+    """
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent widget (QWidget)
+        """
+        super(PersonalDataDialog, self).__init__(parent)
+        self.setupUi(self)
+        
+        self.iconLabel.setPixmap(UI.PixmapCache.getPixmap("pim48.png"))
+        
+        self.firstnameEdit.setText(Preferences.getWebBrowser("PimFirstName"))
+        self.lastnameEdit.setText(Preferences.getWebBrowser("PimLastName"))
+        self.fullnameEdit.setText(Preferences.getWebBrowser("PimFullName"))
+        self.emailEdit.setText(Preferences.getWebBrowser("PimEmail"))
+        self.phoneEdit.setText(Preferences.getWebBrowser("PimPhone"))
+        self.mobileEdit.setText(Preferences.getWebBrowser("PimMobile"))
+        self.addressEdit.setText(Preferences.getWebBrowser("PimAddress"))
+        self.cityEdit.setText(Preferences.getWebBrowser("PimCity"))
+        self.zipEdit.setText(Preferences.getWebBrowser("PimZip"))
+        self.stateEdit.setText(Preferences.getWebBrowser("PimState"))
+        self.countryEdit.setText(Preferences.getWebBrowser("PimCountry"))
+        self.homepageEdit.setText(Preferences.getWebBrowser("PimHomePage"))
+        self.special1Edit.setText(Preferences.getWebBrowser("PimSpecial1"))
+        self.special2Edit.setText(Preferences.getWebBrowser("PimSpecial2"))
+        self.special3Edit.setText(Preferences.getWebBrowser("PimSpecial3"))
+        self.special4Edit.setText(Preferences.getWebBrowser("PimSpecial4"))
+    
+    def storeData(self):
+        """
+        Public method to store the entered personal information.
+        """
+        Preferences.setWebBrowser("PimFirstName", self.firstnameEdit.text())
+        Preferences.setWebBrowser("PimLastName", self.lastnameEdit.text())
+        Preferences.setWebBrowser("PimFullName", self.fullnameEdit.text())
+        Preferences.setWebBrowser("PimEmail", self.emailEdit.text())
+        Preferences.setWebBrowser("PimPhone", self.phoneEdit.text())
+        Preferences.setWebBrowser("PimMobile", self.mobileEdit.text())
+        Preferences.setWebBrowser("PimAddress", self.addressEdit.text())
+        Preferences.setWebBrowser("PimCity", self.cityEdit.text())
+        Preferences.setWebBrowser("PimZip", self.zipEdit.text())
+        Preferences.setWebBrowser("PimState", self.stateEdit.text())
+        Preferences.setWebBrowser("PimCountry", self.countryEdit.text())
+        Preferences.setWebBrowser("PimHomePage", self.homepageEdit.text())
+        Preferences.setWebBrowser("PimSpecial1", self.special1Edit.text())
+        Preferences.setWebBrowser("PimSpecial2", self.special2Edit.text())
+        Preferences.setWebBrowser("PimSpecial3", self.special3Edit.text())
+        Preferences.setWebBrowser("PimSpecial4", self.special4Edit.text())
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/PersonalInformationManager/PersonalDataDialog.ui	Sat Feb 20 12:26:28 2016 +0100
@@ -0,0 +1,384 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PersonalDataDialog</class>
+ <widget class="QDialog" name="PersonalDataDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>600</width>
+    <height>400</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Personal Information</string>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <item>
+      <spacer name="horizontalSpacer_2">
+       <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>
+      <widget class="QLabel" name="iconLabel">
+       <property name="minimumSize">
+        <size>
+         <width>48</width>
+         <height>48</height>
+        </size>
+       </property>
+       <property name="text">
+        <string notr="true">Icon</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QLabel" name="label">
+       <property name="text">
+        <string>&lt;h2&gt;Personal Information&lt;/h2&gt;</string>
+       </property>
+      </widget>
+     </item>
+     <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>
+    </layout>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_01">
+     <property name="text">
+      <string>Your personal information that will be used on webpages.</string>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QGridLayout" name="gridLayout">
+     <item row="0" column="0">
+      <widget class="QLabel" name="label_02">
+       <property name="text">
+        <string>First Name:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="1">
+      <widget class="QLineEdit" name="firstnameEdit"/>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLabel" name="label_08">
+       <property name="text">
+        <string>ZIP Code:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="3">
+      <widget class="QLineEdit" name="zipEdit"/>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="label_03">
+       <property name="text">
+        <string>Last Name:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QLineEdit" name="lastnameEdit"/>
+     </item>
+     <item row="1" column="2">
+      <widget class="QLabel" name="label_09">
+       <property name="text">
+        <string>State/Region:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="3">
+      <widget class="QLineEdit" name="stateEdit"/>
+     </item>
+     <item row="2" column="0">
+      <widget class="QLabel" name="label_18">
+       <property name="text">
+        <string>Full Name:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="1">
+      <widget class="QLineEdit" name="fullnameEdit"/>
+     </item>
+     <item row="2" column="2">
+      <widget class="QLabel" name="label_10">
+       <property name="text">
+        <string>Country:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="3">
+      <widget class="QLineEdit" name="countryEdit"/>
+     </item>
+     <item row="3" column="0">
+      <widget class="QLabel" name="label_12">
+       <property name="text">
+        <string>E-mail:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="1">
+      <widget class="QLineEdit" name="emailEdit"/>
+     </item>
+     <item row="3" column="2">
+      <widget class="QLabel" name="label_11">
+       <property name="text">
+        <string>Home Page:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="3">
+      <widget class="QLineEdit" name="homepageEdit"/>
+     </item>
+     <item row="4" column="0">
+      <widget class="QLabel" name="label_04">
+       <property name="text">
+        <string>Phone:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="4" column="1">
+      <widget class="QLineEdit" name="phoneEdit"/>
+     </item>
+     <item row="4" column="2">
+      <widget class="QLabel" name="label_13">
+       <property name="text">
+        <string>Custom 1:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="4" column="3">
+      <widget class="QLineEdit" name="special1Edit"/>
+     </item>
+     <item row="5" column="0">
+      <widget class="QLabel" name="label_05">
+       <property name="text">
+        <string>Mobile Phone:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="5" column="1">
+      <widget class="QLineEdit" name="mobileEdit"/>
+     </item>
+     <item row="5" column="2">
+      <widget class="QLabel" name="label_14">
+       <property name="text">
+        <string>Custom 2:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="5" column="3">
+      <widget class="QLineEdit" name="special2Edit"/>
+     </item>
+     <item row="6" column="0">
+      <widget class="QLabel" name="label_06">
+       <property name="text">
+        <string>Address:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="6" column="1">
+      <widget class="QLineEdit" name="addressEdit"/>
+     </item>
+     <item row="6" column="2">
+      <widget class="QLabel" name="label_15">
+       <property name="text">
+        <string>Custom 3:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="6" column="3">
+      <widget class="QLineEdit" name="special3Edit"/>
+     </item>
+     <item row="7" column="0">
+      <widget class="QLabel" name="label_07">
+       <property name="text">
+        <string>City:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="7" column="1">
+      <widget class="QLineEdit" name="cityEdit"/>
+     </item>
+     <item row="7" column="2">
+      <widget class="QLabel" name="label_17">
+       <property name="text">
+        <string>Custom 4:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="7" column="3">
+      <widget class="QLineEdit" name="special4Edit"/>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QLabel" name="label_16">
+     <property name="text">
+      <string>&lt;b&gt;Note:&lt;/b&gt; Press Ctrl+ENTER to autofill form fields for which personal entries were found.</string>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>31</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>firstnameEdit</tabstop>
+  <tabstop>lastnameEdit</tabstop>
+  <tabstop>fullnameEdit</tabstop>
+  <tabstop>emailEdit</tabstop>
+  <tabstop>phoneEdit</tabstop>
+  <tabstop>mobileEdit</tabstop>
+  <tabstop>addressEdit</tabstop>
+  <tabstop>cityEdit</tabstop>
+  <tabstop>zipEdit</tabstop>
+  <tabstop>stateEdit</tabstop>
+  <tabstop>countryEdit</tabstop>
+  <tabstop>homepageEdit</tabstop>
+  <tabstop>special1Edit</tabstop>
+  <tabstop>special2Edit</tabstop>
+  <tabstop>special3Edit</tabstop>
+  <tabstop>special4Edit</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>PersonalDataDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>PersonalDataDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</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/PersonalInformationManager/PersonalInformationManager.py	Sat Feb 20 12:26:28 2016 +0100
@@ -0,0 +1,281 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Module implementing a personal information manager used to complete form
+fields.
+"""
+
+from __future__ import unicode_literals
+
+from PyQt5.QtCore import Qt, QObject, QPoint
+from PyQt5.QtWidgets import QDialog, QMenu
+
+import Preferences
+import UI.PixmapCache
+
+
+class PersonalInformationManager(QObject):
+    """
+    Class implementing the personal information manager used to complete form
+    fields.
+    """
+    FullName = 0
+    LastName = 1
+    FirstName = 2
+    Email = 3
+    Mobile = 4
+    Phone = 5
+    Address = 6
+    City = 7
+    Zip = 8
+    State = 9
+    Country = 10
+    HomePage = 11
+    Special1 = 12
+    Special2 = 13
+    Special3 = 14
+    Special4 = 15
+    Max = 16
+    Invalid = 256
+    
+    def __init__(self, parent=None):
+        """
+        Constructor
+        
+        @param parent reference to the parent object (QObject)
+        """
+        super(PersonalInformationManager, self).__init__(parent)
+        
+        self.__loaded = False
+        self.__allInfo = {}
+        self.__infoMatches = {}
+        self.__translations = {}
+        
+        self.__view = None
+        self.__clickedPos = QPoint()
+    
+    def __loadSettings(self):
+        """
+        Private method to load the settings.
+        """
+        self.__allInfo[self.FullName] = \
+            Preferences.getWebBrowser("PimFullName")
+        self.__allInfo[self.LastName] = \
+            Preferences.getWebBrowser("PimLastName")
+        self.__allInfo[self.FirstName] = \
+            Preferences.getWebBrowser("PimFirstName")
+        self.__allInfo[self.Email] = Preferences.getWebBrowser("PimEmail")
+        self.__allInfo[self.Mobile] = Preferences.getWebBrowser("PimMobile")
+        self.__allInfo[self.Phone] = Preferences.getWebBrowser("PimPhone")
+        self.__allInfo[self.Address] = Preferences.getWebBrowser("PimAddress")
+        self.__allInfo[self.City] = Preferences.getWebBrowser("PimCity")
+        self.__allInfo[self.Zip] = Preferences.getWebBrowser("PimZip")
+        self.__allInfo[self.State] = Preferences.getWebBrowser("PimState")
+        self.__allInfo[self.Country] = Preferences.getWebBrowser("PimCountry")
+        self.__allInfo[self.HomePage] = \
+            Preferences.getWebBrowser("PimHomePage")
+        self.__allInfo[self.Special1] = \
+            Preferences.getWebBrowser("PimSpecial1")
+        self.__allInfo[self.Special2] = \
+            Preferences.getWebBrowser("PimSpecial2")
+        self.__allInfo[self.Special3] = \
+            Preferences.getWebBrowser("PimSpecial3")
+        self.__allInfo[self.Special4] = \
+            Preferences.getWebBrowser("PimSpecial4")
+        
+        self.__translations[self.FullName] = self.tr("Full Name")
+        self.__translations[self.LastName] = self.tr("Last Name")
+        self.__translations[self.FirstName] = self.tr("First Name")
+        self.__translations[self.Email] = self.tr("E-mail")
+        self.__translations[self.Mobile] = self.tr("Mobile")
+        self.__translations[self.Phone] = self.tr("Phone")
+        self.__translations[self.Address] = self.tr("Address")
+        self.__translations[self.City] = self.tr("City")
+        self.__translations[self.Zip] = self.tr("ZIP Code")
+        self.__translations[self.State] = self.tr("State/Region")
+        self.__translations[self.Country] = self.tr("Country")
+        self.__translations[self.HomePage] = self.tr("Home Page")
+        self.__translations[self.Special1] = self.tr("Custom 1")
+        self.__translations[self.Special2] = self.tr("Custom 2")
+        self.__translations[self.Special3] = self.tr("Custom 3")
+        self.__translations[self.Special4] = self.tr("Custom 4")
+        
+        self.__infoMatches[self.FullName] = ["fullname", "realname"]
+        self.__infoMatches[self.LastName] = ["lastname", "surname"]
+        self.__infoMatches[self.FirstName] = ["firstname", "name"]
+        self.__infoMatches[self.Email] = ["email", "e-mail", "mail"]
+        self.__infoMatches[self.Mobile] = ["mobile", "mobilephone"]
+        self.__infoMatches[self.Phone] = ["phone", "telephone"]
+        self.__infoMatches[self.Address] = ["address"]
+        self.__infoMatches[self.City] = ["city"]
+        self.__infoMatches[self.Zip] = ["zip"]
+        self.__infoMatches[self.State] = ["state", "region"]
+        self.__infoMatches[self.Country] = ["country"]
+        self.__infoMatches[self.HomePage] = ["homepage", "www"]
+        
+        self.__loaded = True
+    
+    def showConfigurationDialog(self):
+        """
+        Public method to show the configuration dialog.
+        """
+        from .PersonalDataDialog import PersonalDataDialog
+        dlg = PersonalDataDialog()
+        if dlg.exec_() == QDialog.Accepted:
+            dlg.storeData()
+            self.__loadSettings()
+    
+    def createSubMenu(self, menu, view, hitTestResult):
+        """
+        Public method to create the personal information sub-menu.
+        
+        @param menu reference to the main menu (QMenu)
+        @param view reference to the view (HelpBrowser)
+        @param hitTestResult reference to the hit test result
+            (WebHitTestResult)
+        """
+        self.__view = view
+        self.__clickedPos = hitTestResult.pos()
+        
+        if not hitTestResult.isContentEditable():
+            return
+        
+        if not self.__loaded:
+            self.__loadSettings()
+        
+        submenu = QMenu(self.tr("Insert Personal Information"), menu)
+        submenu.setIcon(UI.PixmapCache.getIcon("pim.png"))
+        
+        for key, info in sorted(self.__allInfo.items()):
+            if info:
+                act = submenu.addAction(
+                    self.__translations[key], self.__insertData)
+                act.setData(info)
+        
+        submenu.addSeparator()
+        submenu.addAction(self.tr("Edit Personal Information"),
+                          self.showConfigurationDialog)
+        
+        menu.addMenu(submenu)
+        menu.addSeparator()
+    
+    def __insertData(self):
+        """
+        Private slot to insert the selected personal information.
+        """
+        if self.__view is None or self.__clickedPos.isNull():
+            return
+        
+        act = self.sender()
+        if act is None:
+            return
+        
+        info = act.data()
+        info = info.replace('"', '\\"')
+        
+        source = """
+            var e = document.elementFromPoint({0}, {1});
+            if (e) {{
+                var v = e.value.substring(0, e.selectionStart);
+                v += "{2}" + e.value.substring(e.selectionEnd);
+                e.value = v;
+            }}""".format(self.__clickedPos.x(), self.__clickedPos.y(), info)
+        self.__view.page().runJavaScript(source)
+    
+    def viewKeyPressEvent(self, view, evt):
+        """
+        Protected method to handle key press events we are interested in.
+        
+        @param view reference to the view (HelpBrowser)
+        @param evt reference to the key event (QKeyEvent)
+        @return flag indicating handling of the event (boolean)
+        """
+        if view is None:
+            return False
+        
+        isEnter = evt.key() in [Qt.Key_Return, Qt.Key_Enter]
+        isControlModifier = evt.modifiers() & Qt.ControlModifier
+        if not isEnter or not isControlModifier:
+            return False
+        
+        if not self.__loaded:
+            self.__loadSettings()
+        
+        source = """
+            var inputs = document.getElementsByTagName('input');
+            var table = {0};
+            for (var i = 0; i < inputs.length; ++i) {{
+                var input = inputs[i];
+                if (input.type != 'text' || input.name == '')
+                    continue;
+                for (var key in table) {{
+                    if (!table.hasOwnProperty(key))
+                        continue;
+                    if (key == input.name || input.name.indexOf(key) != -1) {{
+                        input.value = table[key];
+                        break;
+                    }}
+                }}
+            }}""".format(self.__matchingJsTable())
+        view.page().runJavaScript(source)
+        
+        return True
+    
+    def connectPage(self, page):
+        """
+        Public method to allow the personal information manager to connect to
+        the page.
+        
+        @param page reference to the web page (HelpWebPage)
+        """
+        page.loadFinished.connect(self.__pageLoadFinished)
+    
+    def __pageLoadFinished(self, ok):
+        """
+        Private slot to handle the completion of a page load.
+        
+        @param ok flag indicating a successful load (boolean)
+        """
+        page = self.sender()
+        if page is None or not ok:
+            return
+        
+        if not self.__loaded:
+            self.__loadSettings()
+        
+        source = """
+            var inputs = document.getElementsByTagName('input');
+            var table = {0};
+            for (var i = 0; i < inputs.length; ++i) {{
+                var input = inputs[i];
+                if (input.type != 'text' || input.name == '')
+                    continue;
+                for (var key in table) {{
+                    if (!table.hasOwnProperty(key) || table[key] == '')
+                        continue;
+                    if (key == input.name || input.name.indexOf(key) != -1) {{
+                        input.style['-webkit-appearance'] = 'none';
+                        input.style['-webkit-box-shadow'] = 
+                            'inset 0 0 2px 1px #000EEE';
+                        break;
+                    }}
+                }}
+            }}""".format(self.__matchingJsTable())
+        page.runJavaScript(source)
+    
+    def __matchingJsTable(self):
+        """
+        Private method to create the common part of the JavaScript sources.
+        
+        @return JavaScript source
+        @rtype str
+        """
+        values = []
+        for key, names in self.__infoMatches.items():
+            for name in names:
+                value = self.__allInfo[key].replace('"', '\\"')
+                values.append('"{0}":"{1}"'.format(name, value))
+        return "{{ {0} }}".format(",".join(values))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WebBrowser/PersonalInformationManager/__init__.py	Sat Feb 20 12:26:28 2016 +0100
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (c) 2012 - 2016 Detlev Offenbach <detlev@die-offenbachs.de>
+#
+
+"""
+Package implementing the personal information manager for the completion of
+forms.
+"""
--- a/WebBrowser/WebBrowserPage.py	Fri Feb 19 19:55:56 2016 +0100
+++ b/WebBrowser/WebBrowserPage.py	Sat Feb 20 12:26:28 2016 +0100
@@ -47,6 +47,7 @@
 except ImportError:
     SSL_AVAILABLE = False
 
+# TODO: ExternalJsObject: move this to the object
 ###############################################################################
 ##
 ##
@@ -727,7 +728,6 @@
         """
         Private method to setup a web channel to our external object.
         """
-##        self.__externalJsObject = ExternalJsObject(self)
         oldChannel = self.webChannel()
         newChannel = QWebChannel(self)
         newChannel.registerObject("eric_object", ExternalJsObject(self))
@@ -753,5 +753,6 @@
     ## Methods below deal with JavaScript messages
     ##############################################
     
+    # TODO: JavaScript messages: do this right and add the others
     def javaScriptConsoleMessage(self, level, message, lineNumber,  sourceId):
         print("JS-console:", message, lineNumber, sourceId)
--- a/WebBrowser/WebBrowserView.py	Fri Feb 19 19:55:56 2016 +0100
+++ b/WebBrowser/WebBrowserView.py	Sat Feb 20 12:26:28 2016 +0100
@@ -149,8 +149,7 @@
         
         self.__clickedFrame = None
         
-        # TODO: PIM
-##        self.__mw.personalInformationManager().connectPage(self.page())
+        self.__mw.personalInformationManager().connectPage(self.page())
         # TODO: GreaseMonkey
 ##        self.__mw.greaseMonkeyManager().connectPage(self.page())
         
@@ -638,9 +637,9 @@
             menu.addAction(self.__mw.cutAct)
             menu.addAction(self.__mw.copyAct)
             menu.addAction(self.__mw.pasteAct)
-            # TODO: PIM
-##            menu.addSeparator()
-##            self.__mw.personalInformationManager().createSubMenu(menu, self, hit)
+            menu.addSeparator()
+            self.__mw.personalInformationManager().createSubMenu(
+                menu, self, hitTest)
             
             if hitTest.tagName() == "input":
                 menu.addSeparator()
@@ -1273,9 +1272,9 @@
         
         @param evt reference to the key event (QKeyEvent)
         """
-        # TODO: PIM
-##        if self.__mw.personalInformationManager().viewKeyPressEvent(self, evt):
-##            return
+        if self.__mw.personalInformationManager().viewKeyPressEvent(self, evt):
+            evt.accept()
+            return
         
         # TODO: Access Keys
 ##        if self.__enableAccessKeys:
--- a/WebBrowser/WebBrowserWindow.py	Fri Feb 19 19:55:56 2016 +0100
+++ b/WebBrowser/WebBrowserWindow.py	Sat Feb 20 12:26:28 2016 +0100
@@ -93,7 +93,7 @@
 ##    _userAgentsManager = None
 ##    _syncManager = None
 ##    _speedDial = None
-##    _personalInformationManager = None
+    _personalInformationManager = None
 ##    _greaseMonkeyManager = None
     _notification = None
     _featurePermissionManager = None
@@ -1314,24 +1314,23 @@
 ##                self.__showOfflineStorageConfiguration)
 ##        self.__actions.append(self.offlineStorageAct)
         
-        # TODO: PIM
-##        self.personalDataAct = E5Action(
-##            self.tr('Personal Information'),
-##            UI.PixmapCache.getIcon("pim.png"),
-##            self.tr('Personal Information...'),
-##            0, 0,
-##            self, 'webbrowser_personal_information')
-##        self.personalDataAct.setStatusTip(self.tr(
-##            'Configure personal information for completing form fields'))
-##        self.personalDataAct.setWhatsThis(self.tr(
-##            """<b>Personal Information...</b>"""
-##            """<p>Opens a dialog to configure the personal information"""
-##            """ used for completing form fields.</p>"""
-##        ))
-##        if not self.__initShortcutsOnly:
-##            self.personalDataAct.triggered.connect(
-##                self.__showPersonalInformationDialog)
-##        self.__actions.append(self.personalDataAct)
+        self.personalDataAct = E5Action(
+            self.tr('Personal Information'),
+            UI.PixmapCache.getIcon("pim.png"),
+            self.tr('Personal Information...'),
+            0, 0,
+            self, 'webbrowser_personal_information')
+        self.personalDataAct.setStatusTip(self.tr(
+            'Configure personal information for completing form fields'))
+        self.personalDataAct.setWhatsThis(self.tr(
+            """<b>Personal Information...</b>"""
+            """<p>Opens a dialog to configure the personal information"""
+            """ used for completing form fields.</p>"""
+        ))
+        if not self.__initShortcutsOnly:
+            self.personalDataAct.triggered.connect(
+                self.__showPersonalInformationDialog)
+        self.__actions.append(self.personalDataAct)
         
         # TODO: GreaseMonkey
 ##        self.greaseMonkeyAct = E5Action(
@@ -1857,7 +1856,7 @@
 ##        menu.addAction(self.cookiesAct)
         menu.addAction(self.flashCookiesAct)
 ##        menu.addAction(self.offlineStorageAct)
-##        menu.addAction(self.personalDataAct)
+        menu.addAction(self.personalDataAct)
 ##        menu.addAction(self.greaseMonkeyAct)
         menu.addAction(self.featurePermissionAct)
 ##        menu.addSeparator()
@@ -1997,7 +1996,7 @@
 ##        settingstb.addAction(self.cookiesAct)
         settingstb.addAction(self.flashCookiesAct)
 ##        settingstb.addAction(self.offlineStorageAct)
-##        settingstb.addAction(self.personalDataAct)
+        settingstb.addAction(self.personalDataAct)
 ##        settingstb.addAction(self.greaseMonkeyAct)
         settingstb.addAction(self.featurePermissionAct)
         
@@ -3376,12 +3375,12 @@
 ##        from .HelpBrowserWV import HelpWebPage
 ##        HelpWebPage.webPluginFactory().plugin("ClickToFlash").configure()
 ##        
-##    def __showPersonalInformationDialog(self):
-##        """
-##        Private slot to show the Personal Information configuration dialog.
-##        """
-##        self.personalInformationManager().showConfigurationDialog()
-##        
+    def __showPersonalInformationDialog(self):
+        """
+        Private slot to show the Personal Information configuration dialog.
+        """
+        self.personalInformationManager().showConfigurationDialog()
+        
 ##    def __showGreaseMonkeyConfigDialog(self):
 ##        """
 ##        Private slot to show the GreaseMonkey scripts configuration dialog.
@@ -3547,21 +3546,21 @@
 ##        
 ##        return cls._downloadManager
 ##        
-##    @classmethod
-##    def personalInformationManager(cls):
-##        """
-##        Class method to get a reference to the personal information manager.
-##        
-##        @return reference to the personal information manager
-##            (PersonalInformationManager)
-##        """
-##        if cls._personalInformationManager is None:
-##            from .PersonalInformationManager.PersonalInformationManager \
-##                import PersonalInformationManager
-##            cls._personalInformationManager = PersonalInformationManager()
-##        
-##        return cls._personalInformationManager
-##        
+    @classmethod
+    def personalInformationManager(cls):
+        """
+        Class method to get a reference to the personal information manager.
+        
+        @return reference to the personal information manager
+            (PersonalInformationManager)
+        """
+        if cls._personalInformationManager is None:
+            from .PersonalInformationManager.PersonalInformationManager \
+                import PersonalInformationManager
+            cls._personalInformationManager = PersonalInformationManager()
+        
+        return cls._personalInformationManager
+        
 ##    @classmethod
 ##    def greaseMonkeyManager(cls):
 ##        """
--- a/eric6.e4p	Fri Feb 19 19:55:56 2016 +0100
+++ b/eric6.e4p	Sat Feb 20 12:26:28 2016 +0100
@@ -1332,6 +1332,9 @@
     <Source>WebBrowser/Passwords/PasswordWriter.py</Source>
     <Source>WebBrowser/Passwords/PasswordsDialog.py</Source>
     <Source>WebBrowser/Passwords/__init__.py</Source>
+    <Source>WebBrowser/PersonalInformationManager/PersonalDataDialog.py</Source>
+    <Source>WebBrowser/PersonalInformationManager/PersonalInformationManager.py</Source>
+    <Source>WebBrowser/PersonalInformationManager/__init__.py</Source>
     <Source>WebBrowser/SearchWidget.py</Source>
     <Source>WebBrowser/Tools/Scripts.py</Source>
     <Source>WebBrowser/Tools/WebBrowserTools.py</Source>
@@ -1765,6 +1768,7 @@
     <Form>WebBrowser/OpenSearch/OpenSearchDialog.ui</Form>
     <Form>WebBrowser/OpenSearch/OpenSearchEditDialog.ui</Form>
     <Form>WebBrowser/Passwords/PasswordsDialog.ui</Form>
+    <Form>WebBrowser/PersonalInformationManager/PersonalDataDialog.ui</Form>
     <Form>WebBrowser/SearchWidget.ui</Form>
     <Form>WebBrowser/UrlBar/BookmarkActionSelectionDialog.ui</Form>
     <Form>WebBrowser/UrlBar/BookmarkInfoDialog.ui</Form>

eric ide

mercurial