Falkon Develop
Cross-platform Qt-based web browser
PIM_handler.cpp
Go to the documentation of this file.
1/* ============================================================
2* Personal Information Manager plugin for Falkon
3* Copyright (C) 2012-2016 David Rosca <nowrep@gmail.com>
4* Copyright (C) 2012-2014 Mladen Pejaković <pejakm@autistici.org>
5*
6* This program is free software: you can redistribute it and/or modify
7* it under the terms of the GNU General Public License as published by
8* the Free Software Foundation, either version 3 of the License, or
9* (at your option) any later version.
10*
11* This program is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14* GNU General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License
17* along with this program. If not, see <http://www.gnu.org/licenses/>.
18* ============================================================ */
19#include "PIM_handler.h"
20#include "PIM_settings.h"
21#include "webview.h"
22#include "webpage.h"
23#include "webhittestresult.h"
24
25#include <QApplication>
26#include <QSettings>
27#include <QLabel>
28#include <QToolTip>
29#include <QKeyEvent>
30
31PIM_Handler::PIM_Handler(const QString &sPath, QObject* parent)
32 : QObject(parent)
33 , m_settingsFile(sPath + QL1S("/extensions.ini"))
34 , m_loaded(false)
35{
36}
37
38void PIM_Handler::loadSettings()
39{
40 QSettings settings(m_settingsFile, QSettings::IniFormat);
41
42 settings.beginGroup(QSL("PIM"));
43 m_allInfo[PI_LastName] = settings.value(QSL("LastName"), QString()).toString();
44 m_allInfo[PI_FirstName] = settings.value(QSL("FirstName"), QString()).toString();
45 m_allInfo[PI_Email] = settings.value(QSL("Email"), QString()).toString();
46 m_allInfo[PI_Mobile] = settings.value(QSL("Mobile"), QString()).toString();
47 m_allInfo[PI_Phone] = settings.value(QSL("Phone"), QString()).toString();
48 m_allInfo[PI_Address] = settings.value(QSL("Address"), QString()).toString();
49 m_allInfo[PI_City] = settings.value(QSL("City"), QString()).toString();
50 m_allInfo[PI_Zip] = settings.value(QSL("Zip"), QString()).toString();
51 m_allInfo[PI_State] = settings.value(QSL("State"), QString()).toString();
52 m_allInfo[PI_Country] = settings.value(QSL("Country"), QString()).toString();
53 m_allInfo[PI_HomePage] = settings.value(QSL("HomePage"), QString()).toString();
54 m_allInfo[PI_Special1] = settings.value(QSL("Special1"), QString()).toString();
55 m_allInfo[PI_Special2] = settings.value(QSL("Special2"), QString()).toString();
56 m_allInfo[PI_Special3] = settings.value(QSL("Special3"), QString()).toString();
57 settings.endGroup();
58
59 m_translations[PI_LastName] = tr("Last Name");
60 m_translations[PI_FirstName] = tr("First Name");
61 m_translations[PI_Email] = tr("E-mail");
62 m_translations[PI_Mobile] = tr("Mobile");
63 m_translations[PI_Phone] = tr("Phone");
64 m_translations[PI_Address] = tr("Address");
65 m_translations[PI_City] = tr("City");
66 m_translations[PI_Zip] = tr("ZIP Code");
67 m_translations[PI_State] = tr("State/Region");
68 m_translations[PI_Country] = tr("Country");
69 m_translations[PI_HomePage] = tr("Home Page");
70 m_translations[PI_Special1] = tr("Custom 1");
71 m_translations[PI_Special2] = tr("Custom 2");
72 m_translations[PI_Special3] = tr("Custom 3");
73
74 m_infoMatches[PI_LastName] << QSL("lastname") << QSL("surname");
75 m_infoMatches[PI_FirstName] << QSL("firstname") << QSL("name");
76 m_infoMatches[PI_Email] << QSL("email") << QSL("e-mail") << QSL("mail");
77 m_infoMatches[PI_Mobile] << QSL("mobile") << QSL("mobilephone");
78 m_infoMatches[PI_Phone] << QSL("phone") << QSL("telephone");
79 m_infoMatches[PI_Address] << QSL("address");
80 m_infoMatches[PI_City] << QSL("city");
81 m_infoMatches[PI_Zip] << QSL("zip");
82 m_infoMatches[PI_State] << QSL("state") << QSL("region");
83 m_infoMatches[PI_Country] << QSL("country");
84 m_infoMatches[PI_HomePage] << QSL("homepage") << QSL("www");
85
86 m_loaded = true;
87}
88
89void PIM_Handler::showSettings(QWidget* parent)
90{
91 if (!m_settings) {
92 m_settings = new PIM_Settings(m_settingsFile, parent);
93
94 connect(m_settings.data(), &QDialog::accepted, this, &PIM_Handler::loadSettings);
95 }
96
97 m_settings.data()->show();
98 m_settings.data()->raise();
99}
100
101void PIM_Handler::populateWebViewMenu(QMenu* menu, WebView* view, const WebHitTestResult &hitTest)
102{
103 m_view = view;
104 m_clickedPos = hitTest.pos();
105
106 if (!hitTest.isContentEditable()) {
107 return;
108 }
109
110 if (!m_loaded) {
111 loadSettings();
112 }
113
114 auto* pimMenu = new QMenu(tr("Insert Personal Information"));
115 pimMenu->setIcon(QIcon(QStringLiteral(":/PIM/data/PIM.png")));
116
117 if (!m_allInfo[PI_FirstName].isEmpty() && !m_allInfo[PI_LastName].isEmpty()) {
118 const QString fullname = m_allInfo[PI_FirstName] + QLatin1Char(' ') + m_allInfo[PI_LastName];
119 QAction* action = pimMenu->addAction(fullname, this, &PIM_Handler::pimInsert);
120 action->setData(fullname);
121 }
122
123 for (int i = 0; i < PI_Max; ++i) {
124 const QString info = m_allInfo[PI_Type(i)];
125 if (info.isEmpty()) {
126 continue;
127 }
128
129 QAction* action = pimMenu->addAction(info, this, &PIM_Handler::pimInsert);
130 action->setData(info);
131 action->setStatusTip(m_translations[PI_Type(i)]);
132 }
133
134 pimMenu->addSeparator();
135 pimMenu->addAction(tr("Edit"), this, SLOT(showSettings()));
136
137 menu->addMenu(pimMenu);
138 menu->addSeparator();
139}
140
141bool PIM_Handler::keyPress(WebView* view, QKeyEvent* event)
142{
143 if (!view) {
144 return false;
145 }
146
147 bool isEnter = event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter;
148 bool isControlModifier = event->modifiers() & Qt::ControlModifier;
149
150 if (!isEnter || !isControlModifier) {
151 return false;
152 }
153
154 QString source = QL1S("var inputs = document.getElementsByTagName('input');"
155 "var table = %1;"
156 "for (var i = 0; i < inputs.length; ++i) {"
157 " var input = inputs[i];"
158 " if (input.type != 'text' || input.name == '')"
159 " continue;"
160 " for (var key in table) {"
161 " if (!table.hasOwnProperty(key))"
162 " continue;"
163 " if (key == input.name || input.name.indexOf(key) != -1) {"
164 " input.value = table[key];"
165 " break;"
166 " }"
167 " }"
168 "}");
169
170 view->page()->runJavaScript(source.arg(matchingJsTable()), WebPage::SafeJsWorld);
171
172 return true;
173}
174
176{
177 delete m_settings.data();
178}
179
181{
182 connect(page, &QWebEnginePage::loadFinished, this, &PIM_Handler::pageLoadFinished);
183}
184
185void PIM_Handler::pimInsert()
186{
187 if (!m_view || m_clickedPos.isNull())
188 return;
189
190 auto* action = qobject_cast<QAction*>(sender());
191 if (!action)
192 return;
193
194 QString info = action->data().toString();
195 info.replace(QLatin1Char('"'), QLatin1String("\\\""));
196
197 QString source = QL1S("var e = document.elementFromPoint(%1, %2);"
198 "if (e) {"
199 " var v = e.value.substring(0, e.selectionStart);"
200 " v += \"%3\" + e.value.substring(e.selectionEnd);"
201 " e.value = v;"
202 "}");
203 source = source.arg(m_clickedPos.x()).arg(m_clickedPos.y()).arg(info);
204 m_view->page()->runJavaScript(source, WebPage::SafeJsWorld);
205}
206
207void PIM_Handler::pageLoadFinished()
208{
209 auto* page = qobject_cast<WebPage*>(sender());
210 if (!page) {
211 return;
212 }
213
214 if (!m_loaded) {
215 loadSettings();
216 }
217
218 QString source = QL1S("var inputs = document.getElementsByTagName('input');"
219 "var table = %1;"
220 "for (var i = 0; i < inputs.length; ++i) {"
221 " var input = inputs[i];"
222 " if (input.type != 'text' || input.name == '')"
223 " continue;"
224 " for (var key in table) {"
225 " if (!table.hasOwnProperty(key) || table[key] == '')"
226 " continue;"
227 " if (key == input.name || input.name.indexOf(key) != -1) {"
228 " input.style['-webkit-appearance'] = 'none';"
229 " input.style['-webkit-box-shadow'] = 'inset 0 0 2px 1px #EEE000';"
230 " break;"
231 " }"
232 " }"
233 "}");
234
235 page->runJavaScript(source.arg(matchingJsTable()), WebPage::SafeJsWorld);
236}
237
238QString PIM_Handler::matchingJsTable() const
239{
240 QString values;
241
242 QHashIterator<PI_Type, QStringList> i(m_infoMatches);
243 while (i.hasNext()) {
244 i.next();
245
246 const auto ivalues = i.value();
247 for (const QString &value : ivalues) {
248 QString key = m_allInfo.value(i.key());
249 key.replace(QL1C('"'), QL1S("\\\""));
250 values.append(QSL("\"%1\":\"%2\",").arg(value, key));
251 }
252 }
253
254 if (!values.isEmpty()) {
255 values = values.left(values.size() - 1);
256 }
257
258 return QSL("{ %1 }").arg(values);
259}
bool keyPress(WebView *view, QKeyEvent *event)
void webPageCreated(WebPage *page)
PIM_Handler(const QString &sPath, QObject *parent=nullptr)
Definition: PIM_handler.cpp:31
void showSettings(QWidget *parent=nullptr)
Definition: PIM_handler.cpp:89
void unloadPlugin()
void populateWebViewMenu(QMenu *menu, WebView *view, const WebHitTestResult &hitTest)
QPoint pos() const
bool isContentEditable() const
@ SafeJsWorld
Definition: webpage.h:45
WebPage * page() const
Definition: webview.cpp:132
int value(const QColor &c)
Definition: colors.cpp:238
i
Definition: i18n.py:23
#define QL1S(x)
Definition: qzcommon.h:44
#define QL1C(x)
Definition: qzcommon.h:48
#define QSL(x)
Definition: qzcommon.h:40