fix logic
[personal-kdelibs.git] / khtml / khtml_ext.cpp
blob8e56af9fa41c5971c86ec2d2c88a8af05d42d578
1 /* This file is part of the KDE project
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>
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.
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.
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.
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 <QtGui/QClipboard>
37 #include <QtCore/QFileInfo>
38 #include <QtGui/QMenu>
39 #include <QtCore/QUrl>
40 #include <QtCore/QMetaEnum>
41 #include <assert.h>
43 #include <kdebug.h>
44 #include <klocale.h>
45 #include <kfiledialog.h>
46 #include <kjobuidelegate.h>
47 #include <kio/job.h>
48 #include <kshell.h>
49 #include <ktoolbar.h>
50 #include <ksavefile.h>
51 #include <kstringhandler.h>
52 #include <ktoolinvocation.h>
53 #include <kmessagebox.h>
54 #include <kstandarddirs.h>
55 #include <krun.h>
56 #include <kurifilter.h>
57 #include <kicon.h>
58 #include <kiconloader.h>
59 #include <kdesktopfile.h>
60 #include <kinputdialog.h>
61 #include <ktemporaryfile.h>
62 #include "khtml_global.h"
63 #include <kstandardaction.h>
64 #include <kactioncollection.h>
65 #include <kactionmenu.h>
67 #include "dom/dom_element.h"
68 #include "misc/htmltags.h"
70 #include "khtmlpart_p.h"
72 KHTMLPartBrowserExtension::KHTMLPartBrowserExtension( KHTMLPart *parent )
73 : KParts::BrowserExtension( parent )
75 m_part = parent;
76 setURLDropHandlingEnabled( true );
78 enableAction( "cut", false );
79 enableAction( "copy", false );
80 enableAction( "paste", false );
82 m_connectedToClipboard = false;
85 int KHTMLPartBrowserExtension::xOffset()
87 return m_part->view()->contentsX();
90 int KHTMLPartBrowserExtension::yOffset()
92 return m_part->view()->contentsY();
95 void KHTMLPartBrowserExtension::saveState( QDataStream &stream )
97 //kDebug( 6050 ) << "saveState!";
98 m_part->saveState( stream );
101 void KHTMLPartBrowserExtension::restoreState( QDataStream &stream )
103 //kDebug( 6050 ) << "restoreState!";
104 m_part->restoreState( stream );
107 void KHTMLPartBrowserExtension::editableWidgetFocused( QWidget *widget )
109 m_editableFormWidget = widget;
110 updateEditActions();
112 if ( !m_connectedToClipboard && m_editableFormWidget )
114 connect( QApplication::clipboard(), SIGNAL( dataChanged() ),
115 this, SLOT( updateEditActions() ) );
117 if ( m_editableFormWidget->inherits( "QLineEdit" ) || m_editableFormWidget->inherits( "QTextEdit" ) )
118 connect( m_editableFormWidget, SIGNAL( selectionChanged() ),
119 this, SLOT( updateEditActions() ) );
121 m_connectedToClipboard = true;
123 editableWidgetFocused();
126 void KHTMLPartBrowserExtension::editableWidgetBlurred( QWidget * /*widget*/ )
128 QWidget *oldWidget = m_editableFormWidget;
130 m_editableFormWidget = 0;
131 enableAction( "cut", false );
132 enableAction( "paste", false );
133 m_part->emitSelectionChanged();
135 if ( m_connectedToClipboard )
137 disconnect( QApplication::clipboard(), SIGNAL( dataChanged() ),
138 this, SLOT( updateEditActions() ) );
140 if ( oldWidget )
142 if ( oldWidget->inherits( "QLineEdit" ) || oldWidget->inherits( "QTextEdit" ) )
143 disconnect( oldWidget, SIGNAL( selectionChanged() ),
144 this, SLOT( updateEditActions() ) );
147 m_connectedToClipboard = false;
149 editableWidgetBlurred();
152 void KHTMLPartBrowserExtension::setExtensionProxy( KParts::BrowserExtension *proxy )
154 if ( m_extensionProxy )
156 disconnect( m_extensionProxy, SIGNAL( enableAction( const char *, bool ) ),
157 this, SLOT( extensionProxyActionEnabled( const char *, bool ) ) );
158 if ( m_extensionProxy->inherits( "KHTMLPartBrowserExtension" ) )
160 disconnect( m_extensionProxy, SIGNAL( editableWidgetFocused() ),
161 this, SLOT( extensionProxyEditableWidgetFocused() ) );
162 disconnect( m_extensionProxy, SIGNAL( editableWidgetBlurred() ),
163 this, SLOT( extensionProxyEditableWidgetBlurred() ) );
167 m_extensionProxy = proxy;
169 if ( m_extensionProxy )
171 connect( m_extensionProxy, SIGNAL( enableAction( const char *, bool ) ),
172 this, SLOT( extensionProxyActionEnabled( const char *, bool ) ) );
173 if ( m_extensionProxy->inherits( "KHTMLPartBrowserExtension" ) )
175 connect( m_extensionProxy, SIGNAL( editableWidgetFocused() ),
176 this, SLOT( extensionProxyEditableWidgetFocused() ) );
177 connect( m_extensionProxy, SIGNAL( editableWidgetBlurred() ),
178 this, SLOT( extensionProxyEditableWidgetBlurred() ) );
181 enableAction( "cut", m_extensionProxy->isActionEnabled( "cut" ) );
182 enableAction( "copy", m_extensionProxy->isActionEnabled( "copy" ) );
183 enableAction( "paste", m_extensionProxy->isActionEnabled( "paste" ) );
185 else
187 updateEditActions();
188 enableAction( "copy", false ); // ### re-check this
192 void KHTMLPartBrowserExtension::cut()
194 if ( m_extensionProxy )
196 callExtensionProxyMethod( "cut()" );
197 return;
200 if ( !m_editableFormWidget )
201 return;
203 if ( m_editableFormWidget->inherits( "QLineEdit" ) )
204 static_cast<QLineEdit *>( &(*m_editableFormWidget) )->cut();
205 else if ( m_editableFormWidget->inherits( "QTextEdit" ) )
206 static_cast<QTextEdit *>( &(*m_editableFormWidget) )->cut();
209 void KHTMLPartBrowserExtension::copy()
211 if ( m_extensionProxy )
213 callExtensionProxyMethod( "copy()" );
214 return;
217 kDebug( 6050 ) << "************! KHTMLPartBrowserExtension::copy()";
218 if ( !m_editableFormWidget )
220 // get selected text and paste to the clipboard
221 QString text = m_part->selectedText();
222 text.replace( QChar( 0xa0 ), ' ' );
224 QClipboard *cb = QApplication::clipboard();
225 disconnect( cb, SIGNAL( selectionChanged() ), m_part, SLOT( slotClearSelection() ) );
226 #ifndef QT_NO_MIMECLIPBOARD
227 QString htmltext;
229 * When selectionModeEnabled, that means the user has just selected
230 * the text, not ctrl+c to copy it. The selection clipboard
231 * doesn't seem to support mime type, so to save time, don't calculate
232 * the selected text as html.
233 * optomisation disabled for now until everything else works.
235 //if(!cb->selectionModeEnabled())
236 htmltext = m_part->selectedTextAsHTML();
237 QMimeData *mimeData = new QMimeData;
238 mimeData->setText(text);
239 if(!htmltext.isEmpty()) {
240 htmltext.replace( QChar( 0xa0 ), ' ' );
241 mimeData->setHtml(htmltext);
243 cb->setMimeData(mimeData);
244 #else
245 cb->setText(text);
246 #endif
248 connect( cb, SIGNAL( selectionChanged() ), m_part, SLOT( slotClearSelection() ) );
250 else
252 if ( m_editableFormWidget->inherits( "QLineEdit" ) )
253 static_cast<QLineEdit *>( &(*m_editableFormWidget) )->copy();
254 else if ( m_editableFormWidget->inherits( "QTextEdit" ) )
255 static_cast<QTextEdit *>( &(*m_editableFormWidget) )->copy();
259 void KHTMLPartBrowserExtension::searchProvider()
261 // action name is of form "previewProvider[<searchproviderprefix>:]"
262 const QString searchProviderPrefix = QString( sender()->objectName() ).mid( 14 );
264 const QString text = m_part->simplifiedSelectedText();
265 KUriFilterData data;
266 QStringList list;
267 data.setData( searchProviderPrefix + text );
268 list << "kurisearchfilter" << "kuriikwsfilter";
270 if( !KUriFilter::self()->filterUri(data, list) )
272 KDesktopFile file("services", "searchproviders/google.desktop");
273 QString encodedSearchTerm = QUrl::toPercentEncoding(text);
274 KConfigGroup cg(file.desktopGroup());
275 data.setData(cg.readEntry("Query").replace("\\{@}", encodedSearchTerm));
278 KParts::BrowserArguments browserArgs;
279 browserArgs.frameName = "_blank";
281 emit m_part->browserExtension()->openUrlRequest( data.uri(), KParts::OpenUrlArguments(), browserArgs );
284 void KHTMLPartBrowserExtension::paste()
286 if ( m_extensionProxy )
288 callExtensionProxyMethod( "paste()" );
289 return;
292 if ( !m_editableFormWidget )
293 return;
295 if ( m_editableFormWidget->inherits( "QLineEdit" ) )
296 static_cast<QLineEdit *>( &(*m_editableFormWidget) )->paste();
297 else if ( m_editableFormWidget->inherits( "QTextEdit" ) )
298 static_cast<QTextEdit *>( &(*m_editableFormWidget) )->paste();
301 void KHTMLPartBrowserExtension::callExtensionProxyMethod( const char *method )
303 if ( !m_extensionProxy )
304 return;
306 int slot = m_extensionProxy->metaObject()->indexOfSlot( method );
307 if ( slot == -1 )
308 return;
310 QMetaObject::invokeMethod(m_extensionProxy, method, Qt::DirectConnection);
313 void KHTMLPartBrowserExtension::updateEditActions()
315 if ( !m_editableFormWidget )
317 enableAction( "cut", false );
318 enableAction( "copy", false );
319 enableAction( "paste", false );
320 return;
323 // ### duplicated from KonqMainWindow::slotClipboardDataChanged
324 #ifndef QT_NO_MIMECLIPBOARD // Handle minimalized versions of Qt Embedded
325 const QMimeData *data = QApplication::clipboard()->mimeData();
326 enableAction( "paste", data->hasFormat( "text/plain" ) );
327 #else
328 QString data=QApplication::clipboard()->text();
329 enableAction( "paste", data.contains("://"));
330 #endif
331 bool hasSelection = false;
333 if( m_editableFormWidget) {
334 if ( qobject_cast<QLineEdit*>(m_editableFormWidget))
335 hasSelection = static_cast<QLineEdit *>( &(*m_editableFormWidget) )->hasSelectedText();
336 else if(qobject_cast<QTextEdit*>(m_editableFormWidget))
337 hasSelection = static_cast<QTextEdit *>( &(*m_editableFormWidget) )->textCursor().hasSelection();
340 enableAction( "copy", hasSelection );
341 enableAction( "cut", hasSelection );
344 void KHTMLPartBrowserExtension::extensionProxyEditableWidgetFocused() {
345 editableWidgetFocused();
348 void KHTMLPartBrowserExtension::extensionProxyEditableWidgetBlurred() {
349 editableWidgetBlurred();
352 void KHTMLPartBrowserExtension::extensionProxyActionEnabled( const char *action, bool enable )
354 // only forward enableAction calls for actions we actually do forward
355 if ( strcmp( action, "cut" ) == 0 ||
356 strcmp( action, "copy" ) == 0 ||
357 strcmp( action, "paste" ) == 0 ) {
358 enableAction( action, enable );
362 void KHTMLPartBrowserExtension::reparseConfiguration()
364 m_part->reparseConfiguration();
367 void KHTMLPartBrowserExtension::print()
369 m_part->view()->print();
372 void KHTMLPartBrowserExtension::disableScrolling()
374 QScrollArea *scrollArea = m_part->view();
375 if (scrollArea) {
376 scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
377 scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
381 class KHTMLPopupGUIClient::KHTMLPopupGUIClientPrivate
383 public:
384 KHTMLPart *m_khtml;
385 KUrl m_url;
386 KUrl m_imageURL;
387 QPixmap m_pixmap;
388 QString m_suggestedFilename;
389 KActionCollection* m_actionCollection;
390 KParts::BrowserExtension::ActionGroupMap actionGroups;
394 KHTMLPopupGUIClient::KHTMLPopupGUIClient( KHTMLPart *khtml, const KUrl &url )
395 : QObject( khtml ), d(new KHTMLPopupGUIClientPrivate)
397 d->m_khtml = khtml;
398 d->m_url = url;
399 d->m_actionCollection = new KActionCollection(this);
400 bool isImage = false;
401 bool hasSelection = khtml->hasSelection();
403 DOM::Element e = khtml->nodeUnderMouse();
405 if ( !e.isNull() && (e.elementId() == ID_IMG ||
406 (e.elementId() == ID_INPUT && !static_cast<DOM::HTMLInputElement>(e).src().isEmpty())))
408 if (e.elementId() == ID_IMG) {
409 DOM::HTMLImageElementImpl *ie = static_cast<DOM::HTMLImageElementImpl*>(e.handle());
410 khtml::RenderImage *ri = dynamic_cast<khtml::RenderImage*>(ie->renderer());
411 if (ri && ri->contentObject()) {
412 d->m_suggestedFilename = static_cast<khtml::CachedImage*>(ri->contentObject())->suggestedFilename();
415 isImage=true;
418 if (hasSelection) {
419 QList<QAction *> editActions;
420 QAction* copyAction = d->m_actionCollection->addAction( KStandardAction::Copy, "copy",
421 d->m_khtml->browserExtension(), SLOT( copy() ) );
423 copyAction->setText(i18n("&Copy Text"));
424 copyAction->setEnabled(d->m_khtml->browserExtension()->isActionEnabled( "copy" ));
425 editActions.append(copyAction);
427 editActions.append(khtml->actionCollection()->action("selectAll"));
429 addSearchActions(editActions);
431 QString selectedTextURL = selectedTextAsOneLine();
432 if ( selectedTextURL.contains("://") && KUrl(selectedTextURL).isValid() ) {
433 if (selectedTextURL.length() > 18) {
434 selectedTextURL.truncate(15);
435 selectedTextURL += "...";
437 KAction *action = new KAction(i18n("Open '%1'", selectedTextURL), this);
438 d->m_actionCollection->addAction( "openSelection", action );
439 action->setIcon( KIcon( "window-new" ) );
440 connect( action, SIGNAL(triggered(bool)), this, SLOT( openSelection() ) );
441 editActions.append(action);
444 KAction* separator = new KAction(d->m_actionCollection);
445 separator->setSeparator(true);
446 editActions.append(separator);
448 d->actionGroups.insert("editactions", editActions);
451 if (!url.isEmpty()) {
452 QList<QAction *> linkActions;
453 if (url.protocol() == "mailto") {
454 KAction *action = new KAction( i18n( "&Copy Email Address" ), this );
455 d->m_actionCollection->addAction( "copylinklocation", action );
456 connect( action, SIGNAL(triggered(bool)), this, SLOT(slotCopyLinkLocation()) );
457 linkActions.append(action);
458 } else {
459 KAction *action = new KAction( i18n( "&Save Link As..." ), this );
460 d->m_actionCollection->addAction( "savelinkas", action );
461 connect( action, SIGNAL(triggered(bool)), this, SLOT(slotSaveLinkAs()) );
462 linkActions.append(action);
464 action = new KAction( i18n( "&Copy Link Address" ), this );
465 d->m_actionCollection->addAction( "copylinklocation", action );
466 connect( action, SIGNAL(triggered(bool)), this, SLOT( slotCopyLinkLocation() ) );
467 linkActions.append(action);
469 d->actionGroups.insert("linkactions", linkActions);
472 QList<QAction *> partActions;
473 // frameset? -> add "Reload Frame" etc.
474 if (!hasSelection) {
475 if ( khtml->parentPart() ) {
476 KActionMenu* menu = new KActionMenu( i18nc("@title:menu HTML frame/iframe", "Frame"), this);
477 KAction *action = new KAction( i18n( "Open in New &Window" ), this );
478 d->m_actionCollection->addAction( "frameinwindow", action );
479 action->setIcon( KIcon( "window-new" ) );
480 connect( action, SIGNAL(triggered(bool)), this, SLOT(slotFrameInWindow()) );
481 menu->addAction(action);
483 action = new KAction( i18n( "Open in &This Window" ), this );
484 d->m_actionCollection->addAction( "frameintop", action );
485 connect( action, SIGNAL(triggered(bool)), this, SLOT( slotFrameInTop() ) );
486 menu->addAction(action);
488 action = new KAction( i18n( "Open in &New Tab" ), this );
489 d->m_actionCollection->addAction( "frameintab", action );
490 action->setIcon( KIcon( "tab-new" ) );
491 connect( action, SIGNAL(triggered(bool)), this, SLOT( slotFrameInTab() ) );
492 menu->addAction(action);
494 action = new KAction(d->m_actionCollection);
495 action->setSeparator(true);
496 menu->addAction(action);
498 action = new KAction( i18n( "Reload Frame" ), this );
499 d->m_actionCollection->addAction( "reloadframe", action );
500 connect( action, SIGNAL(triggered(bool)), this, SLOT( slotReloadFrame() ) );
501 menu->addAction(action);
503 action = new KAction( i18n( "Print Frame..." ), this );
504 d->m_actionCollection->addAction( "printFrame", action );
505 action->setIcon( KIcon( "document-print-frame" ) );
506 connect( action, SIGNAL(triggered(bool)), d->m_khtml->browserExtension(), SLOT( print() ) );
507 menu->addAction(action);
509 action = new KAction( i18n( "Save &Frame As..." ), this );
510 d->m_actionCollection->addAction( "saveFrame", action );
511 connect( action, SIGNAL(triggered(bool)), d->m_khtml, SLOT( slotSaveFrame() ) );
512 menu->addAction(action);
514 action = new KAction( i18n( "View Frame Source" ), this );
515 d->m_actionCollection->addAction( "viewFrameSource", action );
516 connect( action, SIGNAL(triggered(bool)), d->m_khtml, SLOT( slotViewDocumentSource() ) );
517 menu->addAction(action);
519 action = new KAction( i18n( "View Frame Information" ), this );
520 d->m_actionCollection->addAction( "viewFrameInfo", action );
521 connect( action, SIGNAL(triggered(bool)), d->m_khtml, SLOT( slotViewPageInfo() ) );
523 action = new KAction(d->m_actionCollection);
524 action->setSeparator(true);
525 menu->addAction(action);
527 if ( KHTMLGlobal::defaultHTMLSettings()->isAdFilterEnabled() ) {
528 if ( khtml->d->m_frame->m_type == khtml::ChildFrame::IFrame ) {
529 action = new KAction( i18n( "Block IFrame..." ), this );
530 d->m_actionCollection->addAction( "blockiframe", action );
531 connect( action, SIGNAL(triggered(bool)), this, SLOT( slotBlockIFrame() ) );
532 menu->addAction(action);
536 partActions.append(menu);
540 if (isImage) {
541 if ( e.elementId() == ID_IMG ) {
542 d->m_imageURL = KUrl( static_cast<DOM::HTMLImageElement>( e ).src().string() );
543 DOM::HTMLImageElementImpl *imageimpl = static_cast<DOM::HTMLImageElementImpl *>( e.handle() );
544 Q_ASSERT(imageimpl);
545 if(imageimpl) // should be true always. right?
547 if(imageimpl->complete()) {
548 d->m_pixmap = imageimpl->currentPixmap();
552 else
553 d->m_imageURL = KUrl( static_cast<DOM::HTMLInputElement>( e ).src().string() );
554 KAction *action = new KAction( i18n( "Save Image As..." ), this );
555 d->m_actionCollection->addAction( "saveimageas", action );
556 connect( action, SIGNAL(triggered(bool)), this, SLOT( slotSaveImageAs() ) );
557 partActions.append(action);
559 action = new KAction( i18n( "Send Image..." ), this );
560 d->m_actionCollection->addAction( "sendimage", action );
561 connect( action, SIGNAL(triggered(bool)), this, SLOT( slotSendImage() ) );
562 partActions.append(action);
564 #ifndef QT_NO_MIMECLIPBOARD
565 action = new KAction( i18n( "Copy Image" ), this );
566 d->m_actionCollection->addAction( "copyimage", action );
567 action->setEnabled(!d->m_pixmap.isNull());
568 connect( action, SIGNAL(triggered(bool)), this, SLOT( slotCopyImage() ) );
569 partActions.append(action);
570 #endif
572 if(d->m_pixmap.isNull()) { //fallback to image location if still loading the image. this will always be true if ifdef QT_NO_MIMECLIPBOARD
573 action = new KAction( i18n( "Copy Image Location" ), this );
574 d->m_actionCollection->addAction( "copyimagelocation", action );
575 connect( action, SIGNAL(triggered(bool)), this, SLOT( slotCopyImageLocation() ) );
576 partActions.append(action);
579 QString actionText = d->m_suggestedFilename.isEmpty() ?
580 KStringHandler::csqueeze(d->m_imageURL.fileName()+d->m_imageURL.query(), 25)
581 : d->m_suggestedFilename;
582 action = new KAction( i18n("View Image (%1)", actionText.replace("&", "&&")), this );
583 d->m_actionCollection->addAction( "viewimage", action );
584 connect( action, SIGNAL(triggered(bool)), this, SLOT( slotViewImage() ) );
585 partActions.append(action);
587 if (KHTMLGlobal::defaultHTMLSettings()->isAdFilterEnabled()) {
588 action = new KAction( i18n( "Block Image..." ), this );
589 d->m_actionCollection->addAction( "blockimage", action );
590 connect( action, SIGNAL(triggered(bool)), this, SLOT( slotBlockImage() ) );
591 partActions.append(action);
593 if (!d->m_imageURL.host().isEmpty() &&
594 !d->m_imageURL.protocol().isEmpty())
596 action = new KAction( i18n( "Block Images From %1" , d->m_imageURL.host()), this );
597 d->m_actionCollection->addAction( "blockhost", action );
598 connect( action, SIGNAL(triggered(bool)), this, SLOT( slotBlockHost() ) );
599 partActions.append(action);
602 KAction* separator = new KAction(d->m_actionCollection);
603 separator->setSeparator(true);
604 partActions.append(separator);
607 if ( isImage || url.isEmpty() ) {
608 KAction *action = new KAction( i18n( "Stop Animations" ), this );
609 d->m_actionCollection->addAction( "stopanimations", action );
610 connect( action, SIGNAL(triggered(bool)), this, SLOT(slotStopAnimations()) );
611 partActions.append(action);
612 KAction* separator = new KAction(d->m_actionCollection);
613 separator->setSeparator(true);
614 partActions.append(separator);
616 if (!hasSelection && url.isEmpty()) { // only when right-clicking on the page itself
617 partActions.append(khtml->actionCollection()->action("viewDocumentSource"));
619 if (!hasSelection && url.isEmpty() && !isImage) {
620 partActions.append(khtml->actionCollection()->action("setEncoding"));
622 d->actionGroups.insert("partactions", partActions);
625 KHTMLPopupGUIClient::~KHTMLPopupGUIClient()
627 delete d->m_actionCollection;
628 delete d;
631 void KHTMLPopupGUIClient::addSearchActions(QList<QAction *>& editActions)
633 // Fill search provider entries
634 KConfig config("kuriikwsfilterrc");
635 KConfigGroup cg = config.group("General");
636 const QString defaultEngine = cg.readEntry("DefaultSearchEngine", "google");
637 const char keywordDelimiter = cg.readEntry("KeywordDelimiter", static_cast<int>(':'));
639 // search text
640 QString selectedText = d->m_khtml->simplifiedSelectedText();
641 if (selectedText.isEmpty())
642 return;
644 selectedText.replace("&", "&&");
645 if (selectedText.length() > 18) {
646 selectedText.truncate(15);
647 selectedText += "...";
650 // default search provider
651 KService::Ptr service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(defaultEngine));
653 // search provider icon
654 KIcon icon;
655 KUriFilterData data;
656 QStringList list;
657 data.setData(QString("some keyword"));
658 list << "kurisearchfilter" << "kuriikwsfilter";
660 QString name;
661 if (KUriFilter::self()->filterUri(data, list)) {
662 QString iconPath = KStandardDirs::locate("cache", KMimeType::favIconForUrl(data.uri()) + ".png");
663 if (iconPath.isEmpty())
664 icon = KIcon("edit-find");
665 else
666 icon = KIcon(QPixmap(iconPath));
667 name = service->name();
668 } else {
669 icon = KIcon("google");
670 name = "Google";
673 KAction *action = new KAction(i18n("Search for '%1' with %2", selectedText, name), this);
674 d->m_actionCollection->addAction("searchProvider", action);
675 editActions.append(action);
676 action->setIcon(icon);
677 connect(action, SIGNAL(triggered(bool)), d->m_khtml->browserExtension(), SLOT(searchProvider()));
679 // favorite search providers
680 QStringList favoriteEngines;
681 favoriteEngines << "google" << "google_groups" << "google_news" << "webster" << "dmoz" << "wikipedia";
682 favoriteEngines = cg.readEntry("FavoriteSearchEngines", favoriteEngines);
684 if (!favoriteEngines.isEmpty()) {
685 KActionMenu* providerList = new KActionMenu(i18n("Search for '%1' with", selectedText), this);
686 d->m_actionCollection->addAction("searchProviderList", providerList);
687 editActions.append(providerList);
689 QStringList::ConstIterator it = favoriteEngines.constBegin();
690 for (; it != favoriteEngines.constEnd(); ++it) {
691 if (*it==defaultEngine)
692 continue;
693 service = KService::serviceByDesktopPath(QString("searchproviders/%1.desktop").arg(*it));
694 if (!service)
695 continue;
696 const QString searchProviderPrefix = *(service->property("Keys").toStringList().begin()) + keywordDelimiter;
697 data.setData(searchProviderPrefix + "some keyword");
699 if (KUriFilter::self()->filterUri(data, list)) {
700 const QString iconPath = KStandardDirs::locate("cache", KMimeType::favIconForUrl(data.uri()) + ".png");
701 if (iconPath.isEmpty())
702 icon = KIcon("edit-find");
703 else
704 icon = KIcon(iconPath);
705 name = service->name();
707 KAction *action = new KAction(name, this);
708 d->m_actionCollection->addAction(QString("searchProvider" + searchProviderPrefix).toLatin1().constData(), action);
709 action->setIcon(icon);
710 connect(action, SIGNAL(triggered(bool)), d->m_khtml->browserExtension(), SLOT(searchProvider()));
712 providerList->addAction(action);
718 QString KHTMLPopupGUIClient::selectedTextAsOneLine() const
720 QString text = d->m_khtml->simplifiedSelectedText();
721 // in addition to what simplifiedSelectedText does,
722 // remove linefeeds and any whitespace surrounding it (#113177),
723 // to get it all in a single line.
724 text.remove(QRegExp("[\\s]*\\n+[\\s]*"));
725 return text;
728 void KHTMLPopupGUIClient::openSelection()
730 KParts::BrowserArguments browserArgs;
731 browserArgs.frameName = "_blank";
733 emit d->m_khtml->browserExtension()->openUrlRequest(selectedTextAsOneLine(), KParts::OpenUrlArguments(), browserArgs);
736 KParts::BrowserExtension::ActionGroupMap KHTMLPopupGUIClient::actionGroups() const
738 return d->actionGroups;
741 void KHTMLPopupGUIClient::slotSaveLinkAs()
743 KIO::MetaData metaData;
744 metaData["referrer"] = d->m_khtml->referrer();
745 saveURL( d->m_khtml->widget(), i18n( "Save Link As" ), d->m_url, metaData );
748 void KHTMLPopupGUIClient::slotSendImage()
750 QStringList urls;
751 urls.append( d->m_imageURL.url());
752 QString subject = d->m_imageURL.url();
753 KToolInvocation::invokeMailer(QString(), QString(), QString(), subject,
754 QString(), //body
755 QString(),
756 urls); // attachments
761 void KHTMLPopupGUIClient::slotSaveImageAs()
763 KIO::MetaData metaData;
764 metaData["referrer"] = d->m_khtml->referrer();
765 saveURL( d->m_khtml->widget(), i18n( "Save Image As" ), d->m_imageURL, metaData, QString(), 0, d->m_suggestedFilename );
768 void KHTMLPopupGUIClient::slotBlockHost()
770 QString name=d->m_imageURL.protocol()+"://"+d->m_imageURL.host()+"/*";
771 KHTMLGlobal::defaultHTMLSettings()->addAdFilter( name );
772 d->m_khtml->reparseConfiguration();
775 void KHTMLPopupGUIClient::slotBlockImage()
777 bool ok = false;
779 QString url = KInputDialog::getText( i18n("Add URL to Filter"),
780 i18n("Enter the URL:"),
781 d->m_imageURL.url(),
782 &ok);
783 if ( ok ) {
784 KHTMLGlobal::defaultHTMLSettings()->addAdFilter( url );
785 d->m_khtml->reparseConfiguration();
789 void KHTMLPopupGUIClient::slotBlockIFrame()
791 bool ok = false;
792 QString url = KInputDialog::getText( i18n( "Add URL to Filter"),
793 i18n("Enter the URL:"),
794 d->m_khtml->url().url(),
795 &ok );
796 if ( ok ) {
797 KHTMLGlobal::defaultHTMLSettings()->addAdFilter( url );
798 d->m_khtml->reparseConfiguration();
802 void KHTMLPopupGUIClient::slotCopyLinkLocation()
804 KUrl safeURL(d->m_url);
805 safeURL.setPass(QString());
806 #ifndef QT_NO_MIMECLIPBOARD
807 // Set it in both the mouse selection and in the clipboard
808 QMimeData* mimeData = new QMimeData;
809 safeURL.populateMimeData( mimeData );
810 QApplication::clipboard()->setMimeData( mimeData, QClipboard::Clipboard );
812 mimeData = new QMimeData;
813 safeURL.populateMimeData( mimeData );
814 QApplication::clipboard()->setMimeData( mimeData, QClipboard::Selection );
816 #else
817 QApplication::clipboard()->setText( safeURL.url() ); //FIXME(E): Handle multiple entries
818 #endif
821 void KHTMLPopupGUIClient::slotStopAnimations()
823 d->m_khtml->stopAnimations();
826 void KHTMLPopupGUIClient::slotCopyImage()
828 #ifndef QT_NO_MIMECLIPBOARD
829 KUrl safeURL(d->m_imageURL);
830 safeURL.setPass(QString());
832 // Set it in both the mouse selection and in the clipboard
833 QMimeData* mimeData = new QMimeData;
834 mimeData->setImageData( d->m_pixmap );
835 safeURL.populateMimeData( mimeData );
836 QApplication::clipboard()->setMimeData( mimeData, QClipboard::Clipboard );
838 mimeData = new QMimeData;
839 mimeData->setImageData( d->m_pixmap );
840 safeURL.populateMimeData( mimeData );
841 QApplication::clipboard()->setMimeData( mimeData, QClipboard::Selection );
842 #else
843 kDebug() << "slotCopyImage called when the clipboard does not support this. This should not be possible.";
844 #endif
847 void KHTMLPopupGUIClient::slotCopyImageLocation()
849 KUrl safeURL(d->m_imageURL);
850 safeURL.setPass(QString());
851 #ifndef QT_NO_MIMECLIPBOARD
852 // Set it in both the mouse selection and in the clipboard
853 QMimeData* mimeData = new QMimeData;
854 safeURL.populateMimeData( mimeData );
855 QApplication::clipboard()->setMimeData( mimeData, QClipboard::Clipboard );
856 mimeData = new QMimeData;
857 safeURL.populateMimeData( mimeData );
858 QApplication::clipboard()->setMimeData( mimeData, QClipboard::Selection );
859 #else
860 QApplication::clipboard()->setText( safeURL.url() ); //FIXME(E): Handle multiple entries
861 #endif
864 void KHTMLPopupGUIClient::slotViewImage()
866 d->m_khtml->browserExtension()->createNewWindow(d->m_imageURL);
869 void KHTMLPopupGUIClient::slotReloadFrame()
871 KParts::OpenUrlArguments args = d->m_khtml->arguments();
872 args.setReload( true );
873 args.metaData()["referrer"] = d->m_khtml->pageReferrer();
874 // reload document
875 d->m_khtml->closeUrl();
876 d->m_khtml->setArguments( args );
877 d->m_khtml->openUrl( d->m_khtml->url() );
880 void KHTMLPopupGUIClient::slotFrameInWindow()
882 KParts::OpenUrlArguments args = d->m_khtml->arguments();
883 args.metaData()["referrer"] = d->m_khtml->pageReferrer();
884 args.metaData()["forcenewwindow"] = "true";
885 emit d->m_khtml->browserExtension()->createNewWindow( d->m_khtml->url(), args );
888 void KHTMLPopupGUIClient::slotFrameInTop()
890 KParts::OpenUrlArguments args = d->m_khtml->arguments();
891 args.metaData()["referrer"] = d->m_khtml->pageReferrer();
892 KParts::BrowserArguments browserArgs( d->m_khtml->browserExtension()->browserArguments() );
893 browserArgs.frameName = "_top";
894 emit d->m_khtml->browserExtension()->openUrlRequest( d->m_khtml->url(), args, browserArgs );
897 void KHTMLPopupGUIClient::slotFrameInTab()
899 KParts::OpenUrlArguments args = d->m_khtml->arguments();
900 args.metaData()["referrer"] = d->m_khtml->pageReferrer();
901 KParts::BrowserArguments browserArgs( d->m_khtml->browserExtension()->browserArguments() );
902 browserArgs.setNewTab(true);
903 emit d->m_khtml->browserExtension()->createNewWindow( d->m_khtml->url(), args, browserArgs );
906 void KHTMLPopupGUIClient::saveURL( QWidget *parent, const QString &caption,
907 const KUrl &url,
908 const QMap<QString, QString> &metadata,
909 const QString &filter, long cacheId,
910 const QString & suggestedFilename )
912 QString name = QLatin1String( "index.html" );
913 if ( !suggestedFilename.isEmpty() )
914 name = suggestedFilename;
915 else if ( !url.fileName().isEmpty() )
916 name = url.fileName();
918 KUrl destURL;
919 int query;
920 do {
921 query = KMessageBox::Yes;
922 destURL = KFileDialog::getSaveUrl( name, filter, parent, caption );
923 if( destURL.isLocalFile() )
925 QFileInfo info( destURL.path() );
926 if( info.exists() ) {
927 // TODO: use KIO::RenameDlg (shows more information)
928 query = KMessageBox::warningContinueCancel( parent, i18n( "A file named \"%1\" already exists. " "Are you sure you want to overwrite it?" , info.fileName() ), i18n( "Overwrite File?" ), KGuiItem(i18n( "Overwrite" )) );
931 } while ( query == KMessageBox::Cancel );
933 if ( destURL.isValid() )
934 saveURL(parent, url, destURL, metadata, cacheId);
937 void KHTMLPopupGUIClient::saveURL( QWidget* parent, const KUrl &url, const KUrl &destURL,
938 const QMap<QString, QString> &metadata,
939 long cacheId )
941 if ( destURL.isValid() )
943 bool saved = false;
944 if (KHTMLPageCache::self()->isComplete(cacheId))
946 if (destURL.isLocalFile())
948 KSaveFile destFile(destURL.path());
949 if (destFile.open())
951 QDataStream stream ( &destFile );
952 KHTMLPageCache::self()->saveData(cacheId, &stream);
953 saved = true;
956 else
958 // save to temp file, then move to final destination.
959 KTemporaryFile destFile;
960 if (destFile.open())
962 QDataStream stream ( &destFile );
963 KHTMLPageCache::self()->saveData(cacheId, &stream);
964 KUrl url2 = KUrl();
965 url2.setPath(destFile.fileName());
966 KIO::file_move(url2, destURL, -1, KIO::Overwrite);
967 saved = true;
971 if(!saved)
973 // DownloadManager <-> konqueror integration
974 // find if the integration is enabled
975 // the empty key means no integration
976 // only use download manager for non-local urls!
977 bool downloadViaKIO = true;
978 if ( !url.isLocalFile() )
980 KConfigGroup cfg = KSharedConfig::openConfig("konquerorrc", KConfig::NoGlobals)->group("HTML Settings");
981 QString downloadManger = cfg.readPathEntry("DownloadManager", QString());
982 if (!downloadManger.isEmpty())
984 // then find the download manager location
985 kDebug(1000) << "Using: "<<downloadManger <<" as Download Manager";
986 QString cmd = KStandardDirs::findExe(downloadManger);
987 if (cmd.isEmpty())
989 QString errMsg=i18n("The Download Manager (%1) could not be found in your $PATH ", downloadManger);
990 QString errMsgEx= i18n("Try to reinstall it \n\nThe integration with Konqueror will be disabled.");
991 KMessageBox::detailedSorry(0,errMsg,errMsgEx);
992 cfg.writePathEntry("DownloadManager",QString());
993 cfg.sync ();
995 else
997 downloadViaKIO = false;
998 KUrl cleanDest = destURL;
999 cleanDest.setPass( QString() ); // don't put password into commandline
1000 cmd += ' ' + KShell::quoteArg(url.url()) + ' ' +
1001 KShell::quoteArg(cleanDest.url());
1002 kDebug(1000) << "Calling command "<<cmd;
1003 KRun::runCommand(cmd, parent->topLevelWidget());
1008 if ( downloadViaKIO )
1010 KIO::Job *job = KIO::file_copy( url, destURL, -1, KIO::Overwrite );
1011 job->setMetaData(metadata);
1012 job->addMetaData("MaxCacheSize", "0"); // Don't store in http cache.
1013 job->addMetaData("cache", "cache"); // Use entry from cache if available.
1014 job->uiDelegate()->setAutoErrorHandlingEnabled( true );
1016 } //end if(!saved)
1020 KHTMLPartBrowserHostExtension::KHTMLPartBrowserHostExtension( KHTMLPart *part )
1021 : KParts::BrowserHostExtension( part )
1023 m_part = part;
1026 KHTMLPartBrowserHostExtension::~KHTMLPartBrowserHostExtension()
1030 QStringList KHTMLPartBrowserHostExtension::frameNames() const
1032 return m_part->frameNames();
1035 const QList<KParts::ReadOnlyPart*> KHTMLPartBrowserHostExtension::frames() const
1037 return m_part->frames();
1040 bool KHTMLPartBrowserHostExtension::openUrlInFrame(const KUrl &url, const KParts::OpenUrlArguments& arguments, const KParts::BrowserArguments &browserArguments)
1042 return m_part->openUrlInFrame( url, arguments, browserArguments );
1045 KParts::BrowserHostExtension* KHTMLPartBrowserHostExtension::findFrameParent( KParts::ReadOnlyPart
1046 *callingPart, const QString &frame )
1048 KHTMLPart *parentPart = m_part->findFrameParent(callingPart, frame);
1049 if (parentPart)
1050 return parentPart->browserHostExtension();
1051 return 0;
1055 // defined in khtml_part.cpp
1056 extern const int KDE_NO_EXPORT fastZoomSizes[];
1057 extern const int KDE_NO_EXPORT fastZoomSizeCount;
1059 KHTMLZoomFactorAction::KHTMLZoomFactorAction( KHTMLPart *part, bool direction, const QString &icon, const QString &text, QObject *parent )
1060 : KSelectAction( text, parent )
1062 setIcon( KIcon( icon ) );
1064 setToolBarMode(MenuMode);
1065 setToolButtonPopupMode(QToolButton::DelayedPopup);
1067 init(part, direction);
1070 void KHTMLZoomFactorAction::init(KHTMLPart *part, bool direction)
1072 m_direction = direction;
1073 m_part = part;
1075 // xgettext: no-c-format
1076 addAction( i18n( "Default Font Size (100%)" ) );
1078 int m = m_direction ? 1 : -1;
1079 int ofs = fastZoomSizeCount / 2; // take index of 100%
1081 // this only works if there is an odd number of elements in fastZoomSizes[]
1082 for ( int i = m; i != m*(ofs+1); i += m )
1084 int num = i * m;
1085 QString numStr = QString::number( num );
1086 if ( num > 0 ) numStr.prepend( QLatin1Char('+') );
1088 // xgettext: no-c-format
1089 addAction( i18n( "%1%" , fastZoomSizes[ofs + i] ) );
1092 connect( selectableActionGroup(), SIGNAL( triggered(QAction*) ), this, SLOT( slotTriggered(QAction*) ) );
1095 KHTMLZoomFactorAction::~KHTMLZoomFactorAction()
1099 void KHTMLZoomFactorAction::slotTriggered(QAction* action)
1101 int idx = selectableActionGroup()->actions().indexOf(action);
1103 if (idx == 0)
1104 m_part->setFontScaleFactor(100);
1105 else
1106 m_part->setFontScaleFactor(fastZoomSizes[fastZoomSizeCount/2 + (m_direction ? 1 : -1)*idx]);
1107 setCurrentAction( 0L );
1110 #include "khtml_ext.moc"