File indexing completed on 2024-05-19 04:59:18
0001 /* ============================================================ 0002 * Personal Information Manager plugin for Falkon 0003 * Copyright (C) 2012-2016 David Rosca <nowrep@gmail.com> 0004 * Copyright (C) 2012-2014 Mladen Pejaković <pejakm@autistici.org> 0005 * 0006 * This program is free software: you can redistribute it and/or modify 0007 * it under the terms of the GNU General Public License as published by 0008 * the Free Software Foundation, either version 3 of the License, or 0009 * (at your option) any later version. 0010 * 0011 * This program is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License 0017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0018 * ============================================================ */ 0019 #include "PIM_handler.h" 0020 #include "PIM_settings.h" 0021 #include "webview.h" 0022 #include "webpage.h" 0023 #include "webhittestresult.h" 0024 0025 #include <QApplication> 0026 #include <QSettings> 0027 #include <QLabel> 0028 #include <QToolTip> 0029 #include <QKeyEvent> 0030 0031 PIM_Handler::PIM_Handler(const QString &sPath, QObject* parent) 0032 : QObject(parent) 0033 , m_settingsFile(sPath + QL1S("/extensions.ini")) 0034 , m_loaded(false) 0035 { 0036 } 0037 0038 void PIM_Handler::loadSettings() 0039 { 0040 QSettings settings(m_settingsFile, QSettings::IniFormat); 0041 0042 settings.beginGroup(QSL("PIM")); 0043 m_allInfo[PI_LastName] = settings.value(QSL("LastName"), QString()).toString(); 0044 m_allInfo[PI_FirstName] = settings.value(QSL("FirstName"), QString()).toString(); 0045 m_allInfo[PI_Email] = settings.value(QSL("Email"), QString()).toString(); 0046 m_allInfo[PI_Mobile] = settings.value(QSL("Mobile"), QString()).toString(); 0047 m_allInfo[PI_Phone] = settings.value(QSL("Phone"), QString()).toString(); 0048 m_allInfo[PI_Address] = settings.value(QSL("Address"), QString()).toString(); 0049 m_allInfo[PI_City] = settings.value(QSL("City"), QString()).toString(); 0050 m_allInfo[PI_Zip] = settings.value(QSL("Zip"), QString()).toString(); 0051 m_allInfo[PI_State] = settings.value(QSL("State"), QString()).toString(); 0052 m_allInfo[PI_Country] = settings.value(QSL("Country"), QString()).toString(); 0053 m_allInfo[PI_HomePage] = settings.value(QSL("HomePage"), QString()).toString(); 0054 m_allInfo[PI_Special1] = settings.value(QSL("Special1"), QString()).toString(); 0055 m_allInfo[PI_Special2] = settings.value(QSL("Special2"), QString()).toString(); 0056 m_allInfo[PI_Special3] = settings.value(QSL("Special3"), QString()).toString(); 0057 settings.endGroup(); 0058 0059 m_translations[PI_LastName] = tr("Last Name"); 0060 m_translations[PI_FirstName] = tr("First Name"); 0061 m_translations[PI_Email] = tr("E-mail"); 0062 m_translations[PI_Mobile] = tr("Mobile"); 0063 m_translations[PI_Phone] = tr("Phone"); 0064 m_translations[PI_Address] = tr("Address"); 0065 m_translations[PI_City] = tr("City"); 0066 m_translations[PI_Zip] = tr("ZIP Code"); 0067 m_translations[PI_State] = tr("State/Region"); 0068 m_translations[PI_Country] = tr("Country"); 0069 m_translations[PI_HomePage] = tr("Home Page"); 0070 m_translations[PI_Special1] = tr("Custom 1"); 0071 m_translations[PI_Special2] = tr("Custom 2"); 0072 m_translations[PI_Special3] = tr("Custom 3"); 0073 0074 m_infoMatches[PI_LastName] << QSL("lastname") << QSL("surname"); 0075 m_infoMatches[PI_FirstName] << QSL("firstname") << QSL("name"); 0076 m_infoMatches[PI_Email] << QSL("email") << QSL("e-mail") << QSL("mail"); 0077 m_infoMatches[PI_Mobile] << QSL("mobile") << QSL("mobilephone"); 0078 m_infoMatches[PI_Phone] << QSL("phone") << QSL("telephone"); 0079 m_infoMatches[PI_Address] << QSL("address"); 0080 m_infoMatches[PI_City] << QSL("city"); 0081 m_infoMatches[PI_Zip] << QSL("zip"); 0082 m_infoMatches[PI_State] << QSL("state") << QSL("region"); 0083 m_infoMatches[PI_Country] << QSL("country"); 0084 m_infoMatches[PI_HomePage] << QSL("homepage") << QSL("www"); 0085 0086 m_loaded = true; 0087 } 0088 0089 void PIM_Handler::showSettings(QWidget* parent) 0090 { 0091 if (!m_settings) { 0092 m_settings = new PIM_Settings(m_settingsFile, parent); 0093 0094 connect(m_settings.data(), &QDialog::accepted, this, &PIM_Handler::loadSettings); 0095 } 0096 0097 m_settings.data()->show(); 0098 m_settings.data()->raise(); 0099 } 0100 0101 void PIM_Handler::populateWebViewMenu(QMenu* menu, WebView* view, const WebHitTestResult &hitTest) 0102 { 0103 m_view = view; 0104 m_clickedPos = hitTest.pos(); 0105 0106 if (!hitTest.isContentEditable()) { 0107 return; 0108 } 0109 0110 if (!m_loaded) { 0111 loadSettings(); 0112 } 0113 0114 auto* pimMenu = new QMenu(tr("Insert Personal Information")); 0115 pimMenu->setIcon(QIcon(QStringLiteral(":/PIM/data/PIM.png"))); 0116 0117 if (!m_allInfo[PI_FirstName].isEmpty() && !m_allInfo[PI_LastName].isEmpty()) { 0118 const QString fullname = m_allInfo[PI_FirstName] + QLatin1Char(' ') + m_allInfo[PI_LastName]; 0119 QAction* action = pimMenu->addAction(fullname, this, &PIM_Handler::pimInsert); 0120 action->setData(fullname); 0121 } 0122 0123 for (int i = 0; i < PI_Max; ++i) { 0124 const QString info = m_allInfo[PI_Type(i)]; 0125 if (info.isEmpty()) { 0126 continue; 0127 } 0128 0129 QAction* action = pimMenu->addAction(info, this, &PIM_Handler::pimInsert); 0130 action->setData(info); 0131 action->setStatusTip(m_translations[PI_Type(i)]); 0132 } 0133 0134 pimMenu->addSeparator(); 0135 pimMenu->addAction(tr("Edit"), this, SLOT(showSettings())); 0136 0137 menu->addMenu(pimMenu); 0138 menu->addSeparator(); 0139 } 0140 0141 bool PIM_Handler::keyPress(WebView* view, QKeyEvent* event) 0142 { 0143 if (!view) { 0144 return false; 0145 } 0146 0147 bool isEnter = event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter; 0148 bool isControlModifier = event->modifiers() & Qt::ControlModifier; 0149 0150 if (!isEnter || !isControlModifier) { 0151 return false; 0152 } 0153 0154 QString source = QL1S("var inputs = document.getElementsByTagName('input');" 0155 "var table = %1;" 0156 "for (var i = 0; i < inputs.length; ++i) {" 0157 " var input = inputs[i];" 0158 " if (input.type != 'text' || input.name == '')" 0159 " continue;" 0160 " for (var key in table) {" 0161 " if (!table.hasOwnProperty(key))" 0162 " continue;" 0163 " if (key == input.name || input.name.indexOf(key) != -1) {" 0164 " input.value = table[key];" 0165 " break;" 0166 " }" 0167 " }" 0168 "}"); 0169 0170 view->page()->runJavaScript(source.arg(matchingJsTable()), WebPage::SafeJsWorld); 0171 0172 return true; 0173 } 0174 0175 void PIM_Handler::unloadPlugin() 0176 { 0177 delete m_settings.data(); 0178 } 0179 0180 void PIM_Handler::webPageCreated(WebPage* page) 0181 { 0182 connect(page, &QWebEnginePage::loadFinished, this, &PIM_Handler::pageLoadFinished); 0183 } 0184 0185 void PIM_Handler::pimInsert() 0186 { 0187 if (!m_view || m_clickedPos.isNull()) 0188 return; 0189 0190 auto* action = qobject_cast<QAction*>(sender()); 0191 if (!action) 0192 return; 0193 0194 QString info = action->data().toString(); 0195 info.replace(QLatin1Char('"'), QLatin1String("\\\"")); 0196 0197 QString source = QL1S("var e = document.elementFromPoint(%1, %2);" 0198 "if (e) {" 0199 " var v = e.value.substring(0, e.selectionStart);" 0200 " v += \"%3\" + e.value.substring(e.selectionEnd);" 0201 " e.value = v;" 0202 "}"); 0203 source = source.arg(m_clickedPos.x()).arg(m_clickedPos.y()).arg(info); 0204 m_view->page()->runJavaScript(source, WebPage::SafeJsWorld); 0205 } 0206 0207 void PIM_Handler::pageLoadFinished() 0208 { 0209 auto* page = qobject_cast<WebPage*>(sender()); 0210 if (!page) { 0211 return; 0212 } 0213 0214 if (!m_loaded) { 0215 loadSettings(); 0216 } 0217 0218 QString source = QL1S("var inputs = document.getElementsByTagName('input');" 0219 "var table = %1;" 0220 "for (var i = 0; i < inputs.length; ++i) {" 0221 " var input = inputs[i];" 0222 " if (input.type != 'text' || input.name == '')" 0223 " continue;" 0224 " for (var key in table) {" 0225 " if (!table.hasOwnProperty(key) || table[key] == '')" 0226 " continue;" 0227 " if (key == input.name || input.name.indexOf(key) != -1) {" 0228 " input.style['-webkit-appearance'] = 'none';" 0229 " input.style['-webkit-box-shadow'] = 'inset 0 0 2px 1px #EEE000';" 0230 " break;" 0231 " }" 0232 " }" 0233 "}"); 0234 0235 page->runJavaScript(source.arg(matchingJsTable()), WebPage::SafeJsWorld); 0236 } 0237 0238 QString PIM_Handler::matchingJsTable() const 0239 { 0240 QString values; 0241 0242 QHashIterator<PI_Type, QStringList> i(m_infoMatches); 0243 while (i.hasNext()) { 0244 i.next(); 0245 0246 const auto ivalues = i.value(); 0247 for (const QString &value : ivalues) { 0248 QString key = m_allInfo.value(i.key()); 0249 key.replace(QL1C('"'), QL1S("\\\"")); 0250 values.append(QSL("\"%1\":\"%2\",").arg(value, key)); 0251 } 0252 } 0253 0254 if (!values.isEmpty()) { 0255 values = values.left(values.size() - 1); 0256 } 0257 0258 return QSL("{ %1 }").arg(values); 0259 }