File indexing completed on 2024-04-14 04:52:53
0001 /* This file is part of the KDE project 0002 0003 Copyright (C) 2002 Patrick Charbonnier <pch@valleeurpe.net> 0004 Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org> 0005 Copyright (C) 2007 Urs Wolfer <uwolfer @ kde.org> 0006 Copyright (C) 2010 Dawit Alemayehu <adawit@kde.org> 0007 Copyright (C) 2010 Matthias Fuchs <mat69@gmx.net> 0008 0009 This program is free software; you can redistribute it and/or 0010 modify it under the terms of the GNU General Public 0011 License as published by the Free Software Foundation; either 0012 version 2 of the License, or (at your option) any later version. 0013 */ 0014 0015 #include "kget_plugin.h" 0016 0017 #include "kget_interface.h" 0018 #include "konq_kpart_plugin.h" 0019 0020 #include <QDBusConnection> 0021 #include <QIcon> 0022 #include <QMenu> 0023 0024 #include <KActionCollection> 0025 #include <KActionMenu> 0026 #include <KDialogJobUiDelegate> 0027 #include <KFileItem> 0028 #include <KIO/CommandLauncherJob> 0029 #include <KIconLoader> 0030 #include <KLocalizedString> 0031 #include <KMessageBox> 0032 #include <KParts/FileInfoExtension> 0033 #include <KParts/Part> 0034 #include <KParts/PartManager> 0035 #include <KParts/ReadOnlyPart> 0036 #include <KPluginFactory> 0037 #include <KProtocolInfo> 0038 #include <KToggleAction> 0039 0040 #include <konq_kpart_plugin.h> 0041 #include <asyncselectorinterface.h> 0042 #include <htmlextension.h> 0043 0044 #define QL1S(x) QLatin1String(x) 0045 0046 K_PLUGIN_CLASS_WITH_JSON(KGetPlugin, "kget_plugin.json") 0047 0048 static QWidget *partWidget(QObject *obj) 0049 { 0050 auto *part = qobject_cast<KParts::ReadOnlyPart *>(obj); 0051 return part ? part->widget() : nullptr; 0052 } 0053 0054 KGetPlugin::KGetPlugin(QObject *parent, const QVariantList &) 0055 : KonqParts::Plugin(parent) 0056 { 0057 auto *menu = new KActionMenu(QIcon::fromTheme("kget"), i18n("Download Manager"), actionCollection()); 0058 actionCollection()->addAction("kget_menu", menu); 0059 0060 menu->setPopupMode(QToolButton::InstantPopup); 0061 connect(menu->menu(), &QMenu::aboutToShow, this, &KGetPlugin::showPopup); 0062 0063 m_dropTargetAction = new KToggleAction(i18n("Show Drop Target"), actionCollection()); 0064 0065 connect(m_dropTargetAction, &QAction::triggered, this, &KGetPlugin::slotShowDrop); 0066 actionCollection()->addAction(QL1S("show_drop"), m_dropTargetAction); 0067 menu->addAction(m_dropTargetAction); 0068 0069 QAction *showLinksAction = actionCollection()->addAction(QL1S("show_links")); 0070 showLinksAction->setText(i18n("List All Links")); 0071 connect(showLinksAction, &QAction::triggered, this, &KGetPlugin::slotShowLinks); 0072 menu->addAction(showLinksAction); 0073 0074 QAction *showSelectedLinksAction = actionCollection()->addAction(QL1S("show_selected_links")); 0075 showSelectedLinksAction->setText(i18n("List Selected Links")); 0076 connect(showSelectedLinksAction, &QAction::triggered, this, &KGetPlugin::slotShowSelectedLinks); 0077 menu->addAction(showSelectedLinksAction); 0078 0079 // Hide this plugin if the parent part does not support either 0080 // The FileInfo or Html extensions... 0081 if (!HtmlExtension::childObject(parent) && !KParts::FileInfoExtension::childObject(parent)) { 0082 menu->setVisible(false); 0083 } 0084 } 0085 0086 KGetPlugin::~KGetPlugin() 0087 { 0088 } 0089 0090 static bool hasDropTarget() 0091 { 0092 bool found = false; 0093 0094 if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kget")) { 0095 OrgKdeKgetMainInterface kgetInterface("org.kde.kget", "/KGet", QDBusConnection::sessionBus()); 0096 QDBusReply<bool> reply = kgetInterface.dropTargetVisible(); 0097 if (reply.isValid()) { 0098 found = reply.value(); 0099 } 0100 } 0101 0102 return found; 0103 } 0104 0105 KGetPlugin::SelectorInterface::SelectorInterface(HtmlExtension* ext) 0106 { 0107 #if QT_VERSION_MAJOR < 6 0108 KParts::SelectorInterface *syncIface = qobject_cast<KParts::SelectorInterface*>(ext); 0109 if (syncIface) { 0110 interfaceType = SelectorInterfaceType::Sync; 0111 syncInterface = syncIface; 0112 } else { 0113 #endif 0114 AsyncSelectorInterface *asyncIface = qobject_cast<AsyncSelectorInterface*>(ext); 0115 if (asyncIface) { 0116 interfaceType = SelectorInterfaceType::Async; 0117 asyncInterface = asyncIface; 0118 } 0119 #if QT_VERSION_MAJOR < 6 0120 } 0121 #endif 0122 } 0123 0124 bool KGetPlugin::SelectorInterface::hasInterface() const 0125 { 0126 #if QT_VERSION_MAJOR < 6 0127 return ((interfaceType == SelectorInterfaceType::Sync && syncInterface) || (interfaceType == SelectorInterfaceType::Async && asyncInterface)); 0128 #else 0129 return interfaceType == SelectorInterfaceType::Async && asyncInterface; 0130 #endif 0131 } 0132 0133 AsyncSelectorInterface::QueryMethods KGetPlugin::SelectorInterface::supportedMethods() const 0134 { 0135 #if QT_VERSION_MAJOR < 6 0136 if (interfaceType == SelectorInterfaceType::Sync) { 0137 auto methods = syncInterface->supportedQueryMethods(); 0138 AsyncSelectorInterface::QueryMethods res; 0139 if (methods & KParts::SelectorInterface::SelectedContent) { 0140 res |= AsyncSelectorInterface::SelectedContent; 0141 } 0142 if (methods & KParts::SelectorInterface::EntireContent) { 0143 res |= AsyncSelectorInterface::EntireContent; 0144 } 0145 return res; 0146 } else { 0147 return asyncInterface->supportedAsyncQueryMethods(); 0148 } 0149 #else 0150 return asyncInterface->supportedAsyncQueryMethods(); 0151 #endif 0152 } 0153 0154 void KGetPlugin::showPopup() 0155 { 0156 // Check for HtmlExtension support... 0157 HtmlExtension *htmlExtn = HtmlExtension::childObject(parent()); 0158 if (htmlExtn) { 0159 SelectorInterface iface(htmlExtn); 0160 AsyncSelectorInterface::QueryMethods methods = iface.supportedMethods(); 0161 m_dropTargetAction->setChecked(hasDropTarget()); 0162 0163 bool enable = (methods & AsyncSelectorInterface::EntireContent); 0164 actionCollection()->action(QL1S("show_links"))->setEnabled(enable); 0165 0166 enable = (htmlExtn->hasSelection() && (methods & AsyncSelectorInterface::SelectedContent)); 0167 actionCollection()->action(QL1S("show_selected_links"))->setEnabled(enable); 0168 0169 enable = (actionCollection()->action(QL1S("show_links"))->isEnabled() || actionCollection()->action(QL1S("show_selected_links"))->isEnabled()); 0170 actionCollection()->action(QL1S("show_drop"))->setEnabled(enable); 0171 0172 return; 0173 } 0174 0175 // Check for FileInfoExtension support... 0176 KParts::FileInfoExtension *fileinfoExtn = KParts::FileInfoExtension::childObject(parent()); 0177 if (fileinfoExtn) { 0178 m_dropTargetAction->setChecked(hasDropTarget()); 0179 const KParts::FileInfoExtension::QueryModes modes = fileinfoExtn->supportedQueryModes(); 0180 bool enable = (modes & KParts::FileInfoExtension::AllItems); 0181 actionCollection()->action(QL1S("show_links"))->setEnabled(enable); 0182 enable = (fileinfoExtn->hasSelection() && (modes & KParts::FileInfoExtension::SelectedItems)); 0183 actionCollection()->action(QL1S("show_selected_links"))->setEnabled(enable); 0184 enable = (actionCollection()->action(QL1S("show_links"))->isEnabled() || actionCollection()->action(QL1S("show_selected_links"))->isEnabled()); 0185 actionCollection()->action(QL1S("show_drop"))->setEnabled(enable); 0186 return; 0187 } 0188 0189 actionCollection()->action(QL1S("show_selected_links"))->setEnabled(false); 0190 actionCollection()->action(QL1S("show_links"))->setEnabled(false); 0191 actionCollection()->action(QL1S("show_drop"))->setEnabled(false); 0192 if (m_dropTargetAction->isChecked()) { 0193 m_dropTargetAction->setChecked(false); 0194 } 0195 } 0196 0197 void KGetPlugin::slotShowDrop() 0198 { 0199 if (!QDBusConnection::sessionBus().interface()->isServiceRegistered("org.kde.kget")) { 0200 const QString command = QStringLiteral("kget --showDropTarget --hideMainWindow"); 0201 auto *job = new KIO::CommandLauncherJob(command); 0202 job->setDesktopName(QStringLiteral("org.kde.kget")); 0203 job->setUiDelegate(new KDialogJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, partWidget(parent()))); 0204 job->start(); 0205 } else { 0206 OrgKdeKgetMainInterface kgetInterface("org.kde.kget", "/KGet", QDBusConnection::sessionBus()); 0207 kgetInterface.setDropTargetVisible(m_dropTargetAction->isChecked()); 0208 } 0209 } 0210 0211 void KGetPlugin::slotShowLinks() 0212 { 0213 getLinks(false); 0214 } 0215 0216 void KGetPlugin::slotShowSelectedLinks() 0217 { 0218 getLinks(true); 0219 } 0220 0221 void KGetPlugin::slotImportLinks() 0222 { 0223 if (m_linkList.isEmpty()) { 0224 KMessageBox::error(partWidget(parent()), i18n("No downloadable links were found."), i18n("No Links")); 0225 return; 0226 } 0227 0228 // Remove any duplicates links from the list... 0229 m_linkList.removeDuplicates(); 0230 0231 OrgKdeKgetMainInterface kgetInterface("org.kde.kget", "/KGet", QDBusConnection::sessionBus()); 0232 kgetInterface.importLinks(m_linkList); 0233 } 0234 0235 void KGetPlugin::fillLinkListFromHtml(const QUrl& baseUrl, const QList<AsyncSelectorInterface::Element >& elements) 0236 { 0237 QString attr; 0238 for (const AsyncSelectorInterface::Element &element : elements) { 0239 if (element.hasAttribute(QL1S("href"))) 0240 attr = QL1S("href"); 0241 else if (element.hasAttribute(QL1S("src"))) 0242 attr = QL1S("src"); 0243 else if (element.hasAttribute(QL1S("data"))) 0244 attr = QL1S("data"); 0245 const QUrl resolvedUrl(baseUrl.resolved(QUrl(element.attribute(attr)))); 0246 // Only select valid and non-local links for download... 0247 if (resolvedUrl.isValid() && !resolvedUrl.isLocalFile() && !resolvedUrl.host().isEmpty()) { 0248 if (element.hasAttribute(QL1S("type"))) 0249 m_linkList << QString(QL1S("url ") + resolvedUrl.url() + QL1S(" type ") + element.attribute(QL1S("type"))); 0250 else 0251 m_linkList << resolvedUrl.url(); 0252 } 0253 } 0254 slotImportLinks(); 0255 } 0256 0257 void KGetPlugin::getLinks(bool selectedOnly) 0258 { 0259 HtmlExtension *htmlExtn = HtmlExtension::childObject(parent()); 0260 if (htmlExtn) { 0261 SelectorInterface iface(htmlExtn); 0262 if (iface.hasInterface()) { 0263 m_linkList.clear(); 0264 const QUrl baseUrl = htmlExtn->baseUrl(); 0265 const QString query = QL1S("a[href], img[src], audio[src], video[src], embed[src], object[data]"); 0266 const AsyncSelectorInterface::QueryMethod method = (selectedOnly ? AsyncSelectorInterface::SelectedContent : AsyncSelectorInterface::EntireContent); 0267 if (iface.interfaceType == SelectorInterfaceType::Sync) { 0268 #if QT_VERSION_MAJOR < 6 0269 const QList<AsyncSelectorInterface::Element> elements = iface.syncInterface->querySelectorAll(query, static_cast<KParts::SelectorInterface::QueryMethod>(method)); 0270 fillLinkListFromHtml(baseUrl, elements); 0271 #endif 0272 } else if (iface.interfaceType == SelectorInterfaceType::Async) { 0273 auto callback = [this, baseUrl](const QList<AsyncSelectorInterface::Element>& elements){ 0274 fillLinkListFromHtml(baseUrl, elements); 0275 }; 0276 iface.asyncInterface->querySelectorAllAsync(query, method, callback); 0277 } 0278 } 0279 } 0280 0281 KParts::FileInfoExtension *fileinfoExtn = KParts::FileInfoExtension::childObject(parent()); 0282 if (fileinfoExtn) { 0283 m_linkList.clear(); 0284 const KParts::FileInfoExtension::QueryMode mode = (selectedOnly ? KParts::FileInfoExtension::SelectedItems : KParts::FileInfoExtension::AllItems); 0285 const KFileItemList items = fileinfoExtn->queryFor(mode); 0286 for (const KFileItem &item: items) { 0287 const QUrl url = item.url(); 0288 // Only select valid and non local links for download... 0289 if (item.isReadable() && item.isFile() && !item.isLocalFile() && !url.host().isEmpty()) { 0290 if (item.mimetype().isEmpty()) 0291 m_linkList << url.url(); 0292 else 0293 m_linkList << QString(QL1S("url ") + url.url() + QL1S(" type ") + item.mimetype()); 0294 } 0295 } 0296 slotImportLinks(); 0297 } 0298 } 0299 0300 #include "kget_plugin.moc"