1 /* This file is part of the KDE project
2  *
3  * Copyright (C) 2000-2003 Simon Hausmann <hausmann@kde.org>
4  *               2001-2003 George Staikos <staikos@kde.org>
5  *               2001-2003 Laurent Montel <montel@kde.org>
6  *               2001-2003 Dirk Mueller <mueller@kde.org>
7  *               2001-2003 Waldo Bastian <bastian@kde.org>
8  *               2001-2003 David Faure <faure@kde.org>
9  *               2001-2003 Daniel Naber <dnaber@kde.org>
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Library General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Library General Public License for more details.
20  *
21  * You should have received a copy of the GNU Library General Public License
22  * along with this library; see the file COPYING.LIB.  If not, write to
23  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA 02110-1301, USA.
25  */
26 
27 #include "khtml_ext.h"
28 #include "khtmlview.h"
29 #include "khtml_pagecache.h"
30 #include "rendering/render_form.h"
31 #include "rendering/render_image.h"
32 #include "html/html_imageimpl.h"
33 #include "misc/loader.h"
34 #include "dom/html_form.h"
35 #include "dom/html_image.h"
36 #include "dom/dom_string.h"
37 #include "dom/html_document.h"
38 #include "dom/dom_element.h"
39 #include "xml/dom_elementimpl.h"
40 #include <QClipboard>
41 #include <QFileInfo>
42 #include <QFileDialog>
43 #include <QMenu>
44 #include <QUrl>
45 #include <QMetaEnum>
46 #include <QMimeData>
47 #include <qstandardpaths.h>
48 #include <qinputdialog.h>
49 #include <assert.h>
50 
51 #include <kconfiggroup.h>
52 #include <ksharedconfig.h>
53 #include "khtml_debug.h"
54 #include <klocalizedstring.h>
55 #include <kjobuidelegate.h>
56 #include <kio/job.h>
57 #include <kshell.h>
58 #include <qsavefile.h>
59 #include <kstringhandler.h>
60 #include <ktoolinvocation.h>
61 #include <kmessagebox.h>
62 #include <krun.h>
63 #include <kurifilter.h>
64 #include <kdesktopfile.h>
65 #include <qtemporaryfile.h>
66 #include "khtml_global.h"
67 #include <kstandardaction.h>
68 #include <kactioncollection.h>
69 #include <kactionmenu.h>
70 
71 #include "khtmlpart_p.h"
72 
KHTMLPartBrowserExtension(KHTMLPart * parent)73 KHTMLPartBrowserExtension::KHTMLPartBrowserExtension(KHTMLPart *parent)
74     : KParts::BrowserExtension(parent)
75 {
76     m_part = parent;
77     setURLDropHandlingEnabled(true);
78 
79     enableAction("cut", false);
80     enableAction("copy", false);
81     enableAction("paste", false);
82 
83     m_connectedToClipboard = false;
84 }
85 
xOffset()86 int KHTMLPartBrowserExtension::xOffset()
87 {
88     return m_part->view()->contentsX();
89 }
90 
yOffset()91 int KHTMLPartBrowserExtension::yOffset()
92 {
93     return m_part->view()->contentsY();
94 }
95 
saveState(QDataStream & stream)96 void KHTMLPartBrowserExtension::saveState(QDataStream &stream)
97 {
98     //qCDebug(KHTML_LOG) << "saveState!";
99     m_part->saveState(stream);
100 }
101 
restoreState(QDataStream & stream)102 void KHTMLPartBrowserExtension::restoreState(QDataStream &stream)
103 {
104     //qCDebug(KHTML_LOG) << "restoreState!";
105     m_part->restoreState(stream);
106 }
107 
editableWidgetFocused(QWidget * widget)108 void KHTMLPartBrowserExtension::editableWidgetFocused(QWidget *widget)
109 {
110     m_editableFormWidget = widget;
111     updateEditActions();
112 
113     if (!m_connectedToClipboard && m_editableFormWidget) {
114         connect(QApplication::clipboard(), SIGNAL(dataChanged()),
115                 this, SLOT(updateEditActions()));
116 
117         if (m_editableFormWidget->inherits("QLineEdit") || m_editableFormWidget->inherits("QTextEdit"))
118             connect(m_editableFormWidget, SIGNAL(selectionChanged()),
119                     this, SLOT(updateEditActions()));
120 
121         m_connectedToClipboard = true;
122     }
123     editableWidgetFocused();
124 }
125 
editableWidgetBlurred(QWidget *)126 void KHTMLPartBrowserExtension::editableWidgetBlurred(QWidget * /*widget*/)
127 {
128     QWidget *oldWidget = m_editableFormWidget;
129 
130     m_editableFormWidget = nullptr;
131     enableAction("cut", false);
132     enableAction("paste", false);
133     m_part->emitSelectionChanged();
134 
135     if (m_connectedToClipboard) {
136         disconnect(QApplication::clipboard(), SIGNAL(dataChanged()),
137                    this, SLOT(updateEditActions()));
138 
139         if (oldWidget) {
140             if (oldWidget->inherits("QLineEdit") || oldWidget->inherits("QTextEdit"))
141                 disconnect(oldWidget, SIGNAL(selectionChanged()),
142                            this, SLOT(updateEditActions()));
143         }
144 
145         m_connectedToClipboard = false;
146     }
147     editableWidgetBlurred();
148 }
149 
setExtensionProxy(KParts::BrowserExtension * proxy)150 void KHTMLPartBrowserExtension::setExtensionProxy(KParts::BrowserExtension *proxy)
151 {
152     if (m_extensionProxy) {
153         disconnect(m_extensionProxy, SIGNAL(enableAction(const char*,bool)),
154                    this, SLOT(extensionProxyActionEnabled(const char*,bool)));
155         if (m_extensionProxy->inherits("KHTMLPartBrowserExtension")) {
156             disconnect(m_extensionProxy, SIGNAL(editableWidgetFocused()),
157                        this, SLOT(extensionProxyEditableWidgetFocused()));
158             disconnect(m_extensionProxy, SIGNAL(editableWidgetBlurred()),
159                        this, SLOT(extensionProxyEditableWidgetBlurred()));
160         }
161     }
162 
163     m_extensionProxy = proxy;
164 
165     if (m_extensionProxy) {
166         connect(m_extensionProxy, SIGNAL(enableAction(const char*,bool)),
167                 this, SLOT(extensionProxyActionEnabled(const char*,bool)));
168         if (m_extensionProxy->inherits("KHTMLPartBrowserExtension")) {
169             connect(m_extensionProxy, SIGNAL(editableWidgetFocused()),
170                     this, SLOT(extensionProxyEditableWidgetFocused()));
171             connect(m_extensionProxy, SIGNAL(editableWidgetBlurred()),
172                     this, SLOT(extensionProxyEditableWidgetBlurred()));
173         }
174 
175         enableAction("cut", m_extensionProxy->isActionEnabled("cut"));
176         enableAction("copy", m_extensionProxy->isActionEnabled("copy"));
177         enableAction("paste", m_extensionProxy->isActionEnabled("paste"));
178     } else {
179         updateEditActions();
180         enableAction("copy", false);   // ### re-check this
181     }
182 }
183 
cut()184 void KHTMLPartBrowserExtension::cut()
185 {
186     if (m_extensionProxy) {
187         callExtensionProxyMethod("cut");
188         return;
189     }
190 
191     if (!m_editableFormWidget) {
192         return;
193     }
194 
195     QLineEdit *lineEdit = qobject_cast<QLineEdit *>(m_editableFormWidget);
196     if (lineEdit && !lineEdit->isReadOnly()) {
197         lineEdit->cut();
198     }
199     QTextEdit *textEdit = qobject_cast<QTextEdit *>(m_editableFormWidget);
200     if (textEdit && !textEdit->isReadOnly()) {
201         textEdit->cut();
202     }
203 }
204 
copy()205 void KHTMLPartBrowserExtension::copy()
206 {
207     if (m_extensionProxy) {
208         callExtensionProxyMethod("copy");
209         return;
210     }
211 
212     if (!m_editableFormWidget) {
213         // get selected text and paste to the clipboard
214         QString text = m_part->selectedText();
215         text.replace(QChar(0xa0), ' ');
216         //qCDebug(KHTML_LOG) << text;
217 
218         QClipboard *cb = QApplication::clipboard();
219         disconnect(cb, SIGNAL(selectionChanged()), m_part, SLOT(slotClearSelection()));
220 #ifndef QT_NO_MIMECLIPBOARD
221         QString htmltext;
222         /*
223          * When selectionModeEnabled, that means the user has just selected
224          * the text, not ctrl+c to copy it.  The selection clipboard
225          * doesn't seem to support mime type, so to save time, don't calculate
226          * the selected text as html.
227          * optomisation disabled for now until everything else works.
228         */
229         //if(!cb->selectionModeEnabled())
230         htmltext = m_part->selectedTextAsHTML();
231         QMimeData *mimeData = new QMimeData;
232         mimeData->setText(text);
233         if (!htmltext.isEmpty()) {
234             htmltext.replace(QChar(0xa0), ' ');
235             mimeData->setHtml(htmltext);
236         }
237         cb->setMimeData(mimeData);
238 #else
239         cb->setText(text);
240 #endif
241 
242         connect(cb, SIGNAL(selectionChanged()), m_part, SLOT(slotClearSelection()));
243     } else {
244         QLineEdit *lineEdit = qobject_cast<QLineEdit *>(m_editableFormWidget);
245         if (lineEdit) {
246             lineEdit->copy();
247         }
248         QTextEdit *textEdit = qobject_cast<QTextEdit *>(m_editableFormWidget);
249         if (textEdit) {
250             textEdit->copy();
251         }
252     }
253 }
254 
searchProvider()255 void KHTMLPartBrowserExtension::searchProvider()
256 {
257     QAction *action = qobject_cast<QAction *>(sender());
258     if (action) {
259         QUrl url = action->data().toUrl();
260         if (url.host().isEmpty()) {
261             KUriFilterData data(action->data().toString());
262             if (KUriFilter::self()->filterSearchUri(data, KUriFilter::WebShortcutFilter)) {
263                 url = data.uri();
264             }
265         }
266 
267         KParts::BrowserArguments browserArgs;
268         browserArgs.frameName = "_blank";
269         emit m_part->browserExtension()->openUrlRequest(url, KParts::OpenUrlArguments(), browserArgs);
270     }
271 }
272 
paste()273 void KHTMLPartBrowserExtension::paste()
274 {
275     if (m_extensionProxy) {
276         callExtensionProxyMethod("paste");
277         return;
278     }
279 
280     if (!m_editableFormWidget) {
281         return;
282     }
283 
284     QLineEdit *lineEdit = qobject_cast<QLineEdit *>(m_editableFormWidget);
285     if (lineEdit && !lineEdit->isReadOnly()) {
286         lineEdit->paste();
287     }
288     QTextEdit *textEdit = qobject_cast<QTextEdit *>(m_editableFormWidget);
289     if (textEdit && !textEdit->isReadOnly()) {
290         textEdit->paste();
291     }
292 }
293 
callExtensionProxyMethod(const char * method)294 void KHTMLPartBrowserExtension::callExtensionProxyMethod(const char *method)
295 {
296     if (!m_extensionProxy) {
297         return;
298     }
299 
300     QMetaObject::invokeMethod(m_extensionProxy, method, Qt::DirectConnection);
301 }
302 
updateEditActions()303 void KHTMLPartBrowserExtension::updateEditActions()
304 {
305     if (!m_editableFormWidget) {
306         enableAction("cut", false);
307         enableAction("copy", false);
308         enableAction("paste", false);
309         return;
310     }
311 
312     // ### duplicated from KonqMainWindow::slotClipboardDataChanged
313 #ifndef QT_NO_MIMECLIPBOARD // Handle minimalized versions of Qt Embedded
314     const QMimeData *data = QApplication::clipboard()->mimeData();
315     enableAction("paste", data->hasText());
316 #else
317     QString data = QApplication::clipboard()->text();
318     enableAction("paste", data.contains("://"));
319 #endif
320     bool hasSelection = false;
321 
322     if (m_editableFormWidget) {
323         if (qobject_cast<QLineEdit *>(m_editableFormWidget)) {
324             hasSelection = static_cast<QLineEdit *>(&(*m_editableFormWidget))->hasSelectedText();
325         } else if (qobject_cast<QTextEdit *>(m_editableFormWidget)) {
326             hasSelection = static_cast<QTextEdit *>(&(*m_editableFormWidget))->textCursor().hasSelection();
327         }
328     }
329 
330     enableAction("copy", hasSelection);
331     enableAction("cut", hasSelection);
332 }
333 
extensionProxyEditableWidgetFocused()334 void KHTMLPartBrowserExtension::extensionProxyEditableWidgetFocused()
335 {
336     editableWidgetFocused();
337 }
338 
extensionProxyEditableWidgetBlurred()339 void KHTMLPartBrowserExtension::extensionProxyEditableWidgetBlurred()
340 {
341     editableWidgetBlurred();
342 }
343 
extensionProxyActionEnabled(const char * action,bool enable)344 void KHTMLPartBrowserExtension::extensionProxyActionEnabled(const char *action, bool enable)
345 {
346     // only forward enableAction calls for actions we actually do forward
347     if (strcmp(action, "cut") == 0 ||
348             strcmp(action, "copy") == 0 ||
349             strcmp(action, "paste") == 0) {
350         enableAction(action, enable);
351     }
352 }
353 
reparseConfiguration()354 void KHTMLPartBrowserExtension::reparseConfiguration()
355 {
356     m_part->reparseConfiguration();
357 }
358 
print()359 void KHTMLPartBrowserExtension::print()
360 {
361     m_part->view()->print();
362 }
363 
disableScrolling()364 void KHTMLPartBrowserExtension::disableScrolling()
365 {
366     QScrollArea *scrollArea = m_part->view();
367     if (scrollArea) {
368         scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
369         scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
370     }
371 }
372 
373 class KHTMLPopupGUIClient::KHTMLPopupGUIClientPrivate
374 {
375 public:
376     KHTMLPart *m_khtml;
377     QUrl m_url;
378     QUrl m_imageURL;
379     QPixmap m_pixmap;
380     QString m_suggestedFilename;
381     KActionCollection *m_actionCollection;
382     KParts::BrowserExtension::ActionGroupMap actionGroups;
383 };
384 
KHTMLPopupGUIClient(KHTMLPart * khtml,const QUrl & url)385 KHTMLPopupGUIClient::KHTMLPopupGUIClient(KHTMLPart *khtml, const QUrl &url)
386     : QObject(khtml), d(new KHTMLPopupGUIClientPrivate)
387 {
388     d->m_khtml = khtml;
389     d->m_url = url;
390     d->m_actionCollection = new KActionCollection(this);
391     bool isImage = false;
392     bool hasSelection = khtml->hasSelection();
393 
394     DOM::Element e = khtml->nodeUnderMouse();
395 
396     if (!e.isNull() && (e.elementId() == ID_IMG ||
397                         (e.elementId() == ID_INPUT && !static_cast<DOM::HTMLInputElement>(e).src().isEmpty()))) {
398         if (e.elementId() == ID_IMG) {
399             DOM::HTMLImageElementImpl *ie = static_cast<DOM::HTMLImageElementImpl *>(e.handle());
400             khtml::RenderImage *ri = dynamic_cast<khtml::RenderImage *>(ie->renderer());
401             if (ri && ri->contentObject()) {
402                 d->m_suggestedFilename = static_cast<khtml::CachedImage *>(ri->contentObject())->suggestedFilename();
403             }
404         }
405         isImage = true;
406     }
407 
408     if (hasSelection) {
409         QList<QAction *> editActions;
410         QAction *copyAction = d->m_actionCollection->addAction(KStandardAction::Copy, "copy",
411                               d->m_khtml->browserExtension(), SLOT(copy()));
412 
413         copyAction->setText(i18n("&Copy Text"));
414         copyAction->setEnabled(d->m_khtml->browserExtension()->isActionEnabled("copy"));
415         editActions.append(copyAction);
416 
417         editActions.append(khtml->actionCollection()->action("selectAll"));
418 
419         addSearchActions(editActions);
420 
421         QString selectedTextURL = selectedTextAsOneLine(d->m_khtml);
422         if (selectedTextURL.contains("://") && QUrl(selectedTextURL).isValid()) {
423             if (selectedTextURL.length() > 18) {
424                 selectedTextURL.truncate(15);
425                 selectedTextURL += "...";
426             }
427             QAction *action = new QAction(i18n("Open '%1'", selectedTextURL), this);
428             d->m_actionCollection->addAction("openSelection", action);
429             action->setIcon(QIcon::fromTheme("window-new"));
430             connect(action, SIGNAL(triggered(bool)), this, SLOT(openSelection()));
431             editActions.append(action);
432         }
433 
434         QAction *separator = new QAction(d->m_actionCollection);
435         separator->setSeparator(true);
436         editActions.append(separator);
437 
438         d->actionGroups.insert("editactions", editActions);
439     }
440 
441     if (!url.isEmpty()) {
442         QList<QAction *> linkActions;
443         if (url.scheme() == "mailto") {
444             QAction *action = new QAction(i18n("&Copy Email Address"), this);
445             d->m_actionCollection->addAction("copylinklocation", action);
446             connect(action, SIGNAL(triggered(bool)), this, SLOT(slotCopyLinkLocation()));
447             linkActions.append(action);
448         } else {
449             QAction *action = new QAction(i18n("&Save Link As..."), this);
450             d->m_actionCollection->addAction("savelinkas", action);
451             connect(action, SIGNAL(triggered(bool)), this, SLOT(slotSaveLinkAs()));
452             linkActions.append(action);
453 
454             action = new QAction(i18n("&Copy Link Address"), this);
455             d->m_actionCollection->addAction("copylinklocation", action);
456             connect(action, SIGNAL(triggered(bool)), this, SLOT(slotCopyLinkLocation()));
457             linkActions.append(action);
458         }
459         d->actionGroups.insert("linkactions", linkActions);
460     }
461 
462     QList<QAction *> partActions;
463     // frameset? -> add "Reload Frame" etc.
464     if (!hasSelection) {
465         if (khtml->parentPart()) {
466             KActionMenu *menu = new KActionMenu(i18nc("@title:menu HTML frame/iframe", "Frame"), this);
467             QAction *action = new QAction(i18n("Open in New &Window"), this);
468             d->m_actionCollection->addAction("frameinwindow", action);
469             action->setIcon(QIcon::fromTheme("window-new"));
470             connect(action, SIGNAL(triggered(bool)), this, SLOT(slotFrameInWindow()));
471             menu->addAction(action);
472 
473             action = new QAction(i18n("Open in &This Window"), this);
474             d->m_actionCollection->addAction("frameintop", action);
475             connect(action, SIGNAL(triggered(bool)), this, SLOT(slotFrameInTop()));
476             menu->addAction(action);
477 
478             action = new QAction(i18n("Open in &New Tab"), this);
479             d->m_actionCollection->addAction("frameintab", action);
480             action->setIcon(QIcon::fromTheme("tab-new"));
481             connect(action, SIGNAL(triggered(bool)), this, SLOT(slotFrameInTab()));
482             menu->addAction(action);
483 
484             action = new QAction(d->m_actionCollection);
485             action->setSeparator(true);
486             menu->addAction(action);
487 
488             action = new QAction(i18n("Reload Frame"), this);
489             d->m_actionCollection->addAction("reloadframe", action);
490             connect(action, SIGNAL(triggered(bool)), this, SLOT(slotReloadFrame()));
491             menu->addAction(action);
492 
493             action = new QAction(i18n("Print Frame..."), this);
494             d->m_actionCollection->addAction("printFrame", action);
495             action->setIcon(QIcon::fromTheme("document-print-frame"));
496             connect(action, SIGNAL(triggered(bool)), d->m_khtml->browserExtension(), SLOT(print()));
497             menu->addAction(action);
498 
499             action = new QAction(i18n("Save &Frame As..."), this);
500             d->m_actionCollection->addAction("saveFrame", action);
501             connect(action, SIGNAL(triggered(bool)), d->m_khtml, SLOT(slotSaveFrame()));
502             menu->addAction(action);
503 
504             action = new QAction(i18n("View Frame Source"), this);
505             d->m_actionCollection->addAction("viewFrameSource", action);
506             connect(action, SIGNAL(triggered(bool)), d->m_khtml, SLOT(slotViewDocumentSource()));
507             menu->addAction(action);
508 
509             action = new QAction(i18n("View Frame Information"), this);
510             d->m_actionCollection->addAction("viewFrameInfo", action);
511             connect(action, SIGNAL(triggered(bool)), d->m_khtml, SLOT(slotViewPageInfo()));
512 
513             action = new QAction(d->m_actionCollection);
514             action->setSeparator(true);
515             menu->addAction(action);
516 
517             if (KHTMLGlobal::defaultHTMLSettings()->isAdFilterEnabled()) {
518                 if (khtml->d->m_frame->m_type == khtml::ChildFrame::IFrame) {
519                     action = new QAction(i18n("Block IFrame..."), this);
520                     d->m_actionCollection->addAction("blockiframe", action);
521                     connect(action, SIGNAL(triggered(bool)), this, SLOT(slotBlockIFrame()));
522                     menu->addAction(action);
523                 }
524             }
525 
526             partActions.append(menu);
527         }
528     }
529 
530     if (isImage) {
531         if (e.elementId() == ID_IMG) {
532             d->m_imageURL = QUrl(static_cast<DOM::HTMLImageElement>(e).src().string());
533             DOM::HTMLImageElementImpl *imageimpl = static_cast<DOM::HTMLImageElementImpl *>(e.handle());
534             Q_ASSERT(imageimpl);
535             if (imageimpl) { // should be true always.  right?
536                 if (imageimpl->complete()) {
537                     d->m_pixmap = imageimpl->currentPixmap();
538                 }
539             }
540         } else {
541             d->m_imageURL = QUrl(static_cast<DOM::HTMLInputElement>(e).src().string());
542         }
543         QAction *action = new QAction(i18n("Save Image As..."), this);
544         d->m_actionCollection->addAction("saveimageas", action);
545         connect(action, SIGNAL(triggered(bool)), this, SLOT(slotSaveImageAs()));
546         partActions.append(action);
547 
548         action = new QAction(i18n("Send Image..."), this);
549         d->m_actionCollection->addAction("sendimage", action);
550         connect(action, SIGNAL(triggered(bool)), this, SLOT(slotSendImage()));
551         partActions.append(action);
552 
553 #ifndef QT_NO_MIMECLIPBOARD
554         action = new QAction(i18n("Copy Image"), this);
555         d->m_actionCollection->addAction("copyimage", action);
556         action->setEnabled(!d->m_pixmap.isNull());
557         connect(action, SIGNAL(triggered(bool)), this, SLOT(slotCopyImage()));
558         partActions.append(action);
559 #endif
560 
561         if (d->m_pixmap.isNull()) {   //fallback to image location if still loading the image.  this will always be true if ifdef QT_NO_MIMECLIPBOARD
562             action = new QAction(i18n("Copy Image Location"), this);
563             d->m_actionCollection->addAction("copyimagelocation", action);
564             connect(action, SIGNAL(triggered(bool)), this, SLOT(slotCopyImageLocation()));
565             partActions.append(action);
566         }
567 
568         QString actionText = d->m_suggestedFilename.isEmpty() ?
569                              KStringHandler::csqueeze(d->m_imageURL.fileName() + d->m_imageURL.query(), 25)
570                              : d->m_suggestedFilename;
571         action = new QAction(i18n("View Image (%1)", actionText.replace("&", "&&")), this);
572         d->m_actionCollection->addAction("viewimage", action);
573         connect(action, SIGNAL(triggered(bool)), this, SLOT(slotViewImage()));
574         partActions.append(action);
575 
576         if (KHTMLGlobal::defaultHTMLSettings()->isAdFilterEnabled()) {
577             action = new QAction(i18n("Block Image..."), this);
578             d->m_actionCollection->addAction("blockimage", action);
579             connect(action, SIGNAL(triggered(bool)), this, SLOT(slotBlockImage()));
580             partActions.append(action);
581 
582             if (!d->m_imageURL.host().isEmpty() &&
583                     !d->m_imageURL.scheme().isEmpty()) {
584                 action = new QAction(i18n("Block Images From %1", d->m_imageURL.host()), this);
585                 d->m_actionCollection->addAction("blockhost", action);
586                 connect(action, SIGNAL(triggered(bool)), this, SLOT(slotBlockHost()));
587                 partActions.append(action);
588             }
589         }
590         QAction *separator = new QAction(d->m_actionCollection);
591         separator->setSeparator(true);
592         partActions.append(separator);
593     }
594 
595     if (isImage || url.isEmpty()) {
596         QAction *action = new QAction(i18n("Stop Animations"), this);
597         d->m_actionCollection->addAction("stopanimations", action);
598         connect(action, SIGNAL(triggered(bool)), this, SLOT(slotStopAnimations()));
599         partActions.append(action);
600         QAction *separator = new QAction(d->m_actionCollection);
601         separator->setSeparator(true);
602         partActions.append(separator);
603     }
604     if (!hasSelection && url.isEmpty()) { // only when right-clicking on the page itself
605         partActions.append(khtml->actionCollection()->action("viewDocumentSource"));
606     }
607     if (!hasSelection && url.isEmpty() && !isImage) {
608         partActions.append(khtml->actionCollection()->action("setEncoding"));
609     }
610     d->actionGroups.insert("partactions", partActions);
611 }
612 
~KHTMLPopupGUIClient()613 KHTMLPopupGUIClient::~KHTMLPopupGUIClient()
614 {
615     delete d->m_actionCollection;
616     delete d;
617 }
618 
addSearchActions(QList<QAction * > & editActions)619 void KHTMLPopupGUIClient::addSearchActions(QList<QAction *> &editActions)
620 {
621     QString selectedText = d->m_khtml->simplifiedSelectedText();
622     // replace linefeeds with spaces
623     selectedText = selectedText.replace(QChar(10), QChar(32)).trimmed();
624 
625     if (selectedText.isEmpty()) {
626         return;
627     }
628 
629     KUriFilterData data(selectedText);
630     QStringList alternateProviders;
631     alternateProviders << "google" << "google_groups" << "google_news" << "webster" << "dmoz" << "wikipedia";
632     data.setAlternateSearchProviders(alternateProviders);
633     data.setAlternateDefaultSearchProvider("google");
634 
635     if (KUriFilter::self()->filterSearchUri(data, KUriFilter::NormalTextFilter)) {
636         const QString squeezedText = KStringHandler::rsqueeze(selectedText, 21);
637         QAction *action = new QAction(i18n("Search for '%1' with %2",
638                                            squeezedText, data.searchProvider()), this);
639         action->setData(QUrl(data.uri()));
640         action->setIcon(QIcon::fromTheme(data.iconName()));
641         connect(action, SIGNAL(triggered(bool)), d->m_khtml->browserExtension(), SLOT(searchProvider()));
642         d->m_actionCollection->addAction("defaultSearchProvider", action);
643         editActions.append(action);
644 
645         const QStringList preferredSearchProviders = data.preferredSearchProviders();
646         if (!preferredSearchProviders.isEmpty()) {
647             KActionMenu *providerList = new KActionMenu(i18n("Search for '%1' with", squeezedText), this);
648             Q_FOREACH (const QString &searchProvider, preferredSearchProviders) {
649                 if (searchProvider == data.searchProvider()) {
650                     continue;
651                 }
652                 QAction *action = new QAction(searchProvider, this);
653                 action->setData(data.queryForPreferredSearchProvider(searchProvider));
654                 d->m_actionCollection->addAction(searchProvider, action);
655                 action->setIcon(QIcon::fromTheme(data.iconNameForPreferredSearchProvider(searchProvider)));
656                 connect(action, SIGNAL(triggered(bool)), d->m_khtml->browserExtension(), SLOT(searchProvider()));
657                 providerList->addAction(action);
658             }
659             d->m_actionCollection->addAction("searchProviderList", providerList);
660             editActions.append(providerList);
661         }
662     }
663 }
664 
selectedTextAsOneLine(KHTMLPart * part)665 QString KHTMLPopupGUIClient::selectedTextAsOneLine(KHTMLPart *part)
666 {
667     QString text = part->simplifiedSelectedText();
668     // in addition to what simplifiedSelectedText does,
669     // remove linefeeds and any whitespace surrounding it (#113177),
670     // to get it all in a single line.
671     text.remove(QRegExp("[\\s]*\\n+[\\s]*"));
672     return text;
673 }
674 
openSelection()675 void KHTMLPopupGUIClient::openSelection()
676 {
677     KParts::BrowserArguments browserArgs;
678     browserArgs.frameName = "_blank";
679 
680     QUrl url(selectedTextAsOneLine(d->m_khtml));
681     emit d->m_khtml->browserExtension()->openUrlRequest(url, KParts::OpenUrlArguments(), browserArgs);
682 }
683 
actionGroups() const684 KParts::BrowserExtension::ActionGroupMap KHTMLPopupGUIClient::actionGroups() const
685 {
686     return d->actionGroups;
687 }
688 
slotSaveLinkAs()689 void KHTMLPopupGUIClient::slotSaveLinkAs()
690 {
691     KIO::MetaData metaData;
692     metaData["referrer"] = d->m_khtml->referrer();
693     saveURL(d->m_khtml->widget(), i18n("Save Link As"), d->m_url, metaData);
694 }
695 
slotSendImage()696 void KHTMLPopupGUIClient::slotSendImage()
697 {
698     QStringList urls;
699     urls.append(d->m_imageURL.url());
700     QString subject = d->m_imageURL.url();
701     KToolInvocation::invokeMailer(QString(), QString(), QString(), subject,
702                                   QString(), //body
703                                   QString(),
704                                   urls); // attachments
705 
706 }
707 
slotSaveImageAs()708 void KHTMLPopupGUIClient::slotSaveImageAs()
709 {
710     KIO::MetaData metaData;
711     metaData["referrer"] = d->m_khtml->referrer();
712     saveURL(d->m_khtml->widget(), i18n("Save Image As"), d->m_imageURL, metaData, QString(), 0, d->m_suggestedFilename);
713 }
714 
slotBlockHost()715 void KHTMLPopupGUIClient::slotBlockHost()
716 {
717     QString name = d->m_imageURL.scheme() + "://" + d->m_imageURL.host() + "/*";
718     KHTMLGlobal::defaultHTMLSettings()->addAdFilter(name);
719     d->m_khtml->reparseConfiguration();
720 }
721 
slotBlockImage()722 void KHTMLPopupGUIClient::slotBlockImage()
723 {
724     bool ok = false;
725 
726     QString url = QInputDialog::getText(d->m_khtml->widget(), i18n("Add URL to Filter"),
727                                         i18n("Enter the URL:"), QLineEdit::Normal,
728                                         d->m_imageURL.url(), &ok);
729     if (ok) {
730         KHTMLGlobal::defaultHTMLSettings()->addAdFilter(url);
731         d->m_khtml->reparseConfiguration();
732     }
733 }
734 
slotBlockIFrame()735 void KHTMLPopupGUIClient::slotBlockIFrame()
736 {
737     bool ok = false;
738     QString url = QInputDialog::getText(d->m_khtml->widget(), i18n("Add URL to Filter"),
739                                         i18n("Enter the URL:"), QLineEdit::Normal,
740                                         d->m_khtml->url().toString(), &ok);
741     if (ok) {
742         KHTMLGlobal::defaultHTMLSettings()->addAdFilter(url);
743         d->m_khtml->reparseConfiguration();
744     }
745 }
746 
slotCopyLinkLocation()747 void KHTMLPopupGUIClient::slotCopyLinkLocation()
748 {
749     QUrl safeURL(d->m_url);
750     safeURL.setPassword(QString());
751 #ifndef QT_NO_MIMECLIPBOARD
752     // Set it in both the mouse selection and in the clipboard
753     QMimeData *mimeData = new QMimeData;
754     mimeData->setUrls(QList<QUrl>() << safeURL);
755     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
756 
757     mimeData = new QMimeData;
758     mimeData->setUrls(QList<QUrl>() << safeURL);
759     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Selection);
760 
761 #else
762     QApplication::clipboard()->setText(safeURL.url());   //FIXME(E): Handle multiple entries
763 #endif
764 }
765 
slotStopAnimations()766 void KHTMLPopupGUIClient::slotStopAnimations()
767 {
768     d->m_khtml->stopAnimations();
769 }
770 
slotCopyImage()771 void KHTMLPopupGUIClient::slotCopyImage()
772 {
773 #ifndef QT_NO_MIMECLIPBOARD
774     QUrl safeURL(d->m_imageURL);
775     safeURL.setPassword(QString());
776 
777     // Set it in both the mouse selection and in the clipboard
778     QMimeData *mimeData = new QMimeData;
779     mimeData->setImageData(d->m_pixmap);
780     mimeData->setUrls(QList<QUrl>() << safeURL);
781     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
782 
783     mimeData = new QMimeData;
784     mimeData->setImageData(d->m_pixmap);
785     mimeData->setUrls(QList<QUrl>() << safeURL);
786     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Selection);
787 #else
788     // qCDebug(KHTML_LOG) << "slotCopyImage called when the clipboard does not support this.  This should not be possible.";
789 #endif
790 }
791 
slotCopyImageLocation()792 void KHTMLPopupGUIClient::slotCopyImageLocation()
793 {
794     QUrl safeURL(d->m_imageURL);
795     safeURL.setPassword(QString());
796 #ifndef QT_NO_MIMECLIPBOARD
797     // Set it in both the mouse selection and in the clipboard
798     QMimeData *mimeData = new QMimeData;
799     mimeData->setUrls(QList<QUrl>() << safeURL);
800     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
801     mimeData = new QMimeData;
802     mimeData->setUrls(QList<QUrl>() << safeURL);
803     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Selection);
804 #else
805     QApplication::clipboard()->setText(safeURL.url());   //FIXME(E): Handle multiple entries
806 #endif
807 }
808 
slotViewImage()809 void KHTMLPopupGUIClient::slotViewImage()
810 {
811     d->m_khtml->browserExtension()->createNewWindow(d->m_imageURL);
812 }
813 
slotReloadFrame()814 void KHTMLPopupGUIClient::slotReloadFrame()
815 {
816     KParts::OpenUrlArguments args = d->m_khtml->arguments();
817     args.setReload(true);
818     args.metaData()["referrer"] = d->m_khtml->pageReferrer();
819     // reload document
820     d->m_khtml->closeUrl();
821     d->m_khtml->setArguments(args);
822     d->m_khtml->openUrl(d->m_khtml->url());
823 }
824 
slotFrameInWindow()825 void KHTMLPopupGUIClient::slotFrameInWindow()
826 {
827     KParts::OpenUrlArguments args = d->m_khtml->arguments();
828     args.metaData()["referrer"] = d->m_khtml->pageReferrer();
829     KParts::BrowserArguments browserArgs(d->m_khtml->browserExtension()->browserArguments());
830     browserArgs.setForcesNewWindow(true);
831     emit d->m_khtml->browserExtension()->createNewWindow(d->m_khtml->url(), args, browserArgs);
832 }
833 
slotFrameInTop()834 void KHTMLPopupGUIClient::slotFrameInTop()
835 {
836     KParts::OpenUrlArguments args = d->m_khtml->arguments();
837     args.metaData()["referrer"] = d->m_khtml->pageReferrer();
838     KParts::BrowserArguments browserArgs(d->m_khtml->browserExtension()->browserArguments());
839     browserArgs.frameName = "_top";
840     emit d->m_khtml->browserExtension()->openUrlRequest(d->m_khtml->url(), args, browserArgs);
841 }
842 
slotFrameInTab()843 void KHTMLPopupGUIClient::slotFrameInTab()
844 {
845     KParts::OpenUrlArguments args = d->m_khtml->arguments();
846     args.metaData()["referrer"] = d->m_khtml->pageReferrer();
847     KParts::BrowserArguments browserArgs(d->m_khtml->browserExtension()->browserArguments());
848     browserArgs.setNewTab(true);
849     emit d->m_khtml->browserExtension()->createNewWindow(d->m_khtml->url(), args, browserArgs);
850 }
851 
saveURL(QWidget * parent,const QString & caption,const QUrl & url,const QMap<QString,QString> & metadata,const QString & filter,long cacheId,const QString & suggestedFilename)852 void KHTMLPopupGUIClient::saveURL(QWidget *parent, const QString &caption,
853                                   const QUrl &url,
854                                   const QMap<QString, QString> &metadata,
855                                   const QString &filter, long cacheId,
856                                   const QString &suggestedFilename)
857 {
858     QString name = QLatin1String("index.html");
859     if (!suggestedFilename.isEmpty()) {
860         name = suggestedFilename;
861     } else if (!url.fileName().isEmpty()) {
862         name = url.fileName();
863     }
864 
865     QUrl destURL;
866     int query;
867     do {
868         query = KMessageBox::Yes;
869         // convert filename to URL using fromLocalFile to avoid trouble with ':' in filenames (#184202)
870         destURL = QFileDialog::getSaveFileUrl(parent, caption, QUrl::fromLocalFile(name), filter);
871         if (destURL.isLocalFile()) {
872             QFileInfo info(destURL.toLocalFile());
873             if (info.exists()) {
874                 // TODO: use KIO::RenameDlg (shows more information)
875                 query = KMessageBox::warningContinueCancel(parent, i18n("A file named \"%1\" already exists. " "Are you sure you want to overwrite it?",  info.fileName()), i18n("Overwrite File?"), KStandardGuiItem::overwrite());
876             }
877         }
878     } while (query == KMessageBox::Cancel);
879 
880     if (destURL.isValid()) {
881         saveURL(parent, url, destURL, metadata, cacheId);
882     }
883 }
884 
saveURL(QWidget * parent,const QUrl & url,const QUrl & destURL,const QMap<QString,QString> & metadata,long cacheId)885 void KHTMLPopupGUIClient::saveURL(QWidget *parent, const QUrl &url, const QUrl &destURL,
886                                   const QMap<QString, QString> &metadata,
887                                   long cacheId)
888 {
889     if (destURL.isValid()) {
890         bool saved = false;
891         if (KHTMLPageCache::self()->isComplete(cacheId)) {
892             if (destURL.isLocalFile()) {
893                 QSaveFile destFile(destURL.toLocalFile());
894                 if (destFile.open(QIODevice::WriteOnly)) {
895                     QDataStream stream(&destFile);
896                     KHTMLPageCache::self()->saveData(cacheId, &stream);
897                     destFile.commit();
898                     saved = true;
899                 }
900             } else {
901                 // save to temp file, then move to final destination.
902                 QTemporaryFile destFile;
903                 if (destFile.open()) {
904                     QDataStream stream(&destFile);
905                     KHTMLPageCache::self()->saveData(cacheId, &stream);
906                     QUrl url2 = QUrl();
907                     url2.setPath(destFile.fileName());
908                     KIO::file_move(url2, destURL, -1, KIO::Overwrite);
909                     saved = true;
910                 }
911             }
912         }
913         if (!saved) {
914             // DownloadManager <-> konqueror integration
915             // find if the integration is enabled
916             // the empty key  means no integration
917             // only use download manager for non-local urls!
918             bool downloadViaKIO = true;
919             if (!url.isLocalFile()) {
920                 KConfigGroup cfg = KSharedConfig::openConfig("konquerorrc", KConfig::NoGlobals)->group("HTML Settings");
921                 QString downloadManger = cfg.readPathEntry("DownloadManager", QString());
922                 if (!downloadManger.isEmpty()) {
923                     // then find the download manager location
924                     // qCDebug(KHTML_LOG) << "Using: "<<downloadManger <<" as Download Manager";
925                     QString cmd = QStandardPaths::findExecutable(downloadManger);
926                     if (cmd.isEmpty()) {
927                         QString errMsg = i18n("The Download Manager (%1) could not be found in your $PATH ", downloadManger);
928                         QString errMsgEx = i18n("Try to reinstall it  \n\nThe integration with Konqueror will be disabled.");
929                         KMessageBox::detailedSorry(nullptr, errMsg, errMsgEx);
930                         cfg.writePathEntry("DownloadManager", QString());
931                         cfg.sync();
932                     } else {
933                         downloadViaKIO = false;
934                         QUrl cleanDest = destURL;
935                         cleanDest.setPassword(QString());   // don't put password into commandline
936                         cmd += ' ' + KShell::quoteArg(url.url()) + ' ' +
937                                KShell::quoteArg(cleanDest.url());
938                         // qCDebug(KHTML_LOG) << "Calling command  "<<cmd;
939                         KRun::runCommand(cmd, parent->topLevelWidget());
940                     }
941                 }
942             }
943 
944             if (downloadViaKIO) {
945                 KParts::BrowserRun::saveUrlUsingKIO(url, destURL, parent, metadata);
946             }
947         } //end if(!saved)
948     }
949 }
950 
KHTMLPartBrowserHostExtension(KHTMLPart * part)951 KHTMLPartBrowserHostExtension::KHTMLPartBrowserHostExtension(KHTMLPart *part)
952     : KParts::BrowserHostExtension(part)
953 {
954     m_part = part;
955 }
956 
~KHTMLPartBrowserHostExtension()957 KHTMLPartBrowserHostExtension::~KHTMLPartBrowserHostExtension()
958 {
959 }
960 
frameNames() const961 QStringList KHTMLPartBrowserHostExtension::frameNames() const
962 {
963     return m_part->frameNames();
964 }
965 
frames() const966 const QList<KParts::ReadOnlyPart *> KHTMLPartBrowserHostExtension::frames() const
967 {
968     return m_part->frames();
969 }
970 
openUrlInFrame(const QUrl & url,const KParts::OpenUrlArguments & arguments,const KParts::BrowserArguments & browserArguments)971 bool KHTMLPartBrowserHostExtension::openUrlInFrame(const QUrl &url, const KParts::OpenUrlArguments &arguments, const KParts::BrowserArguments &browserArguments)
972 {
973     return m_part->openUrlInFrame(url, arguments, browserArguments);
974 }
975 
findFrameParent(KParts::ReadOnlyPart * callingPart,const QString & frame)976 KParts::BrowserHostExtension *KHTMLPartBrowserHostExtension::findFrameParent(KParts::ReadOnlyPart
977         *callingPart, const QString &frame)
978 {
979     KHTMLPart *parentPart = m_part->d->findFrameParent(callingPart, frame, nullptr, true /* navigation*/);
980     if (parentPart) {
981         return parentPart->browserHostExtension();
982     }
983     return nullptr;
984 }
985 
986 // defined in khtml_part.cpp
987 extern const int KHTML_NO_EXPORT fastZoomSizes[];
988 extern const int KHTML_NO_EXPORT fastZoomSizeCount;
989 
KHTMLZoomFactorAction(KHTMLPart * part,bool direction,const QString & icon,const QString & text,QObject * parent)990 KHTMLZoomFactorAction::KHTMLZoomFactorAction(KHTMLPart *part, bool direction, const QString &icon, const QString &text, QObject *parent)
991     : KSelectAction(text, parent)
992 {
993     setIcon(QIcon::fromTheme(icon));
994 
995     setToolBarMode(MenuMode);
996     setToolButtonPopupMode(QToolButton::DelayedPopup);
997 
998     init(part, direction);
999 }
1000 
init(KHTMLPart * part,bool direction)1001 void KHTMLZoomFactorAction::init(KHTMLPart *part, bool direction)
1002 {
1003     m_direction = direction;
1004     m_part = part;
1005 
1006     // xgettext: no-c-format
1007     addAction(i18n("Default Font Size (100%)"));
1008 
1009     int m = m_direction ? 1 : -1;
1010     int ofs = fastZoomSizeCount / 2;       // take index of 100%
1011 
1012     // this only works if there is an odd number of elements in fastZoomSizes[]
1013     for (int i = m; i != m * (ofs + 1); i += m) {
1014         int num = i * m;
1015         QString numStr = QString::number(num);
1016         if (num > 0) {
1017             numStr.prepend(QLatin1Char('+'));
1018         }
1019 
1020         // xgettext: no-c-format
1021         addAction(i18n("%1%",  fastZoomSizes[ofs + i]));
1022     }
1023 
1024     connect(selectableActionGroup(), SIGNAL(triggered(QAction*)), this, SLOT(slotTriggered(QAction*)));
1025 }
1026 
~KHTMLZoomFactorAction()1027 KHTMLZoomFactorAction::~KHTMLZoomFactorAction()
1028 {
1029 }
1030 
slotTriggered(QAction * action)1031 void KHTMLZoomFactorAction::slotTriggered(QAction *action)
1032 {
1033     int idx = selectableActionGroup()->actions().indexOf(action);
1034 
1035     if (idx == 0) {
1036         m_part->setFontScaleFactor(100);
1037     } else {
1038         m_part->setFontScaleFactor(fastZoomSizes[fastZoomSizeCount / 2 + (m_direction ? 1 : -1)*idx]);
1039     }
1040     setCurrentAction(nullptr);
1041 }
1042 
KHTMLTextExtension(KHTMLPart * part)1043 KHTMLTextExtension::KHTMLTextExtension(KHTMLPart *part)
1044     : KParts::TextExtension(part)
1045 {
1046     connect(part, SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged()));
1047 }
1048 
part() const1049 KHTMLPart *KHTMLTextExtension::part() const
1050 {
1051     return static_cast<KHTMLPart *>(parent());
1052 }
1053 
hasSelection() const1054 bool KHTMLTextExtension::hasSelection() const
1055 {
1056     return part()->hasSelection();
1057 }
1058 
selectedText(Format format) const1059 QString KHTMLTextExtension::selectedText(Format format) const
1060 {
1061     switch (format) {
1062     case PlainText:
1063         return part()->selectedText();
1064     case HTML:
1065         return part()->selectedTextAsHTML();
1066     }
1067     return QString();
1068 }
1069 
completeText(Format format) const1070 QString KHTMLTextExtension::completeText(Format format) const
1071 {
1072     switch (format) {
1073     case PlainText:
1074         return part()->htmlDocument().body().innerText().string();
1075     case HTML:
1076         return part()->htmlDocument().body().innerHTML().string();
1077     }
1078     return QString();
1079 }
1080 
1081 ////
1082 
KHTMLHtmlExtension(KHTMLPart * part)1083 KHTMLHtmlExtension::KHTMLHtmlExtension(KHTMLPart *part)
1084     : KParts::HtmlExtension(part)
1085 {
1086 }
1087 
baseUrl() const1088 QUrl KHTMLHtmlExtension::baseUrl() const
1089 {
1090     return part()->baseURL();
1091 }
1092 
hasSelection() const1093 bool KHTMLHtmlExtension::hasSelection() const
1094 {
1095     return part()->hasSelection();
1096 }
1097 
supportedQueryMethods() const1098 KParts::SelectorInterface::QueryMethods KHTMLHtmlExtension::supportedQueryMethods() const
1099 {
1100     return (KParts::SelectorInterface::SelectedContent | KParts::SelectorInterface::EntireContent);
1101 }
1102 
convertDomElement(const DOM::ElementImpl * domElem)1103 static KParts::SelectorInterface::Element convertDomElement(const DOM::ElementImpl *domElem)
1104 {
1105     KParts::SelectorInterface::Element elem;
1106     elem.setTagName(domElem->tagName().string());
1107     const DOM::NamedAttrMapImpl *attrMap = domElem->attributes(true /*readonly*/);
1108     if (attrMap) {
1109         for (unsigned i = 0; i < attrMap->length(); ++i) {
1110             const DOM::AttributeImpl &attr = attrMap->attributeAt(i);
1111             elem.setAttribute(attr.localName().string(), attr.value().string());
1112             // we could have a setAttributeNS too.
1113         }
1114     }
1115     return elem;
1116 }
1117 
querySelector(const QString & query,KParts::SelectorInterface::QueryMethod method) const1118 KParts::SelectorInterface::Element KHTMLHtmlExtension::querySelector(const QString &query, KParts::SelectorInterface::QueryMethod method) const
1119 {
1120     KParts::SelectorInterface::Element element;
1121 
1122     // If the specified method is None, return an empty list; similarly
1123     // if the document is null, which may be possible in case of an error
1124     if (method == KParts::SelectorInterface::None || part()->document().isNull()) {
1125         return element;
1126     }
1127 
1128     if (!(supportedQueryMethods() & method)) {
1129         return element;
1130     }
1131 
1132     switch (method) {
1133     case KParts::SelectorInterface::EntireContent: {
1134         int ec = 0; // exceptions are ignored
1135         WTF::RefPtr<DOM::ElementImpl> domElem = part()->document().handle()->querySelector(query, ec);
1136         element = convertDomElement(domElem.get());
1137         break;
1138     }
1139     case KParts::SelectorInterface::SelectedContent:
1140         if (part()->hasSelection()) {
1141             DOM::Element domElem = part()->selection().cloneContents().querySelector(query);
1142             element = convertDomElement(static_cast<DOM::ElementImpl *>(domElem.handle()));
1143         }
1144         break;
1145     default:
1146         break;
1147     }
1148 
1149     return element;
1150 }
1151 
querySelectorAll(const QString & query,KParts::SelectorInterface::QueryMethod method) const1152 QList<KParts::SelectorInterface::Element> KHTMLHtmlExtension::querySelectorAll(const QString &query, KParts::SelectorInterface::QueryMethod method) const
1153 {
1154     QList<KParts::SelectorInterface::Element> elements;
1155 
1156     // If the specified method is None, return an empty list; similarly
1157     // if the document is null, which may be possible in case of an error
1158     if (method == KParts::SelectorInterface::None || part()->document().isNull()) {
1159         return elements;
1160     }
1161 
1162     // If the specified method is not supported, return an empty list...
1163     if (!(supportedQueryMethods() & method)) {
1164         return elements;
1165     }
1166 
1167     switch (method) {
1168     case KParts::SelectorInterface::EntireContent: {
1169         int ec = 0; // exceptions are ignored
1170         WTF::RefPtr<DOM::NodeListImpl> nodes = part()->document().handle()->querySelectorAll(query, ec);
1171         const unsigned long len = nodes->length();
1172         elements.reserve(len);
1173         for (unsigned long i = 0; i < len; ++i) {
1174             DOM::NodeImpl *node = nodes->item(i);
1175             if (node->isElementNode()) { // should be always true
1176                 elements.append(convertDomElement(static_cast<DOM::ElementImpl *>(node)));
1177             }
1178         }
1179         break;
1180     }
1181     case KParts::SelectorInterface::SelectedContent:
1182         if (part()->hasSelection()) {
1183             DOM::NodeList nodes = part()->selection().cloneContents().querySelectorAll(query);
1184             const unsigned long len = nodes.length();
1185             for (unsigned long i = 0; i < len; ++i) {
1186                 DOM::NodeImpl *node = nodes.item(i).handle();
1187                 if (node->isElementNode()) {
1188                     elements.append(convertDomElement(static_cast<DOM::ElementImpl *>(node)));
1189                 }
1190             }
1191         }
1192         break;
1193     default:
1194         break;
1195     }
1196 
1197     return elements;
1198 }
1199 
htmlSettingsProperty(HtmlSettingsInterface::HtmlSettingsType type) const1200 QVariant KHTMLHtmlExtension::htmlSettingsProperty(HtmlSettingsInterface::HtmlSettingsType type) const
1201 {
1202     if (part()) {
1203         switch (type) {
1204         case KParts::HtmlSettingsInterface::AutoLoadImages:
1205             return part()->autoloadImages();
1206         case KParts::HtmlSettingsInterface::DnsPrefetchEnabled:
1207             return (part()->dnsPrefetch() == KHTMLPart::DNSPrefetchEnabled);
1208         case KParts::HtmlSettingsInterface::JavaEnabled:
1209             return part()->javaEnabled();
1210         case KParts::HtmlSettingsInterface::JavascriptEnabled:
1211             return part()->jScriptEnabled();
1212         case KParts::HtmlSettingsInterface::MetaRefreshEnabled:
1213             return part()->metaRefreshEnabled();
1214         case KParts::HtmlSettingsInterface::PluginsEnabled:
1215             return part()->pluginsEnabled();
1216         default:
1217             break;
1218         }
1219     }
1220     return QVariant();
1221 }
1222 
setHtmlSettingsProperty(HtmlSettingsInterface::HtmlSettingsType type,const QVariant & value)1223 bool KHTMLHtmlExtension::setHtmlSettingsProperty(HtmlSettingsInterface::HtmlSettingsType type, const QVariant &value)
1224 {
1225     KHTMLPart *p = part();
1226 
1227     if (p) {
1228         switch (type) {
1229         case KParts::HtmlSettingsInterface::AutoLoadImages:
1230             p->setAutoloadImages(value.toBool());
1231             return true;
1232         case KParts::HtmlSettingsInterface::DnsPrefetchEnabled:
1233             p->setDNSPrefetch((value.toBool() ? KHTMLPart::DNSPrefetchEnabled : KHTMLPart::DNSPrefetchDisabled));
1234             return true;
1235         case KParts::HtmlSettingsInterface::JavaEnabled:
1236             p->setJavaEnabled(value.toBool());
1237             return true;
1238         case KParts::HtmlSettingsInterface::JavascriptEnabled:
1239             p->setJScriptEnabled(value.toBool());
1240             return true;
1241         case KParts::HtmlSettingsInterface::MetaRefreshEnabled:
1242             p->setMetaRefreshEnabled(value.toBool());
1243             return true;
1244         case KParts::HtmlSettingsInterface::PluginsEnabled:
1245             p->setPluginsEnabled(value.toBool());
1246             return true;
1247         case KParts::HtmlSettingsInterface::UserDefinedStyleSheetURL: {
1248             const QUrl url(value.toUrl());
1249             if (url.scheme() == QLatin1String("data")) {
1250                 const QByteArray data(url.path(QUrl::FullyEncoded).toLatin1());
1251                 if (!data.isEmpty()) {
1252                     const int index = data.indexOf(',');
1253                     const QByteArray decodedData((index > -1 ? QByteArray::fromBase64(data.mid(index)) : QByteArray()));
1254                     p->setUserStyleSheet(QString::fromUtf8(decodedData.constData(), decodedData.size()));
1255                 }
1256             } else {
1257                 p->setUserStyleSheet(url);
1258             }
1259             return true;
1260         }
1261         default:
1262             break; // Unsupported property...
1263         }
1264     }
1265 
1266     return false;
1267 }
1268 
part() const1269 KHTMLPart *KHTMLHtmlExtension::part() const
1270 {
1271     return static_cast<KHTMLPart *>(parent());
1272 }
1273 
1274