File indexing completed on 2024-04-28 15:29:19
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 1999 Simon Hausmann <hausmann@kde.org> 0004 SPDX-FileCopyrightText: 1999 David Faure <faure@kde.org> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "browserextension.h" 0010 0011 #include "kparts_logging.h" 0012 0013 #include <KLocalizedString> 0014 #include <KMessageBox> 0015 #include <KUriFilter> 0016 0017 #include <QApplication> 0018 #include <QClipboard> 0019 #include <QMap> 0020 #include <QRegularExpression> 0021 #include <QTimer> 0022 0023 using namespace KParts; 0024 0025 namespace KParts 0026 { 0027 // Internal class, use to store the status of the actions 0028 class KBitArray 0029 { 0030 public: 0031 int val = 0; 0032 bool operator[](int index) 0033 { 0034 return (val & (1 << index)) ? true : false; 0035 } 0036 void setBit(int index, bool value) 0037 { 0038 if (value) { 0039 val = val | (1 << index); 0040 } else { 0041 val = val & ~(1 << index); 0042 } 0043 } 0044 }; 0045 0046 class BrowserExtensionPrivate 0047 { 0048 public: 0049 BrowserExtensionPrivate(KParts::ReadOnlyPart *parent) 0050 : m_urlDropHandlingEnabled(false) 0051 , m_browserInterface(nullptr) 0052 , m_part(parent) 0053 { 0054 } 0055 0056 struct DelayedRequest { 0057 QUrl m_delayedURL; 0058 KParts::OpenUrlArguments m_delayedArgs; 0059 KParts::BrowserArguments m_delayedBrowserArgs; 0060 }; 0061 0062 QList<DelayedRequest> m_requests; 0063 bool m_urlDropHandlingEnabled; 0064 KBitArray m_actionStatus; 0065 QMap<int, QString> m_actionText; 0066 BrowserInterface *m_browserInterface; 0067 0068 static void createActionSlotMap(); 0069 0070 KParts::ReadOnlyPart *m_part; 0071 OpenUrlArguments m_args; 0072 BrowserArguments m_browserArgs; 0073 }; 0074 0075 Q_GLOBAL_STATIC(BrowserExtension::ActionSlotMap, s_actionSlotMap) 0076 Q_GLOBAL_STATIC(BrowserExtension::ActionNumberMap, s_actionNumberMap) 0077 0078 void BrowserExtensionPrivate::createActionSlotMap() 0079 { 0080 s_actionSlotMap()->insert("cut", SLOT(cut())); 0081 s_actionSlotMap()->insert("copy", SLOT(copy())); 0082 s_actionSlotMap()->insert("paste", SLOT(paste())); 0083 s_actionSlotMap()->insert("print", SLOT(print())); 0084 // Tricky. Those aren't actions in fact, but simply methods that a browserextension 0085 // can have or not. No need to return them here. 0086 // s_actionSlotMap()->insert( "reparseConfiguration", SLOT(reparseConfiguration()) ); 0087 // s_actionSlotMap()->insert( "refreshMimeTypes", SLOT(refreshMimeTypes()) ); 0088 0089 // Create the action-number map 0090 BrowserExtension::ActionSlotMap::ConstIterator it = s_actionSlotMap()->constBegin(); 0091 BrowserExtension::ActionSlotMap::ConstIterator itEnd = s_actionSlotMap()->constEnd(); 0092 for (int i = 0; it != itEnd; ++it, ++i) { 0093 // qDebug() << " action " << it.key() << " number " << i; 0094 s_actionNumberMap()->insert(it.key(), i); 0095 } 0096 } 0097 0098 } 0099 0100 BrowserExtension::BrowserExtension(KParts::ReadOnlyPart *parent) 0101 : QObject(parent) 0102 , d(new BrowserExtensionPrivate(parent)) 0103 { 0104 // qDebug() << "BrowserExtension::BrowserExtension() " << this; 0105 0106 if (s_actionSlotMap()->isEmpty()) 0107 // Create the action-slot map 0108 { 0109 BrowserExtensionPrivate::createActionSlotMap(); 0110 } 0111 0112 // Set the initial status of the actions depending on whether 0113 // they're supported or not 0114 const QMetaObject *metaobj = metaObject(); 0115 ActionSlotMap::ConstIterator it = s_actionSlotMap()->constBegin(); 0116 ActionSlotMap::ConstIterator itEnd = s_actionSlotMap()->constEnd(); 0117 for (int i = 0; it != itEnd; ++it, ++i) { 0118 // Does the extension have a slot with the name of this action ? 0119 QByteArray slotSig = it.key() + "()"; 0120 d->m_actionStatus.setBit(i, metaobj->indexOfMethod(slotSig.constData()) != -1); 0121 } 0122 0123 connect(d->m_part, static_cast<void (KParts::ReadOnlyPart::*)()>(&KParts::ReadOnlyPart::completed), this, &BrowserExtension::slotCompleted); 0124 connect(this, &BrowserExtension::openUrlRequest, this, &BrowserExtension::slotOpenUrlRequest); 0125 connect(this, &BrowserExtension::enableAction, this, &BrowserExtension::slotEnableAction); 0126 connect(this, &BrowserExtension::setActionText, this, &BrowserExtension::slotSetActionText); 0127 } 0128 0129 BrowserExtension::~BrowserExtension() 0130 { 0131 // qDebug() << "BrowserExtension::~BrowserExtension() " << this; 0132 } 0133 0134 void BrowserExtension::setBrowserArguments(const BrowserArguments &args) 0135 { 0136 d->m_browserArgs = args; 0137 } 0138 0139 BrowserArguments BrowserExtension::browserArguments() const 0140 { 0141 return d->m_browserArgs; 0142 } 0143 0144 int BrowserExtension::xOffset() 0145 { 0146 return 0; 0147 } 0148 0149 int BrowserExtension::yOffset() 0150 { 0151 return 0; 0152 } 0153 0154 void BrowserExtension::saveState(QDataStream &stream) 0155 { 0156 // TODO add d->m_part->mimeType() 0157 stream << d->m_part->url() << static_cast<qint32>(xOffset()) << static_cast<qint32>(yOffset()); 0158 } 0159 0160 void BrowserExtension::restoreState(QDataStream &stream) 0161 { 0162 QUrl u; 0163 qint32 xOfs; 0164 qint32 yOfs; 0165 stream >> u >> xOfs >> yOfs; 0166 0167 OpenUrlArguments args; 0168 args.setXOffset(xOfs); 0169 args.setYOffset(yOfs); 0170 // TODO add args.setMimeType 0171 d->m_part->setArguments(args); 0172 d->m_part->openUrl(u); 0173 } 0174 0175 bool BrowserExtension::isURLDropHandlingEnabled() const 0176 { 0177 return d->m_urlDropHandlingEnabled; 0178 } 0179 0180 void BrowserExtension::setURLDropHandlingEnabled(bool enable) 0181 { 0182 d->m_urlDropHandlingEnabled = enable; 0183 } 0184 0185 void BrowserExtension::slotCompleted() 0186 { 0187 // empty the argument stuff, to avoid bogus/invalid values when opening a new url 0188 setBrowserArguments(BrowserArguments()); 0189 } 0190 0191 void BrowserExtension::pasteRequest() 0192 { 0193 QString plain(QStringLiteral("plain")); 0194 QString url = QApplication::clipboard()->text(plain, QClipboard::Selection).trimmed(); 0195 // Remove linefeeds and any whitespace surrounding it. 0196 url.remove(QRegularExpression(QStringLiteral("[\\ ]*\\n+[\\ ]*"))); 0197 0198 // Check if it's a URL 0199 QStringList filters = KUriFilter::self()->pluginNames(); 0200 filters.removeAll(QStringLiteral("kuriikwsfilter")); 0201 filters.removeAll(QStringLiteral("localdomainurifilter")); 0202 KUriFilterData filterData; 0203 filterData.setData(url); 0204 filterData.setCheckForExecutables(false); 0205 if (KUriFilter::self()->filterUri(filterData, filters)) { 0206 switch (filterData.uriType()) { 0207 case KUriFilterData::LocalFile: 0208 case KUriFilterData::LocalDir: 0209 case KUriFilterData::NetProtocol: 0210 slotOpenUrlRequest(filterData.uri()); 0211 break; 0212 case KUriFilterData::Error: 0213 KMessageBox::error(d->m_part->widget(), filterData.errorMsg()); 0214 break; 0215 default: 0216 break; 0217 } 0218 } else if (KUriFilter::self()->filterUri(filterData, QStringList(QStringLiteral("kuriikwsfilter"))) && url.length() < 250) { 0219 if (KMessageBox::questionTwoActions(d->m_part->widget(), 0220 i18n("<qt>Do you want to search the Internet for <b>%1</b>?</qt>", url.toHtmlEscaped()), 0221 i18n("Internet Search"), 0222 KGuiItem(i18n("&Search"), QStringLiteral("edit-find")), 0223 KStandardGuiItem::cancel(), 0224 QStringLiteral("MiddleClickSearch")) 0225 == KMessageBox::PrimaryAction) { 0226 slotOpenUrlRequest(filterData.uri()); 0227 } 0228 } 0229 } 0230 0231 void BrowserExtension::slotOpenUrlRequest(const QUrl &url, const KParts::OpenUrlArguments &args, const KParts::BrowserArguments &browserArgs) 0232 { 0233 // qDebug() << this << " BrowserExtension::slotOpenURLRequest(): url=" << url.url(); 0234 BrowserExtensionPrivate::DelayedRequest req; 0235 req.m_delayedURL = url; 0236 req.m_delayedArgs = args; 0237 req.m_delayedBrowserArgs = browserArgs; 0238 d->m_requests.append(req); 0239 QTimer::singleShot(0, this, &BrowserExtension::slotEmitOpenUrlRequestDelayed); 0240 } 0241 0242 void BrowserExtension::slotEmitOpenUrlRequestDelayed() 0243 { 0244 if (d->m_requests.isEmpty()) { 0245 return; 0246 } 0247 BrowserExtensionPrivate::DelayedRequest req = d->m_requests.front(); 0248 d->m_requests.pop_front(); 0249 Q_EMIT openUrlRequestDelayed(req.m_delayedURL, req.m_delayedArgs, req.m_delayedBrowserArgs); 0250 // tricky: do not do anything here! (no access to member variables, etc.) 0251 } 0252 0253 void BrowserExtension::setBrowserInterface(BrowserInterface *impl) 0254 { 0255 d->m_browserInterface = impl; 0256 } 0257 0258 BrowserInterface *BrowserExtension::browserInterface() const 0259 { 0260 return d->m_browserInterface; 0261 } 0262 0263 void BrowserExtension::slotEnableAction(const char *name, bool enabled) 0264 { 0265 // qDebug() << "BrowserExtension::slotEnableAction " << name << " " << enabled; 0266 ActionNumberMap::ConstIterator it = s_actionNumberMap()->constFind(name); 0267 if (it != s_actionNumberMap()->constEnd()) { 0268 d->m_actionStatus.setBit(it.value(), enabled); 0269 // qDebug() << "BrowserExtension::slotEnableAction setting bit " << it.data() << " to " << enabled; 0270 } else { 0271 qCWarning(KPARTSLOG) << "BrowserExtension::slotEnableAction unknown action " << name; 0272 } 0273 } 0274 0275 bool BrowserExtension::isActionEnabled(const char *name) const 0276 { 0277 int actionNumber = (*s_actionNumberMap())[name]; 0278 return d->m_actionStatus[actionNumber]; 0279 } 0280 0281 void BrowserExtension::slotSetActionText(const char *name, const QString &text) 0282 { 0283 // qDebug() << "BrowserExtension::slotSetActionText " << name << " " << text; 0284 ActionNumberMap::ConstIterator it = s_actionNumberMap()->constFind(name); 0285 if (it != s_actionNumberMap()->constEnd()) { 0286 d->m_actionText[it.value()] = text; 0287 } else { 0288 qCWarning(KPARTSLOG) << "BrowserExtension::slotSetActionText unknown action " << name; 0289 } 0290 } 0291 0292 QString BrowserExtension::actionText(const char *name) const 0293 { 0294 int actionNumber = (*s_actionNumberMap())[name]; 0295 QMap<int, QString>::ConstIterator it = d->m_actionText.constFind(actionNumber); 0296 if (it != d->m_actionText.constEnd()) { 0297 return *it; 0298 } 0299 return QString(); 0300 } 0301 0302 #if KPARTS_BUILD_DEPRECATED_SINCE(5, 83) 0303 BrowserExtension::ActionSlotMap BrowserExtension::actionSlotMap() 0304 { 0305 return *actionSlotMapPtr(); 0306 } 0307 #endif 0308 0309 BrowserExtension::ActionSlotMap *BrowserExtension::actionSlotMapPtr() 0310 { 0311 if (s_actionSlotMap()->isEmpty()) { 0312 BrowserExtensionPrivate::createActionSlotMap(); 0313 } 0314 return s_actionSlotMap(); 0315 } 0316 0317 BrowserExtension *BrowserExtension::childObject(QObject *obj) 0318 { 0319 return obj->findChild<KParts::BrowserExtension *>(QString(), Qt::FindDirectChildrenOnly); 0320 } 0321 0322 #include "moc_browserextension.cpp"