KParts

browserextension.cpp
1 /*
2  This file is part of the KDE project
3  SPDX-FileCopyrightText: 1999 Simon Hausmann <[email protected]>
4  SPDX-FileCopyrightText: 1999 David Faure <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "browserextension.h"
10 
11 #include "kparts_logging.h"
12 
13 #include <KLocalizedString>
14 #include <KMessageBox>
15 #include <KUriFilter>
16 
17 #include <QApplication>
18 #include <QClipboard>
19 #include <QMap>
20 #include <QRegularExpression>
21 #include <QTimer>
22 
23 using namespace KParts;
24 
25 namespace KParts
26 {
27 // Internal class, use to store the status of the actions
28 class KBitArray
29 {
30 public:
31  int val = 0;
32  bool operator[](int index)
33  {
34  return (val & (1 << index)) ? true : false;
35  }
36  void setBit(int index, bool value)
37  {
38  if (value) {
39  val = val | (1 << index);
40  } else {
41  val = val & ~(1 << index);
42  }
43  }
44 };
45 
46 class BrowserExtensionPrivate
47 {
48 public:
49  BrowserExtensionPrivate(KParts::ReadOnlyPart *parent)
50  : m_urlDropHandlingEnabled(false)
51  , m_browserInterface(nullptr)
52  , m_part(parent)
53  {
54  }
55 
56  struct DelayedRequest {
57  QUrl m_delayedURL;
58  KParts::OpenUrlArguments m_delayedArgs;
59  KParts::BrowserArguments m_delayedBrowserArgs;
60  };
61 
62  QList<DelayedRequest> m_requests;
63  bool m_urlDropHandlingEnabled;
64  KBitArray m_actionStatus;
65  QMap<int, QString> m_actionText;
66  BrowserInterface *m_browserInterface;
67 
68  static void createActionSlotMap();
69 
70  KParts::ReadOnlyPart *m_part;
71  OpenUrlArguments m_args;
72  BrowserArguments m_browserArgs;
73 };
74 
77 
78 void BrowserExtensionPrivate::createActionSlotMap()
79 {
80  s_actionSlotMap()->insert("cut", SLOT(cut()));
81  s_actionSlotMap()->insert("copy", SLOT(copy()));
82  s_actionSlotMap()->insert("paste", SLOT(paste()));
83  s_actionSlotMap()->insert("print", SLOT(print()));
84  // Tricky. Those aren't actions in fact, but simply methods that a browserextension
85  // can have or not. No need to return them here.
86  // s_actionSlotMap()->insert( "reparseConfiguration", SLOT(reparseConfiguration()) );
87  // s_actionSlotMap()->insert( "refreshMimeTypes", SLOT(refreshMimeTypes()) );
88 
89  // Create the action-number map
90  BrowserExtension::ActionSlotMap::ConstIterator it = s_actionSlotMap()->constBegin();
91  BrowserExtension::ActionSlotMap::ConstIterator itEnd = s_actionSlotMap()->constEnd();
92  for (int i = 0; it != itEnd; ++it, ++i) {
93  // qDebug() << " action " << it.key() << " number " << i;
94  s_actionNumberMap()->insert(it.key(), i);
95  }
96 }
97 
98 }
99 
101  : QObject(parent)
102  , d(new BrowserExtensionPrivate(parent))
103 {
104  // qDebug() << "BrowserExtension::BrowserExtension() " << this;
105 
106  if (s_actionSlotMap()->isEmpty())
107  // Create the action-slot map
108  {
109  BrowserExtensionPrivate::createActionSlotMap();
110  }
111 
112  // Set the initial status of the actions depending on whether
113  // they're supported or not
114  const QMetaObject *metaobj = metaObject();
115  ActionSlotMap::ConstIterator it = s_actionSlotMap()->constBegin();
116  ActionSlotMap::ConstIterator itEnd = s_actionSlotMap()->constEnd();
117  for (int i = 0; it != itEnd; ++it, ++i) {
118  // Does the extension have a slot with the name of this action ?
119  QByteArray slotSig = it.key() + "()";
120  d->m_actionStatus.setBit(i, metaobj->indexOfMethod(slotSig.constData()) != -1);
121  }
122 
123  connect(d->m_part, static_cast<void (KParts::ReadOnlyPart::*)()>(&KParts::ReadOnlyPart::completed), this, &BrowserExtension::slotCompleted);
124  connect(this, &BrowserExtension::openUrlRequest, this, &BrowserExtension::slotOpenUrlRequest);
125  connect(this, &BrowserExtension::enableAction, this, &BrowserExtension::slotEnableAction);
126  connect(this, &BrowserExtension::setActionText, this, &BrowserExtension::slotSetActionText);
127 }
128 
129 BrowserExtension::~BrowserExtension()
130 {
131  // qDebug() << "BrowserExtension::~BrowserExtension() " << this;
132 }
133 
135 {
136  d->m_browserArgs = args;
137 }
138 
140 {
141  return d->m_browserArgs;
142 }
143 
145 {
146  return 0;
147 }
148 
150 {
151  return 0;
152 }
153 
155 {
156  // TODO add d->m_part->mimeType()
157  stream << d->m_part->url() << static_cast<qint32>(xOffset()) << static_cast<qint32>(yOffset());
158 }
159 
161 {
162  QUrl u;
163  qint32 xOfs;
164  qint32 yOfs;
165  stream >> u >> xOfs >> yOfs;
166 
167  OpenUrlArguments args;
168  args.setXOffset(xOfs);
169  args.setYOffset(yOfs);
170  // TODO add args.setMimeType
171  d->m_part->setArguments(args);
172  d->m_part->openUrl(u);
173 }
174 
176 {
177  return d->m_urlDropHandlingEnabled;
178 }
179 
181 {
182  d->m_urlDropHandlingEnabled = enable;
183 }
184 
185 void BrowserExtension::slotCompleted()
186 {
187  // empty the argument stuff, to avoid bogus/invalid values when opening a new url
189 }
190 
192 {
193  QString plain(QStringLiteral("plain"));
195  // Remove linefeeds and any whitespace surrounding it.
196  url.remove(QRegularExpression(QStringLiteral("[\\ ]*\\n+[\\ ]*")));
197 
198  // Check if it's a URL
200  filters.removeAll(QStringLiteral("kuriikwsfilter"));
201  filters.removeAll(QStringLiteral("localdomainurifilter"));
202  KUriFilterData filterData;
203  filterData.setData(url);
204  filterData.setCheckForExecutables(false);
205  if (KUriFilter::self()->filterUri(filterData, filters)) {
206  switch (filterData.uriType()) {
210  slotOpenUrlRequest(filterData.uri());
211  break;
213  KMessageBox::error(d->m_part->widget(), filterData.errorMsg());
214  break;
215  default:
216  break;
217  }
218  } else if (KUriFilter::self()->filterUri(filterData, QStringList(QStringLiteral("kuriikwsfilter"))) && url.length() < 250) {
219  if (KMessageBox::questionYesNo(d->m_part->widget(),
220  i18n("<qt>Do you want to search the Internet for <b>%1</b>?</qt>", url.toHtmlEscaped()),
221  i18n("Internet Search"),
222  KGuiItem(i18n("&Search"), QStringLiteral("edit-find")),
224  QStringLiteral("MiddleClickSearch"))
225  == KMessageBox::Yes) {
226  slotOpenUrlRequest(filterData.uri());
227  }
228  }
229 }
230 
231 void BrowserExtension::slotOpenUrlRequest(const QUrl &url, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs)
232 {
233  // qDebug() << this << " BrowserExtension::slotOpenURLRequest(): url=" << url.url();
234  BrowserExtensionPrivate::DelayedRequest req;
235  req.m_delayedURL = url;
236  req.m_delayedArgs = args;
237  req.m_delayedBrowserArgs = browserArgs;
238  d->m_requests.append(req);
239  QTimer::singleShot(0, this, &BrowserExtension::slotEmitOpenUrlRequestDelayed);
240 }
241 
242 void BrowserExtension::slotEmitOpenUrlRequestDelayed()
243 {
244  if (d->m_requests.isEmpty()) {
245  return;
246  }
247  BrowserExtensionPrivate::DelayedRequest req = d->m_requests.front();
248  d->m_requests.pop_front();
249  Q_EMIT openUrlRequestDelayed(req.m_delayedURL, req.m_delayedArgs, req.m_delayedBrowserArgs);
250  // tricky: do not do anything here! (no access to member variables, etc.)
251 }
252 
253 void BrowserExtension::setBrowserInterface(BrowserInterface *impl)
254 {
255  d->m_browserInterface = impl;
256 }
257 
258 BrowserInterface *BrowserExtension::browserInterface() const
259 {
260  return d->m_browserInterface;
261 }
262 
263 void BrowserExtension::slotEnableAction(const char *name, bool enabled)
264 {
265  // qDebug() << "BrowserExtension::slotEnableAction " << name << " " << enabled;
266  ActionNumberMap::ConstIterator it = s_actionNumberMap()->constFind(name);
267  if (it != s_actionNumberMap()->constEnd()) {
268  d->m_actionStatus.setBit(it.value(), enabled);
269  // qDebug() << "BrowserExtension::slotEnableAction setting bit " << it.data() << " to " << enabled;
270  } else {
271  qCWarning(KPARTSLOG) << "BrowserExtension::slotEnableAction unknown action " << name;
272  }
273 }
274 
275 bool BrowserExtension::isActionEnabled(const char *name) const
276 {
277  int actionNumber = (*s_actionNumberMap())[name];
278  return d->m_actionStatus[actionNumber];
279 }
280 
281 void BrowserExtension::slotSetActionText(const char *name, const QString &text)
282 {
283  // qDebug() << "BrowserExtension::slotSetActionText " << name << " " << text;
284  ActionNumberMap::ConstIterator it = s_actionNumberMap()->constFind(name);
285  if (it != s_actionNumberMap()->constEnd()) {
286  d->m_actionText[it.value()] = text;
287  } else {
288  qCWarning(KPARTSLOG) << "BrowserExtension::slotSetActionText unknown action " << name;
289  }
290 }
291 
292 QString BrowserExtension::actionText(const char *name) const
293 {
294  int actionNumber = (*s_actionNumberMap())[name];
295  QMap<int, QString>::ConstIterator it = d->m_actionText.constFind(actionNumber);
296  if (it != d->m_actionText.constEnd()) {
297  return *it;
298  }
299  return QString();
300 }
301 
302 #if KPARTS_BUILD_DEPRECATED_SINCE(5, 83)
304 {
305  return *actionSlotMapPtr();
306 }
307 #endif
308 
310 {
311  if (s_actionSlotMap()->isEmpty()) {
312  BrowserExtensionPrivate::createActionSlotMap();
313  }
314  return s_actionSlotMap();
315 }
316 
318 {
320 }
virtual void restoreState(QDataStream &stream)
Used by the browser to restore the view in the state it was when we left it.
virtual void saveState(QDataStream &stream)
Used by the browser to save the current state of the view (in order to restore it if going back in na...
QString errorMsg() const
void setURLDropHandlingEnabled(bool enable)
Enables or disables url drop handling.
QAction * print(const QObject *recvr, const char *slot, QObject *parent)
QString toHtmlEscaped() const const
Q_EMITQ_EMIT
bool isURLDropHandlingEnabled() const
Returns whether url drop handling is enabled.
int removeAll(const T &value)
void openUrlRequestDelayed(const QUrl &url, const KParts::OpenUrlArguments &arguments, const KParts::BrowserArguments &browserArguments)
This signal is emitted when openUrlRequest() is called, after a 0-seconds timer.
BrowserArguments is a set of web-browsing-specific arguments, which allow specifying how a URL should...
static KUriFilter * self()
QString trimmed() const const
void pasteRequest()
Asks the hosting browser to perform a paste (using openUrlRequestDelayed())
UriTypes uriType() const
void setData(const QString &url)
void setActionText(const char *name, const QString &text)
Change the text of a standard action held by the browser.
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
Q_GLOBAL_STATIC(Internal::StaticControl, s_instance) class ControlPrivate
QAction * paste(const QObject *recvr, const char *slot, QObject *parent)
void enableAction(const char *name, bool enabled)
Enables or disable a standard action held by the browser.
KGuiItem cancel()
QClipboard * clipboard()
QStringList pluginNames() const
QAction * copy(const QObject *recvr, const char *slot, QObject *parent)
QString i18n(const char *text, const TYPE &arg...)
QUrl uri() const
virtual void setBrowserArguments(const BrowserArguments &args)
Set the parameters to use for opening the next URL.
FindDirectChildrenOnly
int length() const const
static BrowserExtension * childObject(QObject *obj)
Queries obj for a child object which inherits from this BrowserExtension class.
QString text(QClipboard::Mode mode) const const
The Browser Extension is an extension (yes, no kidding) to KParts::ReadOnlyPart, which allows a bette...
static ActionSlotMap actionSlotMap()
Returns a map containing the action names as keys and corresponding SLOT()'ified method names as data...
int indexOfMethod(const char *method) const const
void completed()
Emit this when you have completed loading data.
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
virtual const QMetaObject * metaObject() const const
QString actionText(const char *name) const
QString & remove(int position, int n)
T findChild(const QString &name, Qt::FindChildOptions options) const const
static ActionSlotMap * actionSlotMapPtr()
virtual int yOffset()
Returns the current y offset.
BrowserArguments browserArguments() const
Retrieve the set of parameters to use for opening the URL (this must be called from openUrl() in the ...
void openUrlRequest(const QUrl &url, const KParts::OpenUrlArguments &arguments=KParts::OpenUrlArguments(), const KParts::BrowserArguments &browserArguments=KParts::BrowserArguments())
Asks the host (browser) to open url.
The purpose of this interface is to allow a direct communication between a KPart and the hosting brow...
void setCheckForExecutables(bool check)
const char * constData() const const
const char * name(StandardAction id)
BrowserExtension(KParts::ReadOnlyPart *parent)
Constructor.
typedef ConstIterator
Base class for any "viewer" part.
Definition: readonlypart.h:51
ButtonCode questionYesNo(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonYes=KStandardGuiItem::yes(), const KGuiItem &buttonNo=KStandardGuiItem::no(), const QString &dontAskAgainName=QString(), Options options=Notify)
OpenUrlArguments is the set of arguments that specify how a URL should be opened by KParts::ReadOnlyP...
virtual int xOffset()
Returns the current x offset.
bool isActionEnabled(const char *name) const
QAction * cut(const QObject *recvr, const char *slot, QObject *parent)
The KParts namespace,.
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Fri Aug 12 2022 03:47:30 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.