File indexing completed on 2024-05-12 07:51:58
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 "navigationextension.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 NavigationExtensionPrivate 0047 { 0048 public: 0049 NavigationExtensionPrivate(KParts::ReadOnlyPart *parent) 0050 : m_urlDropHandlingEnabled(false) 0051 , m_part(parent) 0052 { 0053 } 0054 0055 struct DelayedRequest { 0056 QUrl m_delayedURL; 0057 KParts::OpenUrlArguments m_delayedArgs; 0058 }; 0059 0060 QList<DelayedRequest> m_requests; 0061 bool m_urlDropHandlingEnabled; 0062 KBitArray m_actionStatus; 0063 QMap<int, QString> m_actionText; 0064 0065 static void createActionSlotMap(); 0066 0067 KParts::ReadOnlyPart *m_part; 0068 }; 0069 0070 Q_GLOBAL_STATIC(NavigationExtension::ActionSlotMap, s_actionSlotMap) 0071 Q_GLOBAL_STATIC(NavigationExtension::ActionNumberMap, s_actionNumberMap) 0072 0073 void NavigationExtensionPrivate::createActionSlotMap() 0074 { 0075 s_actionSlotMap()->insert("cut", SLOT(cut())); 0076 s_actionSlotMap()->insert("copy", SLOT(copy())); 0077 s_actionSlotMap()->insert("paste", SLOT(paste())); 0078 s_actionSlotMap()->insert("print", SLOT(print())); 0079 // Tricky. Those aren't actions in fact, but simply methods that a browserextension 0080 // can have or not. No need to return them here. 0081 // s_actionSlotMap()->insert( "reparseConfiguration", SLOT(reparseConfiguration()) ); 0082 // s_actionSlotMap()->insert( "refreshMimeTypes", SLOT(refreshMimeTypes()) ); 0083 0084 // Create the action-number map 0085 NavigationExtension::ActionSlotMap::ConstIterator it = s_actionSlotMap()->constBegin(); 0086 NavigationExtension::ActionSlotMap::ConstIterator itEnd = s_actionSlotMap()->constEnd(); 0087 for (int i = 0; it != itEnd; ++it, ++i) { 0088 // qDebug() << " action " << it.key() << " number " << i; 0089 s_actionNumberMap()->insert(it.key(), i); 0090 } 0091 } 0092 0093 } 0094 0095 NavigationExtension::NavigationExtension(KParts::ReadOnlyPart *parent) 0096 : QObject(parent) 0097 , d(new NavigationExtensionPrivate(parent)) 0098 { 0099 if (s_actionSlotMap()->isEmpty()) 0100 // Create the action-slot map 0101 { 0102 NavigationExtensionPrivate::createActionSlotMap(); 0103 } 0104 0105 // Set the initial status of the actions depending on whether 0106 // they're supported or not 0107 const QMetaObject *metaobj = metaObject(); 0108 ActionSlotMap::ConstIterator it = s_actionSlotMap()->constBegin(); 0109 ActionSlotMap::ConstIterator itEnd = s_actionSlotMap()->constEnd(); 0110 for (int i = 0; it != itEnd; ++it, ++i) { 0111 // Does the extension have a slot with the name of this action ? 0112 QByteArray slotSig = it.key() + "()"; 0113 d->m_actionStatus.setBit(i, metaobj->indexOfMethod(slotSig.constData()) != -1); 0114 } 0115 0116 connect(this, &NavigationExtension::openUrlRequest, this, &NavigationExtension::slotOpenUrlRequest); 0117 connect(this, &NavigationExtension::enableAction, this, &NavigationExtension::slotEnableAction); 0118 connect(this, &NavigationExtension::setActionText, this, &NavigationExtension::slotSetActionText); 0119 } 0120 0121 NavigationExtension::~NavigationExtension() 0122 { 0123 // qDebug() << "BrowserExtension::~BrowserExtension() " << this; 0124 } 0125 0126 int NavigationExtension::xOffset() 0127 { 0128 return 0; 0129 } 0130 0131 int NavigationExtension::yOffset() 0132 { 0133 return 0; 0134 } 0135 0136 void NavigationExtension::saveState(QDataStream &stream) 0137 { 0138 // TODO add d->m_part->mimeType() 0139 stream << d->m_part->url() << static_cast<qint32>(xOffset()) << static_cast<qint32>(yOffset()); 0140 } 0141 0142 void NavigationExtension::restoreState(QDataStream &stream) 0143 { 0144 QUrl u; 0145 qint32 xOfs; 0146 qint32 yOfs; 0147 stream >> u >> xOfs >> yOfs; 0148 0149 OpenUrlArguments args; 0150 args.setXOffset(xOfs); 0151 args.setYOffset(yOfs); 0152 // TODO add args.setMimeType 0153 d->m_part->setArguments(args); 0154 d->m_part->openUrl(u); 0155 } 0156 0157 bool NavigationExtension::isURLDropHandlingEnabled() const 0158 { 0159 return d->m_urlDropHandlingEnabled; 0160 } 0161 0162 void NavigationExtension::setURLDropHandlingEnabled(bool enable) 0163 { 0164 d->m_urlDropHandlingEnabled = enable; 0165 } 0166 0167 void NavigationExtension::pasteRequest() 0168 { 0169 QString plain(QStringLiteral("plain")); 0170 QString url = QApplication::clipboard()->text(plain, QClipboard::Selection).trimmed(); 0171 // Remove linefeeds and any whitespace surrounding it. 0172 url.remove(QRegularExpression(QStringLiteral("[\\ ]*\\n+[\\ ]*"))); 0173 0174 // Check if it's a URL 0175 QStringList filters = KUriFilter::self()->pluginNames(); 0176 filters.removeAll(QStringLiteral("kuriikwsfilter")); 0177 filters.removeAll(QStringLiteral("localdomainurifilter")); 0178 KUriFilterData filterData; 0179 filterData.setData(url); 0180 filterData.setCheckForExecutables(false); 0181 if (KUriFilter::self()->filterUri(filterData, filters)) { 0182 switch (filterData.uriType()) { 0183 case KUriFilterData::LocalFile: 0184 case KUriFilterData::LocalDir: 0185 case KUriFilterData::NetProtocol: 0186 slotOpenUrlRequest(filterData.uri()); 0187 break; 0188 case KUriFilterData::Error: 0189 KMessageBox::error(d->m_part->widget(), filterData.errorMsg()); 0190 break; 0191 default: 0192 break; 0193 } 0194 } else if (KUriFilter::self()->filterUri(filterData, QStringList(QStringLiteral("kuriikwsfilter"))) && url.length() < 250) { 0195 if (KMessageBox::questionTwoActions(d->m_part->widget(), 0196 i18n("<qt>Do you want to search the Internet for <b>%1</b>?</qt>", url.toHtmlEscaped()), 0197 i18n("Internet Search"), 0198 KGuiItem(i18n("&Search"), QStringLiteral("edit-find")), 0199 KStandardGuiItem::cancel(), 0200 QStringLiteral("MiddleClickSearch")) 0201 == KMessageBox::PrimaryAction) { 0202 slotOpenUrlRequest(filterData.uri()); 0203 } 0204 } 0205 } 0206 0207 void NavigationExtension::slotOpenUrlRequest(const QUrl &url, const KParts::OpenUrlArguments &args) 0208 { 0209 // qDebug() << this << " BrowserExtension::slotOpenURLRequest(): url=" << url.url(); 0210 NavigationExtensionPrivate::DelayedRequest req; 0211 req.m_delayedURL = url; 0212 req.m_delayedArgs = args; 0213 d->m_requests.append(req); 0214 QTimer::singleShot(0, this, &NavigationExtension::slotEmitOpenUrlRequestDelayed); 0215 } 0216 0217 void NavigationExtension::slotEmitOpenUrlRequestDelayed() 0218 { 0219 if (d->m_requests.isEmpty()) { 0220 return; 0221 } 0222 NavigationExtensionPrivate::DelayedRequest req = d->m_requests.front(); 0223 d->m_requests.pop_front(); 0224 Q_EMIT openUrlRequestDelayed(req.m_delayedURL, req.m_delayedArgs); 0225 // tricky: do not do anything here! (no access to member variables, etc.) 0226 } 0227 0228 void NavigationExtension::slotEnableAction(const char *name, bool enabled) 0229 { 0230 // qDebug() << "BrowserExtension::slotEnableAction " << name << " " << enabled; 0231 ActionNumberMap::ConstIterator it = s_actionNumberMap()->constFind(name); 0232 if (it != s_actionNumberMap()->constEnd()) { 0233 d->m_actionStatus.setBit(it.value(), enabled); 0234 // qDebug() << "BrowserExtension::slotEnableAction setting bit " << it.data() << " to " << enabled; 0235 } else { 0236 qCWarning(KPARTSLOG) << "BrowserExtension::slotEnableAction unknown action " << name; 0237 } 0238 } 0239 0240 bool NavigationExtension::isActionEnabled(const char *name) const 0241 { 0242 int actionNumber = (*s_actionNumberMap())[name]; 0243 return d->m_actionStatus[actionNumber]; 0244 } 0245 0246 void NavigationExtension::slotSetActionText(const char *name, const QString &text) 0247 { 0248 // qDebug() << "BrowserExtension::slotSetActionText " << name << " " << text; 0249 ActionNumberMap::ConstIterator it = s_actionNumberMap()->constFind(name); 0250 if (it != s_actionNumberMap()->constEnd()) { 0251 d->m_actionText[it.value()] = text; 0252 } else { 0253 qCWarning(KPARTSLOG) << "BrowserExtension::slotSetActionText unknown action " << name; 0254 } 0255 } 0256 0257 QString NavigationExtension::actionText(const char *name) const 0258 { 0259 int actionNumber = (*s_actionNumberMap())[name]; 0260 QMap<int, QString>::ConstIterator it = d->m_actionText.constFind(actionNumber); 0261 if (it != d->m_actionText.constEnd()) { 0262 return *it; 0263 } 0264 return QString(); 0265 } 0266 0267 NavigationExtension::ActionSlotMap *NavigationExtension::actionSlotMap() 0268 { 0269 if (s_actionSlotMap()->isEmpty()) { 0270 NavigationExtensionPrivate::createActionSlotMap(); 0271 } 0272 return s_actionSlotMap(); 0273 } 0274 0275 NavigationExtension *NavigationExtension::childObject(QObject *obj) 0276 { 0277 return obj->findChild<KParts::NavigationExtension *>(QString(), Qt::FindDirectChildrenOnly); 0278 } 0279 0280 #include "moc_navigationextension.cpp"