Sun, 16 May 2021 20:07:24 +0200
Replaced all imports of PyQt5 to PyQt6 and started to replace code using obsoleted methods and adapt to the PyQt6 enum usage.
# -*- coding: utf-8 -*- # Copyright (c) 2012 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing a personal information manager used to complete form fields. """ import functools from PyQt6.QtCore import Qt, QObject, QPoint from PyQt6.QtWidgets import QDialog, QMenu import Preferences import UI.PixmapCache from ..WebBrowserPage import WebBrowserPage 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().__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.DialogCode.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")) for key, info in sorted(self.__allInfo.items()): if info: act = submenu.addAction(self.__translations[key]) act.setData(info) act.triggered.connect( functools.partial(self.__insertData, act)) submenu.addSeparator() submenu.addAction(self.tr("Edit Personal Information"), self.showConfigurationDialog) menu.addMenu(submenu) menu.addSeparator() def __insertData(self, act): """ Private slot to insert the selected personal information. @param act reference to the action that triggered @type QAction """ if self.__view is None or self.__clickedPos.isNull(): 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, WebBrowserPage.SafeJsWorld) 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.Key_Return, Qt.Key.Key_Enter] isControlModifier = ( evt.modifiers() & Qt.KeyboardModifier.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, WebBrowserPage.SafeJsWorld) 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 @type WebBrowserPage """ page.loadFinished.connect(lambda ok: self.__pageLoadFinished(ok, page)) def __pageLoadFinished(self, ok, page): """ Private slot to handle the completion of a page load. @param ok flag indicating a successful load @type bool @param page reference to the web page object @type WebBrowserPage """ 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, WebBrowserPage.SafeJsWorld) 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))